fix image upload issue
This commit is contained in:
+61
-49
@@ -37,23 +37,12 @@ load_dotenv()
|
|||||||
|
|
||||||
is_posting = False
|
is_posting = False
|
||||||
LOCK_FILE = "/home/shane/foodie_automator/locks/foodie_automator_rss.lock"
|
LOCK_FILE = "/home/shane/foodie_automator/locks/foodie_automator_rss.lock"
|
||||||
|
|
||||||
def signal_handler(sig, frame):
|
|
||||||
logging.info("Received termination signal, checking if safe to exit...")
|
|
||||||
if is_posting:
|
|
||||||
logging.info("Currently posting, will exit after completion.")
|
|
||||||
else:
|
|
||||||
logging.info("Safe to exit immediately.")
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
signal.signal(signal.SIGTERM, signal_handler)
|
|
||||||
signal.signal(signal.SIGINT, signal_handler)
|
|
||||||
|
|
||||||
LOG_FILE = "/home/shane/foodie_automator/logs/foodie_automator_rss.log"
|
LOG_FILE = "/home/shane/foodie_automator/logs/foodie_automator_rss.log"
|
||||||
LOG_PRUNE_DAYS = 30
|
LOG_PRUNE_DAYS = 30
|
||||||
FEED_TIMEOUT = 15
|
FEED_TIMEOUT = 15
|
||||||
MAX_RETRIES = 3
|
MAX_RETRIES = 3
|
||||||
RETRY_BACKOFF = 2
|
RETRY_BACKOFF = 2
|
||||||
|
IMAGE_UPLOAD_TIMEOUT = 30 # Added to match foodie_utils.py
|
||||||
|
|
||||||
POSTED_TITLES_FILE = '/home/shane/foodie_automator/posted_rss_titles.json'
|
POSTED_TITLES_FILE = '/home/shane/foodie_automator/posted_rss_titles.json'
|
||||||
USED_IMAGES_FILE = '/home/shane/foodie_automator/used_images.json'
|
USED_IMAGES_FILE = '/home/shane/foodie_automator/used_images.json'
|
||||||
@@ -65,39 +54,48 @@ posted_titles = set(entry["title"] for entry in posted_titles_data)
|
|||||||
used_images = set(entry["title"] for entry in load_json_file(USED_IMAGES_FILE, IMAGE_EXPIRATION_DAYS) if "title" in entry)
|
used_images = set(entry["title"] for entry in load_json_file(USED_IMAGES_FILE, IMAGE_EXPIRATION_DAYS) if "title" in entry)
|
||||||
|
|
||||||
def setup_logging():
|
def setup_logging():
|
||||||
if os.path.exists(LOG_FILE):
|
"""Initialize logging with pruning of old logs."""
|
||||||
with open(LOG_FILE, 'r') as f:
|
try:
|
||||||
lines = f.readlines()
|
os.makedirs(os.path.dirname(LOG_FILE), exist_ok=True)
|
||||||
cutoff = datetime.now(timezone.utc) - timedelta(days=LOG_PRUNE_DAYS)
|
if not os.access(os.path.dirname(LOG_FILE), os.W_OK):
|
||||||
pruned_lines = []
|
raise PermissionError(f"No write permission for {os.path.dirname(LOG_FILE)}")
|
||||||
malformed_count = 0
|
if os.path.exists(LOG_FILE):
|
||||||
for line in lines:
|
with open(LOG_FILE, 'r') as f:
|
||||||
if len(line) < 19 or not line[:19].replace('-', '').replace(':', '').replace(' ', '').isdigit():
|
lines = f.readlines()
|
||||||
malformed_count += 1
|
cutoff = datetime.now(timezone.utc) - timedelta(days=LOG_PRUNE_DAYS)
|
||||||
continue
|
pruned_lines = []
|
||||||
try:
|
malformed_count = 0
|
||||||
timestamp = datetime.strptime(line[:19], '%Y-%m-%d %H:%M:%S').replace(tzinfo=timezone.utc)
|
for line in lines:
|
||||||
if timestamp > cutoff:
|
if len(line) < 19 or not line[:19].replace('-', '').replace(':', '').replace(' ', '').isdigit():
|
||||||
pruned_lines.append(line)
|
malformed_count += 1
|
||||||
except ValueError:
|
continue
|
||||||
malformed_count += 1
|
try:
|
||||||
continue
|
timestamp = datetime.strptime(line[:19], '%Y-%m-%d %H:%M:%S').replace(tzinfo=timezone.utc)
|
||||||
if malformed_count > 0:
|
if timestamp > cutoff:
|
||||||
logging.info(f"Skipped {malformed_count} malformed log lines during pruning")
|
pruned_lines.append(line)
|
||||||
with open(LOG_FILE, 'w') as f:
|
except ValueError:
|
||||||
f.writelines(pruned_lines)
|
malformed_count += 1
|
||||||
|
continue
|
||||||
|
if malformed_count > 0:
|
||||||
|
logging.info(f"Skipped {malformed_count} malformed log lines during pruning")
|
||||||
|
with open(LOG_FILE, 'w') as f:
|
||||||
|
f.writelines(pruned_lines)
|
||||||
|
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
filename=LOG_FILE,
|
filename=LOG_FILE,
|
||||||
level=logging.INFO,
|
level=logging.INFO,
|
||||||
format="%(asctime)s - %(levelname)s - %(message)s",
|
format="%(asctime)s - %(levelname)s - %(message)s",
|
||||||
datefmt="%Y-%m-%d %H:%M:%S"
|
datefmt="%Y-%m-%d %H:%M:%S"
|
||||||
)
|
)
|
||||||
console_handler = logging.StreamHandler()
|
console_handler = logging.StreamHandler()
|
||||||
console_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
|
console_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
|
||||||
logging.getLogger().addHandler(console_handler)
|
logging.getLogger().addHandler(console_handler)
|
||||||
logging.getLogger("requests").setLevel(logging.WARNING)
|
logging.getLogger("requests").setLevel(logging.WARNING)
|
||||||
logging.info("Logging initialized for foodie_automator_rss.py")
|
logging.getLogger("openai").setLevel(logging.WARNING)
|
||||||
|
logging.info("Logging initialized for foodie_automator_rss.py")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed to setup logging: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
def acquire_lock():
|
def acquire_lock():
|
||||||
os.makedirs(os.path.dirname(LOCK_FILE), exist_ok=True)
|
os.makedirs(os.path.dirname(LOCK_FILE), exist_ok=True)
|
||||||
@@ -111,6 +109,17 @@ def acquire_lock():
|
|||||||
logging.info("Another instance of foodie_automator_rss.py is running")
|
logging.info("Another instance of foodie_automator_rss.py is running")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
def signal_handler(sig, frame):
|
||||||
|
logging.info("Received termination signal, checking if safe to exit...")
|
||||||
|
if is_posting:
|
||||||
|
logging.info("Currently posting, will exit after completion.")
|
||||||
|
else:
|
||||||
|
logging.info("Safe to exit immediately.")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
signal.signal(signal.SIGTERM, signal_handler)
|
||||||
|
signal.signal(signal.SIGINT, signal_handler)
|
||||||
|
|
||||||
def create_http_session() -> requests.Session:
|
def create_http_session() -> requests.Session:
|
||||||
session = requests.Session()
|
session = requests.Session()
|
||||||
retry_strategy = Retry(
|
retry_strategy = Retry(
|
||||||
@@ -209,7 +218,7 @@ def fetch_duckduckgo_news_context(title, hours=24):
|
|||||||
if '+00:00' in date_str:
|
if '+00:00' in date_str:
|
||||||
dt = datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%S+00:00").replace(tzinfo=timezone.utc)
|
dt = datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%S+00:00").replace(tzinfo=timezone.utc)
|
||||||
else:
|
else:
|
||||||
dt = datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%S%Z").replace(tzinfo=timezone.utc)
|
dt = datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=timezone.utc)
|
||||||
if dt > (datetime.now(timezone.utc) - timedelta(hours=24)):
|
if dt > (datetime.now(timezone.utc) - timedelta(hours=24)):
|
||||||
titles.append(r["title"].lower())
|
titles.append(r["title"].lower())
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
@@ -324,6 +333,10 @@ def curate_from_rss():
|
|||||||
interest_score=interest_score,
|
interest_score=interest_score,
|
||||||
should_post_tweet=True
|
should_post_tweet=True
|
||||||
)
|
)
|
||||||
|
if not post_id:
|
||||||
|
logging.warning(f"Failed to post to WordPress for '{title}', skipping")
|
||||||
|
attempts += 1
|
||||||
|
continue
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Failed to post to WordPress for '{title}': {e}", exc_info=True)
|
logging.error(f"Failed to post to WordPress for '{title}': {e}", exc_info=True)
|
||||||
attempts += 1
|
attempts += 1
|
||||||
@@ -383,6 +396,7 @@ def run_rss_automator():
|
|||||||
lock_fd = None
|
lock_fd = None
|
||||||
try:
|
try:
|
||||||
lock_fd = acquire_lock()
|
lock_fd = acquire_lock()
|
||||||
|
setup_logging()
|
||||||
logging.info("***** RSS Automator Launched *****")
|
logging.info("***** RSS Automator Launched *****")
|
||||||
post_data, category, should_continue = curate_from_rss()
|
post_data, category, should_continue = curate_from_rss()
|
||||||
if not post_data:
|
if not post_data:
|
||||||
@@ -392,6 +406,7 @@ def run_rss_automator():
|
|||||||
return post_data, category, should_continue
|
return post_data, category, should_continue
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Fatal error in run_rss_automator: {e}", exc_info=True)
|
logging.error(f"Fatal error in run_rss_automator: {e}", exc_info=True)
|
||||||
|
print(f"Fatal error: {e}")
|
||||||
return None, None, False
|
return None, None, False
|
||||||
finally:
|
finally:
|
||||||
if lock_fd:
|
if lock_fd:
|
||||||
@@ -400,7 +415,4 @@ def run_rss_automator():
|
|||||||
os.remove(LOCK_FILE) if os.path.exists(LOCK_FILE) else None
|
os.remove(LOCK_FILE) if os.path.exists(LOCK_FILE) else None
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
setup_logging()
|
run_rss_automator()
|
||||||
post_data, category, should_continue = run_rss_automator()
|
|
||||||
# Remove sleep timer, let manage_scripts.sh control execution
|
|
||||||
logging.info(f"Run completed, should_continue: {should_continue}")
|
|
||||||
+13
-13
@@ -448,25 +448,24 @@ def upload_image_to_wp(image_url, post_title, wp_base_url, wp_username, wp_passw
|
|||||||
}
|
}
|
||||||
logging.info(f"Fetching image from {image_url} for '{post_title}'")
|
logging.info(f"Fetching image from {image_url} for '{post_title}'")
|
||||||
|
|
||||||
for attempt in range(3):
|
for attempt in range(MAX_RETRIES):
|
||||||
try:
|
try:
|
||||||
image_response = requests.get(image_url, headers=image_headers, timeout=10)
|
image_response = requests.get(image_url, headers=image_headers, timeout=IMAGE_UPLOAD_TIMEOUT)
|
||||||
if image_response.status_code == 429:
|
if image_response.status_code == 429:
|
||||||
wait_time = 10 * (2 ** attempt)
|
wait_time = RETRY_BACKOFF * (2 ** attempt)
|
||||||
logging.warning(f"Rate limit hit for {image_url}. Retrying after {wait_time}s (attempt {attempt+1}/3).")
|
logging.warning(f"Rate limit hit for {image_url}. Retrying after {wait_time}s (attempt {attempt+1}/{MAX_RETRIES}).")
|
||||||
time.sleep(wait_time)
|
time.sleep(wait_time)
|
||||||
continue
|
continue
|
||||||
image_response.raise_for_status()
|
image_response.raise_for_status()
|
||||||
break
|
break
|
||||||
except requests.exceptions.HTTPError as e:
|
except requests.exceptions.RequestException as e:
|
||||||
if e.response.status_code == 429:
|
logging.warning(f"Image fetch failed for {image_url} (attempt {attempt+1}/{MAX_RETRIES}): {e}")
|
||||||
wait_time = 10 * (2 ** attempt)
|
if attempt == MAX_RETRIES - 1:
|
||||||
logging.warning(f"Rate limit hit for {image_url}. Retrying after {wait_time}s (attempt {attempt+1}/3).")
|
logging.error(f"Failed to fetch image {image_url} after {MAX_RETRIES} attempts")
|
||||||
time.sleep(wait_time)
|
return None
|
||||||
continue
|
time.sleep(RETRY_BACKOFF * (2 ** attempt))
|
||||||
raise
|
|
||||||
else:
|
else:
|
||||||
logging.warning(f"Rate limit hit for {image_url} after retries. Failing image upload.")
|
logging.error(f"Failed to fetch image {image_url} after retries")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
@@ -492,7 +491,8 @@ def upload_image_to_wp(image_url, post_title, wp_base_url, wp_username, wp_passw
|
|||||||
logging.info(f"Uploaded image '{safe_title}.jpg' to WP (ID: {image_id}) with caption '{caption}'")
|
logging.info(f"Uploaded image '{safe_title}.jpg' to WP (ID: {image_id}) with caption '{caption}'")
|
||||||
return image_id
|
return image_id
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Image upload to WP failed for '{post_title}': {e}")
|
logging.error(f"Image upload to WP failed for '{post_title}': {e}", exc_info=True)
|
||||||
|
print(f"Image upload to WP failed for '{post_title}': {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def determine_paragraph_count(interest_score):
|
def determine_paragraph_count(interest_score):
|
||||||
|
|||||||
Reference in New Issue
Block a user