Saumya-Gupta-26 / twitter-bot-post-images

A Twitter bot that posts/tweets images/videos once every hour.
5 stars 0 forks source link

shutil.move #1

Closed doppochi closed 3 weeks ago

doppochi commented 3 weeks ago

Hi! Thank you so much for sharing your code. I'm trying to make an hourly bot on twitter too, and I think I was able to get it to run with Python (it was able to post one image for now, waiting for an hour to pass LOL). I was wondering if you could share with me the shutil.move code and how it'd fit into the whole python code? Do I insert it at the very end of the code? I'm a total beginner at coding, so I'd really appreciate the help!

doppochi commented 3 weeks ago

Sorry for the additional comment! Are you hosting on AWS for free?

Saumya-Gupta-26 commented 3 weeks ago

Hello, thanks for your question ^^

Hopefully your bot worked after an hour! :D Let me know if there are any issues.

Regarding AWS --- Yes, I am hosting it on AWS for free right now. AWS gives new users a certain quota for free for 12 months. The quota is sufficient for making hourly posts, hence it's free for me right now.

I can help you with the shutil.move thing. Although, I am using os.rename instead. Essentially in the following code, I always tweet an image from image_folder, and then move it to the backup_folder. Once image_folder is empty, I restore all content from backup_folder to image_folder.

# Directory where images are stored
image_folder = '/path/to/directory/1'
# Backup directory to avoid repeats
backup_folder = '/path/to/directory/2'

# this function checks if image_folder is empty. if its not empty, do nothing. if it is empty, restore all contents from backup_folder
def check_dirs():
    filenames = os.listdir(image_folder)
    if len(filenames) == 0: 
        filenames = os.listdir(backup_folder)
        for fn in filenames:
            os.rename(os.path.join(backup_folder, fn), os.path.join(image_folder, fn)) 

def tweet_random_image():

    # if image_folder is empty, restore all contents from backup
    check_dirs()

    images = os.listdir(image_folder)
    random.shuffle(images)
    random_image = random.choice(images)
    image_path = os.path.join(image_folder, random_image)

    try:
        # Post the image via v1.1 first, get the media-id and then use v2
        media = api_v1.media_upload(image_path)
        client_v2.create_tweet(media_ids=[media.media_id])

        # successfully tweeted ; now move to backup
        os.rename(image_path, image_path.replace(image_folder, backup_folder))

    except:
        print("Error for tweeting file: {}".format(random_image))
        if os.path.exists(image_path):
            try:
                os.rename(image_path, image_path.replace(image_folder, backup_folder))
            except:
                print("Error in moving file : {}".format(random_image))
        tweet_random_image() # since the tweet failed, try again
doppochi commented 3 weeks ago

Thank you so much for your quick response!! The bot does run every hour! But it's somehow not running after I modified it with your new code. Apologies for wasting your time again, but is this how the code should be?

# Use pip/conda to make sure the following libraries exist in your enviroment
import os, random, tweepy, time, schedule

# Fill in your credentials here; Alternatively, use os.environ if you want to use environment variables instead
CONSUMER_KEY = " "
CONSUMER_SECRET = " "
ACCESS_KEY = " "
ACCESS_SECRET = " "

# Twitter API v2 --- Will be used to post the tweet
client_v2 = tweepy.Client(
    consumer_key=CONSUMER_KEY,
    consumer_secret=CONSUMER_SECRET,
    access_token=ACCESS_KEY,
    access_token_secret=ACCESS_SECRET
)

# Twitter API v1.1 --- Will be used to obtain media-id that is needed to post the tweet
auth = tweepy.OAuth1UserHandler(CONSUMER_KEY, CONSUMER_SECRET)
auth.set_access_token(
    ACCESS_KEY,
    ACCESS_SECRET,
)
api_v1 = tweepy.API(auth)

# Directory where images are stored
image_folder = ' '

# Backup directory to avoid repeats
backup_folder = ' '

# this function checks if image_folder is empty. if its not empty, do nothing. if it is empty, restore all contents from backup_folder
def check_dirs():
    filenames = os.listdir(image_folder)
    if len(filenames) == 0: 
        filenames = os.listdir(backup_folder)
        for fn in filenames:
            os.rename(os.path.join(backup_folder, fn), os.path.join(image_folder, fn)) 

def tweet_random_image():

    # if image_folder is empty, restore all contents from backup
    check_dirs()

    images = os.listdir(image_folder)
    random.shuffle(images)
    random_image = random.choice(images)
    image_path = os.path.join(image_folder, random_image)

    try:
        # Post the image via v1.1 first, get the media-id and then use v2
        media = api_v1.media_upload(image_path)
        client_v2.create_tweet(media_ids=[media.media_id])

        # successfully tweeted ; now move to backup
        os.rename(image_path, image_path.replace(image_folder, backup_folder))

    except:
        print("Error for tweeting file: {}".format(random_image))
        if os.path.exists(image_path):
            try:
                os.rename(image_path, image_path.replace(image_folder, backup_folder))
            except:
                print("Error in moving file : {}".format(random_image))
        tweet_random_image() # since the tweet failed, try again

# Schedule the tweet to be sent now and then once every hour
schedule.every().hour.do(tweet_random_image)

# Code runs forerver. After every second, it checkes whether there is a scheduled job, and if there is, it calls tweet_random_image()
while True:
    schedule.run_pending()
    time.sleep(1)
doppochi commented 3 weeks ago

Apologies for the additional notification again!!!! I wanted to ask if you've tried hosting the code with Cron-job.org before, since it's free!

Saumya-Gupta-26 commented 3 weeks ago

Hello,

Your current code will start tweeting an hour later. If you want to start tweeting now itself, you will need to explicitly call it like the line here. The explicit call is missing in the code you have provided. Let me know if it works!

Regarding cron-job, I haven't tried yet. My friend was suggesting supabase as well. My current code needs a place where a directory can be hosted too (essentially image_folder and backup_folder). Hence 'server-free' methods won't work with this code. Do you know if cron-job has the feature to allow us to host directories? If it ends up working for you, please let me know, I can try it too! My one year free AWS ends in Jan 2025, so having alternatives will be useful haha :D

doppochi commented 3 weeks ago

Thank you!! It works! I looked up for alternatives and there seems to be Google Cloud, Oracle Cloud and Azure in terms of low-cost/free tier services. I am trying to get Google Cloud to work but yeaaah, please let me know if you decide to try it out!

doppochi commented 2 weeks ago

Hello! Apologies for bothering you again, but I've been running the program on my PC. Earlier, my wifi got disconnected, and the program ended up trying to tweet a bunch of images (and obviously failed), and those images got moved from the main folder to the backup folder + the program tweeted a bunch of the same three images like 25x time in the same minute LOL. Is there a way to prevent this?

Saumya-Gupta-26 commented 2 weeks ago

Hi!

So, moving images from main -> backup for a failed tweet is an intended functionality. The code also attempts to tweet again if something failed, so that it doesn't stay idle and just wait for the next hour. Maybe that's why it tweeted a bunch for you.

You can try the following code. In this case, if a tweet failed, nothing will happen, and the code will attempt again an hour later. In the except block, just keep it as the following, and remove the other lines.

    except:
        print("Error for tweeting file: {}".format(random_image))
doppochi commented 2 weeks ago

You are godsent!! Thank you so much for helping a noob like me 😭🙇‍♀️ If you ever decide to use Google Cloud or Azure, could you help me with setting up mine too? I'd be willing to pay you money if you wish! 🥺 No pressure if you don't want to, though!!