#!/usr/bin/env python3
from urllib.error import HTTPError
from urllib.request import urlopen, Request
import logging
# from requests_oauthlib import OAuth1Session
from datetime import datetime
import sys
import json
bearer = None
def getBearer():
global bearer
if bearer:
return bearer
headers = {
"Authorization": "Basic Zzl1MXI2SFpYTXg0SXU5UGs5VlNvTzFUdzpmeTIyQjN2QVRRNUI2eGthb1BFdFFRUmtuUGQ1WGZBbnBKVG5hc0ZRa3NyUm5qaVNsaw==",
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
}
data = b"grant_type=client_credentials"
url = "https://api.twitter.com/oauth2/token"
res = urlopen(Request(url, headers=headers, data=data, method="POST"))
response = json.loads(res.read().decode("UTF-8"))
bearer = response["access_token"]
return bearer
def unshorten_urls(title, description, urls):
for url in urls:
shorted_url = url["url"]
long_url = url["expanded_url"]
if "images" in url:
img = url["images"][0]["url"]
long_url_html = ''
else:
long_url_html = '' + long_url + ""
description = description.replace(shorted_url, long_url_html)
title = title.replace(shorted_url, long_url)
return title, description
def twitter(user):
# 500.000 Tweets per month
# API KEY = g9u1r6HZXMx4Iu9Pk9VSoO1Tw
# API SECRET KEY = fy22B3vATQ5B6xkaoPEtQQRknPd5XfAnpJTnasFQksrRnjiSlk
headers = {"authorization": "Bearer " + getBearer()}
# Recent = last 7 days
url = (
"https://api.twitter.com/2/tweets/search/recent?query=from:"
+ user
+ "&tweet.fields=created_at,author_id,lang,source,public_metrics,entities&expansions=referenced_tweets.id,attachments.media_keys&media.fields=url"
)
try:
res = urlopen(Request(url, headers=headers))
response = json.loads(res.read().decode("UTF-8"))
except Exception as exc:
logging.error("Request to twitter failed.", exc_info=exc)
return None
feed = {
"title": "Twitter: " + user,
"url": "https://twitter.com/" + user,
"description": "The latest entries of the twitter account of " + user,
"content": [],
}
if not response["meta"]["result_count"]:
return feed
feed["content"] = [
parse_tweet(
user,
tweet,
response.get("includes", {}).get("tweets", []),
response.get("includes", {}).get("media", []),
headers,
)
for tweet in response["data"]
]
return feed
def parse_tweet(user, tweet, included_tweets, included_media, headers):
title = description = tweet["text"]
link = "https://twitter.com/" + user + "/status/" + str(tweet["id"])
# Check included re-tweets / replace by Retweet
ref_enclosures = []
for rt in tweet.get("referenced_tweets", []):
if rt["type"] == "retweeted":
rt_info = title[: title.index(":") + 2]
ref_tweet = next(t for t in included_tweets if t["id"] == rt["id"])
title = rt_info + ref_tweet["text"]
description = rt_info + ref_tweet["text"]
title, description = unshorten_urls(
title, description, ref_tweet.get("entities", {}).get("urls", [])
)
elif rt["type"] == "replied_to":
description += "
This was a reply to: " + rt["id"]
text, enclosures = fetch_single_tweet(rt["id"], headers)
description += text
ref_enclosures.extend(enclosures)
elif rt["type"] == "quoted":
description += "
Quoted tweet: " + rt["id"]
text, enclosures = fetch_single_tweet(rt["id"], headers)
description += text
ref_enclosures.extend(enclosures)
else:
description += f"
Unknown reference type: {rt['type']}"
title, description = unshorten_urls(
title, description, tweet.get("entities", {}).get("urls", [])
)
# Attach media
enclosures = []
included_media_keys = tweet.get("attachments", {}).get("media_keys", [])
for included_media_key in included_media_keys:
ref_media = next(
t for t in included_media if t["media_key"] == included_media_key
)
if "url" not in ref_media:
continue
if ref_media.get("type", "") == "photo":
description += '
'
else:
enclosures.append(ref_media["url"])
enclosures.extend(ref_enclosures)
# Append Retweets etc
description += "
"
description += str(tweet["public_metrics"]["retweet_count"]) + " Retweets, "
description += str(tweet["public_metrics"]["like_count"]) + " Likes, "
description += str(tweet["public_metrics"]["reply_count"]) + " Replies, "
description += str(tweet["public_metrics"]["quote_count"]) + " Quotes"
description += "
"
description += "Source: " + tweet["source"]
date = datetime.strptime(tweet["created_at"], "%Y-%m-%dT%H:%M:%S.%fZ")
return {
"title": title,
"url": link,
"content": description,
"date": date,
"enclosures": enclosures,
}
def fetch_single_tweet(id, headers):
url = f"https://api.twitter.com/2/tweets/{id}?tweet.fields=entities&expansions=attachments.media_keys&media.fields=url"
try:
res = urlopen(Request(url, headers=headers))
response = json.loads(res.read().decode("UTF-8"))
except Exception as exc:
logging.error("Request to twitter failed (single tweet).", exc_info=exc)
return None
text = response['data'].get('text', 'no text')
enclosures = []
for media in response['data'].get('includes', {}).get('media', []):
if "url" not in media:
continue
if media.get("type", "") == "photo":
text += '
'
else:
enclosures.append(media["url"])
return text, enclosures
def main(channel):
print(twitter(channel))
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage:", sys.argv[0], "")
sys.exit(1)
main(sys.argv[1])
# twitter('rheinbahn_intim')
# twitter('realDonaldTrump')