From b3025f73ca951ba58752d2a798f39d8b45e097e8 Mon Sep 17 00:00:00 2001 From: spla Date: Mon, 14 Feb 2022 20:41:43 +0100 Subject: [PATCH] Update tweepy to 4.5.0 and...polls support! --- mastotuit.py | 200 +++++++++++++++++++++++++++++++++++------------ requirements.txt | 2 +- 2 files changed, 150 insertions(+), 52 deletions(-) diff --git a/mastotuit.py b/mastotuit.py index c11de3c..e2ddffe 100644 --- a/mastotuit.py +++ b/mastotuit.py @@ -12,7 +12,6 @@ from tweepy import TweepyException import logging import filetype import ffmpeg -import pdb logger = logging.getLogger() @@ -29,6 +28,62 @@ def get_toot_text(title): return tuit_text +def get_poll(tuit_text): + + poll_substring = '[ ]' + poll_options = tuit_text.count(poll_substring) + + is_poll = False if poll_options == 0 else True + + options_lst = [] + + remain_str = tuit_text.replace('\n', '') + + i = poll_options + while (i > 0): + + last_option_index = remain_str.rfind('[ ]') + option_str = remain_str[last_option_index+3:].strip() + options_lst.append(option_str) + remain_str = remain_str[:last_option_index] + i-=1 + + if is_poll: + + options_lst_copy = options_lst.copy() + options_lst_copy.reverse() + options_lst = options_lst_copy.copy() + tuit_text = remain_str + + return (tuit_text, poll_options, options_lst, is_poll) + +def get_toot(title): + + tuit_text = get_toot_text(title) + + tuit_text, poll_options, options_lst, is_poll = get_poll(tuit_text) + + return (tuit_text, poll_options, options_lst, is_poll) + +def compose_poll(tuit_text, poll_options, options_lst, toot_id): + + try: + + tweet = apiv2.create_tweet( + poll_duration_minutes=4320, + poll_options = options_lst, + text=tuit_text + ) + + write_db(toot_id, tweet.data['id']) + + except TweepyException as err: + + print('Error while trying to publish poll.\n') + sys.exit(err) + + return tweet + def compose_tweet(tuit_text, with_images, is_reply): images_id_lst = [] @@ -61,7 +116,7 @@ def compose_tweet(tuit_text, with_images, is_reply): try: - media_upload = api.media_upload( + media_upload = apiv1.media_upload( f'images/{image}', media_category='tweet_video' if is_video else 'tweet_image' ) @@ -84,30 +139,45 @@ def compose_tweet(tuit_text, with_images, is_reply): # Compose tuit tuit_text2 = '' + three_parts = False + if len(tuit_text) > 280: - tuit_max_length = 250 if with_images else 275 + tuit_max_length = 250 if with_images else 273 - tuit_text1 = '{0} (1/2)'.format( - tuit_text[:tuit_max_length].rsplit(' ', 1)[0] - ) - tuit_text2 = '{0} (2/2)'.format( - tuit_text[len(tuit_text1) - 6:] - ) + tuit_text1 = '{0}...'.format(tuit_text[:tuit_max_length].rsplit(' ', 1)[0]) + + tuit_text2 = '{0}'.format(tuit_text[len(tuit_text1) - 2:]) + + if len(tuit_text2) > 250: + + three_parts = True + + tuit_text2 = '{0}'.format(tuit_text[len(tuit_text1) - 2:].rsplit('#', 1)[0]) + + tuit_text3 = '#{0}'.format(tuit_text[len(tuit_text1) - 2:].rsplit('#', 1)[1].rsplit(' ', 2)[0]) try: - first_tweet = api.update_status( + first_tweet = apiv1.update_status( status=tuit_text1, - in_reply_to_status_id=tweet_id if is_reply else '' - ) - - tweet = api.update_status( - status=tuit_text2, - in_reply_to_status_id=first_tweet.id, + in_reply_to_status_id=tweet_id if is_reply else '', media_ids=images_id_lst ) + tweet = apiv1.update_status( + status=tuit_text2, + in_reply_to_status_id=first_tweet.id + #media_ids=images_id_lst + ) + + if three_parts: + + tweet = apiv1.update_status( + status=tuit_text3, + in_reply_to_status_id=tweet.id + ) + except TweepyException as err: print('Error while trying to publish split tweet.\n') @@ -117,7 +187,7 @@ def compose_tweet(tuit_text, with_images, is_reply): try: - tweet = api.update_status( + tweet = apiv1.update_status( status=tuit_text, in_reply_to_status_id=tweet_id if is_reply else '', media_ids=images_id_lst @@ -164,6 +234,34 @@ def get_tweet_id(toot_id): conn.close() +def write_db(toot_id, tweet_id): + + sql_insert_ids = 'INSERT INTO id(toot_id, tweet_id) VALUES (%s,%s)' + + conn = None + + try: + + conn = psycopg2.connect(database = feeds_db, user = feeds_db_user, password = "", host = "/var/run/postgresql", port = "5432") + + cur = conn.cursor() + + cur.execute(sql_insert_ids, (toot_id, tweet_id)) + + conn.commit() + + cur.close() + + except (Exception, psycopg2.DatabaseError) as error: + + print(error) + + finally: + + if conn is not None: + + conn.close() + def write_image(image_url): if not os.path.exists('images'): @@ -176,19 +274,40 @@ def write_image(image_url): return filename -def create_api(): +def create_api_v1(): auth = tweepy.OAuthHandler(api_key, api_key_secret) auth.set_access_token(access_token, access_token_secret) - api = tweepy.API(auth) + apiv1 = tweepy.API(auth) try: - api.verify_credentials() + apiv1.verify_credentials() logged_in = True except Exception as e: logger.error("Error creating API", exc_info=True) raise e logger.info("API created") - return (api, logged_in) + return (apiv1, logged_in) + +def create_api_v2(): + + try: + + apiv2 = tweepy.Client( + consumer_key=api_key, + consumer_secret=api_key_secret, + access_token=access_token, + access_token_secret=access_token_secret + ) + logged_in = True + + except Exception as e: + + logger.error("Error creating API", exc_info=True) + raise e + + logger.info("API v2 created") + + return (apiv2, logged_in) def mastodon(): @@ -235,7 +354,6 @@ def twitter_config(): return(api_key, api_key_secret, access_token, access_token_secret) -# Returns the parameter from the specified file def get_parameter( parameter, file_path ): # Check if secrets file exists if not os.path.isfile(file_path): @@ -252,7 +370,6 @@ def get_parameter( parameter, file_path ): print(file_path + " Missing parameter %s "%parameter) sys.exit(0) -############################################################################### # main if __name__ == '__main__': @@ -316,46 +433,26 @@ if __name__ == '__main__': if publish: - tuit_text = get_toot_text(title) + tuit_text, poll_options, options_lst, is_poll = get_toot(title) print("Tooting...") print(tuit_text) if not logged_in: - api, logged_in = create_api() + apiv1, logged_in = create_api_v1() - tweet = compose_tweet(tuit_text, with_images, is_reply) + apiv2, logged_in = create_api_v2() - ######################################################### + if is_poll: - sql_insert_ids = 'INSERT INTO id(toot_id, tweet_id) VALUES (%s,%s)' + tweet = compose_poll(tuit_text, poll_options, options_lst, toot_id) - conn = None + else: - try: + tweet = compose_tweet(tuit_text, with_images, is_reply) - conn = psycopg2.connect(database = feeds_db, user = feeds_db_user, password = "", host = "/var/run/postgresql", port = "5432") - - cur = conn.cursor() - - cur.execute(sql_insert_ids, (toot_id, tweet.id)) - - conn.commit() - - cur.close() - - except (Exception, psycopg2.DatabaseError) as error: - - print(error) - - finally: - - if conn is not None: - - conn.close() - - ######################################################### + write_db(toot_id, tweet.id) time.sleep(2) @@ -363,3 +460,4 @@ if __name__ == '__main__': print("Any new feeds") sys.exit(0) + diff --git a/requirements.txt b/requirements.txt index 1c963f9..df97b66 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,6 +3,6 @@ psycopg2>=2.9.1 feedparser>=6.0.8 html2text>=2020.1.16 Mastodon.py>=1.5.1 -tweepy==4.1.0 +tweepy>=4.5.0 filetype>=1.0.8 ffmpeg-python>=0.2.0