Search code examples
pythonpython-3.xtwittertweepytwitterapi-python

How to possibly tweet more than 280 chars? So if string > 280, print first 280 chars, then tweet again in that thread with the rest of the chars


Sorry for the choppy title, word limit (ironic). I've created a bot that responds with a randomly chosen string from a list when it's mentioned, pretty normal.

The thing is that most of the strings in my list are more than 280 chars, twitters word limit. Also the fact that the users twitter handle, the '@', and the space after the username (where the string should start) count towards the word limit

This is the code that I have come up with but I am stumped...

import replies # Separate file where all replies are stored
def reply_to_tweets():
    print("Scanning for new mentions...")
    last_seen_id = retrieve_id(FILE)
    mentions = api.mentions_timeline(last_seen_id, tweet_mode="extended")
    myself = api.me()
    for tweet in reversed(mentions): 
        if myself.screen_name in tweet.full_text: # If my @ is in the full text
            if tweet.in_reply_to_status_id is not None:
                continue
            last_seen_id = tweet.id 
            store_id(last_seen_id,FILE) 
            random_choice = random.choice(replies.strings_more_than_280)  # Random string chosen
            def splitter(chosen_string):
                return [char for char in chosen_string] # This part may be obsolete but it gives 
                                                        # me peace of mind as I know it counts 
                                                        # emojis and spaces!

            username = '@' + tweet.user.screen_name 
# There is a space at the beginning of every string in my list, so this should 
# account for the character after the @ where the string should go
            length_of_user = len(username) # WORKS
            
            splitter_in_action = splitter(random_choice)
            length_of_string = len(splitter_in_action)
# This is where the space is counted, since there's a space in the beginning of 
# the string already, then it'll count towards the length of the string when we 
# calculate it using the splitter() function

            difference = length_of_string - length_of_user
            difference2 = difference - length_of_user
            if length_of_string + length_of_user > 280: 
                print(username + random_choice[:difference2]) # status update goes here
                
# Now those last few lines of code, I'm just guessing, I have no idea how to 
# calculate for the difference in my string minus the user's @ and then tweet up
# to 280 chars, then tweet the rest later. It's probably simple but I am perplexed!!!

The error is [{'code': 186, 'message': 'Tweet needs to be a bit shorter.'}]

  • EDIT: Deleted the whole error callback (not sure exactly what it's called) and just added the major error above

Any help would be greatly as I've been stuck here a while. This isn't meant to spam people and be annoying, It's just that the messages I want the bot to print are too long, so yeah, I know it's a lot of code but I really hope someone can enlighten me!


Solution

  • This is a work in progress and needs some more testing based on your use case. I did some research and determine that the best way to split your long tweets would be with textwrap. This module will allow you to cleanly break your tweets into chunks.

    I only attempted one tweet and one twitter handle in my tests, but I believe that the code below should work for your use case or give you a solid starting point to fit this functionality into your code.

    Let me know if you have any questions about the code.

    import math
    import textwrap
    
    # the tweet in this list is 1471 characters in length
    tweets = [
        'Four score and seven years ago our fathers brought forth upon this continent, a new nation, conceived in Liberty, '
        'and dedicated to the proposition that all men are created equal. Now we are engaged in a great civil war, '
        'testing whether that nation, or any nation so conceived and so dedicated, can long endure. We are met on a '
        'great battle-field of that war. We have come to dedicate a portion of that field, as a final resting place for those '
        'who here gave their lives that that nation might live. It is altogether fitting and proper that we should '
        'do this. But, in a larger sense, we can not dedicate—we can not consecrate—we can not hallow—this ground. '
        'The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. '
        'The world will little note, nor long remember what we say here, but it can never forget what they did here. '
        'It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have '
        'thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us—that '
        'from these honored dead we take increased devotion to that cause for which they gave the last full measure of '
        'devotion—that we here highly resolve that these dead shall not have died in vain—that this nation, under God, '
        'shall have a new birth of freedom—and that government of the people, by the people, for the people, shall '
        'not perish from the earth. —Abraham Lincoln']
    
    
    twitter_handle = ['@MariahCarey']
    
    for handle in twitter_handle:
        handle_length = len(handle)
        for tweet in tweets:
    
            # obtain length of tweet, which is 1471 characters
            tweet_length = len(tweet)
    
            # check length
            if tweet_length <= 280:
                # do some here
    
            elif tweet_length >= 280:
    
                # divided tweet_length / 280
                # You might consider adjusting this down 
                # depending on how you want to format the 
                # tweet.
                tweet_length_limit = tweet_length / 280
    
                # determine the number of tweets 
                # math.ceil is used because we need to round up
                tweet_chunk_length = tweet_length / math.ceil(tweet_length_limit) + handle_length
    
                # chunk the tweet into individual pieces
                tweet_chunks = textwrap.wrap(tweet,  math.ceil(tweet_chunk_length), break_long_words=False)
    
                # iterate over the chunks 
                for x, chunk in zip(range(len(tweet_chunks)), tweet_chunks):
                    if x == 0:
                        print(f'{handle} 1 of {len(tweet_chunks)} {chunk}')
                    else:
                        print(f'{handle} {x+1} of {len(tweet_chunks)} {chunk}')
                        
    

    Print Output:

    # length 275
    @MariahCarey 1 of 6 Four score and seven years ago our fathers brought forth upon this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal. Now we are engaged in a great civil war, testing whether that nation, or any
    
    # length 268
    @MariahCarey 2 of 6 nation so conceived and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is
    
    # length 278
    @MariahCarey 3 of 6 altogether fitting and proper that we should do this. But, in a larger sense, we can not dedicate—we can not consecrate—we can not hallow—this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or
    
    # length 276
    @MariahCarey 4 of 6 detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It
    
    # length 278
    @MariahCarey 5 of 6 is rather for us to be here dedicated to the great task remaining before us—that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion—that we here highly resolve that these dead shall not have
    
    # length 211
    @MariahCarey 6 of 6 died in vain—that this nation, under God, shall have a new birth of freedom—and that government of the people, by the people, for the people, shall not perish from the earth. —Abraham Lincoln