165 lines
5.4 KiB
Python
165 lines
5.4 KiB
Python
|
#!/usr/bin/python3
|
|||
|
# coding: utf-8
|
|||
|
|
|||
|
import twitter
|
|||
|
from mastodon import Mastodon
|
|||
|
from configparser import ConfigParser
|
|||
|
import urllib.request
|
|||
|
import sys
|
|||
|
import os.path
|
|||
|
import re
|
|||
|
|
|||
|
|
|||
|
__prog_name__ = 'tweet2toot'
|
|||
|
__version__ = '0.2'
|
|||
|
__description__ = 'Toot a tweet on Mastodon'
|
|||
|
|
|||
|
# Définition des variables
|
|||
|
toot_status = ''
|
|||
|
media_dict = None
|
|||
|
DEBUG = False
|
|||
|
url_tweet_regex = r'/^https?:\/\/twitter\.com\/(?:#!\/)?(\w+)\/status(es)?\/(\d+)$/'
|
|||
|
temp_path = ''
|
|||
|
|
|||
|
# Function to scrap the tweet media file and attach them to the toot
|
|||
|
def addmedia(medias):
|
|||
|
for media in medias:
|
|||
|
if media.type == 'photo':
|
|||
|
media_url = media.media_url
|
|||
|
if media.type == 'animated_gif':
|
|||
|
media_url = media.video_info['variants'][0]['url']
|
|||
|
if media.type == 'video':
|
|||
|
bitratemax = 800000 # Mastodon media size limited to 8Mo
|
|||
|
bitrate = 0
|
|||
|
# Find the best media video
|
|||
|
for i in media.video_info['variants']:
|
|||
|
if ('bitrate' in i) and (i['bitrate'] > bitrate) \
|
|||
|
and (i['bitrate'] < bitratemax):
|
|||
|
bitrate = i['bitrate']
|
|||
|
media_url = i['url']
|
|||
|
media_url = media_url.split('?')[0]
|
|||
|
# Get the media filename with the mediaurl
|
|||
|
media_filename = media_url.split('/')[-1]
|
|||
|
# Downloading the media
|
|||
|
local_filename, headers = urllib.request.urlretrieve(
|
|||
|
media_url,
|
|||
|
filename=temp_path + '/' + media_filename,
|
|||
|
reporthook=None,
|
|||
|
data=None)
|
|||
|
# Add this media to the MediaDict Toot
|
|||
|
media_dict.append(mastodonAPI.media_post(local_filename))
|
|||
|
return media_dict
|
|||
|
|
|||
|
|
|||
|
# Reading the script parameters into config.ini
|
|||
|
conf = ConfigParser()
|
|||
|
conf.read('config.ini')
|
|||
|
|
|||
|
# Check if the cache directory exist
|
|||
|
if not os.path.exists(conf['app']['cache_path_dir']):
|
|||
|
os.mkdir(conf['app']['cache_path_dir'])
|
|||
|
temp_path = conf['app']['cache_path_dir']
|
|||
|
|
|||
|
# Use the first argument passed as URL tweet or ask it
|
|||
|
if len(sys.argv) > 1:
|
|||
|
url_tweet = sys.argv[1]
|
|||
|
else:
|
|||
|
url_tweet = input("URL ? ")
|
|||
|
|
|||
|
# TODO : a reverifier
|
|||
|
if re.match(url_tweet_regex, url_tweet) is not None:
|
|||
|
print ('[ERROR] The URL status is incorrect')
|
|||
|
print ('The correct format is : https://twitter.com/<username>/status/<ID>')
|
|||
|
sys.exit(0)
|
|||
|
else:
|
|||
|
# Decompose the tweet URL to find the ID tweet
|
|||
|
id_tweet = url_tweet.split('/')[-1]
|
|||
|
|
|||
|
# Log into Twitter via API
|
|||
|
try:
|
|||
|
twitterAPI = twitter.Api(
|
|||
|
consumer_key=conf['twitter']['TWITTER_API_KEY'],
|
|||
|
consumer_secret=conf['twitter']['TWITTER_API_SECRET'],
|
|||
|
access_token_key=conf['twitter']['TWITTER_ACCESS_TOKEN'],
|
|||
|
access_token_secret=conf['twitter']['TWITTER_ACCESS_TOKEN_SECRET'],
|
|||
|
tweet_mode='extended'
|
|||
|
)
|
|||
|
twitter_hostname = conf['twitter']['TWITTER_INSTANCE']
|
|||
|
twitter_username = twitterAPI.VerifyCredentials().screen_name
|
|||
|
print ('[ OK ] Sucessfully authenticated on ' + twitter_hostname
|
|||
|
+ ' as @' + twitter_username)
|
|||
|
except BaseException as e:
|
|||
|
print ('[ERROR] Error while logging into Twitter:', str(e))
|
|||
|
sys.exit(0)
|
|||
|
|
|||
|
# Retrieve the tweet with the ID tweet
|
|||
|
tweet = twitterAPI.GetStatus(status_id=id_tweet)
|
|||
|
|
|||
|
# Log into Mastodon via API
|
|||
|
mastodon_hostname = conf['mastodon']['MASTODON_INSTANCE']
|
|||
|
try:
|
|||
|
mastodonAPI = Mastodon(
|
|||
|
client_id=conf['mastodon']['MASTODON_APPID'],
|
|||
|
client_secret=conf['mastodon']['MASTODON_APPSECRET'],
|
|||
|
access_token=conf['mastodon']['MASTODON_APPTOKEN'],
|
|||
|
api_base_url='https://' + mastodon_hostname)
|
|||
|
masto_username = mastodonAPI.account_verify_credentials()['username']
|
|||
|
print ('[ OK ] Sucessfully authenticated on ' + mastodon_hostname
|
|||
|
+ ' as @' + masto_username)
|
|||
|
except BaseException as e:
|
|||
|
print ('[ERROR] Error while logging into Mastodon:', str(e))
|
|||
|
sys.exit(0)
|
|||
|
|
|||
|
'''
|
|||
|
Construct the toot status with the tweet status
|
|||
|
'''
|
|||
|
# The toot base
|
|||
|
toot_status += 'RT @' + tweet.user.screen_name + '@twitter.com'
|
|||
|
toot_status += '\n \n'
|
|||
|
toot_status += tweet.full_text
|
|||
|
# Attach the tweet media files to the toot
|
|||
|
if tweet.media:
|
|||
|
media_dict = []
|
|||
|
addmedia(tweet.media)
|
|||
|
# Retrieve the tweet quoted and
|
|||
|
if tweet.quoted_status:
|
|||
|
toot_status += '\n\n'
|
|||
|
toot_status += '❝ '
|
|||
|
#toot_status += '\n'
|
|||
|
idtweetquoted = tweet.quoted_status.id_str
|
|||
|
tweetquoted = twitterAPI.GetStatus(status_id=idtweetquoted)
|
|||
|
toot_status += '@' + tweetquoted.user.screen_name + '@twitter.com'
|
|||
|
toot_status += '\n'
|
|||
|
toot_status += tweetquoted.full_text
|
|||
|
#toot_status += '\n'
|
|||
|
toot_status += ' ❞'
|
|||
|
# Attach the tweet quoted media files to the toot
|
|||
|
if tweetquoted.media:
|
|||
|
media_dict = []
|
|||
|
addmedia(tweetquoted.media)
|
|||
|
# Add the tweet source link
|
|||
|
toot_status += '\n\n'
|
|||
|
toot_status += '🔗' + url_tweet
|
|||
|
if DEBUG :
|
|||
|
print(toot_status)
|
|||
|
print(len(toot_status))
|
|||
|
|
|||
|
'''
|
|||
|
Sending the toot
|
|||
|
'''
|
|||
|
|
|||
|
try:
|
|||
|
status = mastodonAPI.status_post(
|
|||
|
status=toot_status,
|
|||
|
in_reply_to_id=None,
|
|||
|
media_ids=media_dict,
|
|||
|
sensitive=False,
|
|||
|
visibility='public',
|
|||
|
spoiler_text=None
|
|||
|
)
|
|||
|
print (
|
|||
|
'[ OK ] Posting this on Mastodon account with media attachment : '
|
|||
|
+ status['url'])
|
|||
|
except BaseException as e:
|
|||
|
print ('[ERROR] Error while posting toot:' + str(e))
|
|||
|
|