diff --git a/foodie_weekly_thread.py b/foodie_weekly_thread.py index 3395cfe..60c5520 100644 --- a/foodie_weekly_thread.py +++ b/foodie_weekly_thread.py @@ -15,7 +15,8 @@ from foodie_config import X_API_CREDENTIALS, RECENT_POSTS_FILE from dotenv import load_dotenv load_dotenv() - +# Output file for weekly thread content +WEEKLY_THREADS_FILE = "/home/shane/foodie_automator/weekly_threads.json" SCRIPT_NAME = "foodie_weekly_thread" LOCK_FILE = "/home/shane/foodie_automator/locks/foodie_weekly_thread.lock" LOG_FILE = "/home/shane/foodie_automator/logs/foodie_weekly_thread.log" @@ -267,7 +268,7 @@ def generate_final_cta(author): return fallback def post_weekly_thread(): - """Generate and post a weekly thread of top posts for each author on Mondays.""" + """Generate weekly thread content for each author and save to file on Mondays.""" logging.info("Starting foodie_weekly_thread.py") # Check if today is Monday @@ -307,7 +308,10 @@ def post_weekly_thread(): if username in posts_by_author: posts_by_author[username].append(post) - # Post threads for each author + # Generate thread content for each author and save to file + thread_content = [] + timestamp = datetime.now(timezone.utc).isoformat() + for author in AUTHORS: username = author["username"] author_posts = posts_by_author.get(username, []) @@ -315,56 +319,73 @@ def post_weekly_thread(): logging.info(f"No posts found for {username}, skipping") continue - # Check if the author can post before generating the thread - can_post, remaining, reset = check_author_rate_limit(author) - if not can_post: - reset_time = datetime.fromtimestamp(reset, tz=timezone.utc).strftime('%Y-%m-%d %H:%M:%S') if reset else "Unknown" - logging.info(f"Skipping weekly thread for {username} due to rate limit. Reset at: {reset_time}") - continue - # Select top 2 posts (to fit within 3-tweet limit: lead + 2 posts) author_posts = sorted(author_posts, key=lambda x: datetime.fromisoformat(x["timestamp"]), reverse=True)[:2] logging.info(f"Selected {len(author_posts)} posts for {username}") - # Generate and post thread + # Generate thread content try: - # Post lead tweet + # Generate intro tweet intro_tweet = generate_intro_tweet(author) if not intro_tweet: logging.error(f"Failed to generate intro tweet for {username}, skipping") continue - lead_response = post_tweet(author, intro_tweet) - if not lead_response: - logging.error(f"Failed to post lead tweet for {username}, skipping") - continue - lead_tweet_id = lead_response["id"] - logging.info(f"Posted lead tweet for {username}: {intro_tweet}") - # Post thread tweets (up to 2) + # Generate thread tweets (up to 2) + thread_tweets = [] for i, post in enumerate(author_posts, 1): thread_tweet = ( f"{i}. {post['title']} " f"Read more: {post['url']}" ) - thread_response = post_tweet(author, thread_tweet, reply_to_id=lead_tweet_id) - if thread_response: - lead_tweet_id = thread_response["id"] - logging.info(f"Posted thread tweet {i} for {username}: {thread_tweet}") - else: - logging.warning(f"Failed to post thread tweet {i} for {username}") + thread_tweets.append(thread_tweet) + logging.info(f"Generated thread tweet {i} for {username}: {thread_tweet}") - # Post final CTA tweet + # Generate final CTA tweet final_cta = generate_final_cta(author) - if final_cta: - cta_response = post_tweet(author, final_cta, reply_to_id=lead_tweet_id) - if cta_response: - logging.info(f"Posted final CTA tweet for {username}: {final_cta}") - else: - logging.warning(f"Failed to post final CTA tweet for {username}") + if not final_cta: + logging.error(f"Failed to generate final CTA tweet for {username}, using fallback") + final_cta = ( + f"Want more foodie insights like these? Check out insiderfoodie.com and follow @{X_API_CREDENTIALS[username]['x_username']} " + f"for the world’s top 10 foodie trends every Monday. Don’t miss out!" + ) + + # Collect thread content for this author + author_thread = { + "username": username, + "x_handle": X_API_CREDENTIALS[username]["x_username"], + "intro_tweet": intro_tweet, + "thread_tweets": thread_tweets, + "final_cta": final_cta, + "timestamp": timestamp + } + thread_content.append(author_thread) + logging.info(f"Generated thread content for {username}") + except Exception as e: - logging.error(f"Error posting thread for {username}: {e}", exc_info=True) + logging.error(f"Error generating thread content for {username}: {e}", exc_info=True) continue - + + # Save thread content to file + if thread_content: + try: + # Load existing threads, if any + existing_threads = load_json_file(WEEKLY_THREADS_FILE, default=[]) + # Append new thread content + existing_threads.append({ + "week_start": start_date.isoformat(), + "week_end": end_date.isoformat(), + "timestamp": timestamp, + "threads": thread_content + }) + # Save to file + save_json_file(WEEKLY_THREADS_FILE, existing_threads) + logging.info(f"Saved thread content for {len(thread_content)} authors to {WEEKLY_THREADS_FILE}") + except Exception as e: + logging.error(f"Failed to save thread content to {WEEKLY_THREADS_FILE}: {e}") + else: + logging.warning("No thread content generated, nothing to save") + logging.info("Completed foodie_weekly_thread.py") def main(): @@ -374,6 +395,8 @@ def main(): lock_fd = acquire_lock() setup_logging() update_system_activity(SCRIPT_NAME, "running", os.getpid()) # Record start + # Skip Twitter credentials validation since we're not posting + # validate_twitter_credentials() post_weekly_thread() update_system_activity(SCRIPT_NAME, "stopped") # Record stop except Exception as e: