This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

Revert "first working version"

This reverts commit 7a31defc0e955a063738e52e4180bb4ba8a775c1.

+23 -141
+23 -141
src/main.py
··· 3 3 import sys 4 4 import subprocess 5 5 import logging 6 - import json 7 - import requests 8 - import magic 9 6 from datetime import datetime 10 7 from dotenv import load_dotenv 11 8 from logging.handlers import RotatingFileHandler 12 9 from atproto import Client, models 13 10 from atproto.exceptions import BadRequestError 14 11 15 - # Ensure the script is run inside a virtual environment 16 - if not hasattr(sys, 'real_prefix') and not (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix): 17 - print("Error: This script must be run inside a virtual environment.") 18 - sys.exit(1) 19 - else: 20 - print("Virtual environment detected.") 21 - 22 - # Define paths 23 - BASE_DIR = os.path.abspath(os.path.dirname(__file__)) # /src/ 24 - REQ_PATH = os.path.abspath(os.path.join(BASE_DIR, "../requirements.txt")) # /requirements.txt 12 + # Define the paths 13 + BASE_DIR = os.path.abspath(os.path.dirname(__file__)) 25 14 ASSETS_DIR = os.path.join(BASE_DIR, "../assets") 26 15 ENV_PATH = os.path.join(ASSETS_DIR, ".env") 27 16 JSON_PATH = os.path.join(ASSETS_DIR, "cids.json") ··· 39 28 40 29 console_handler = logging.StreamHandler() 41 30 console_handler.setLevel(logging.INFO) 42 - console_handler.setFormatter(log_formatter) 43 - 44 - logging.basicConfig(level=logging.DEBUG, handlers=[log_handler, console_handler]) 45 - logging.info("Starting script with log rotation enabled.") 46 - 47 - def install_and_rerun(): 48 - """Install missing packages from requirements.txt and re-run the script.""" 49 - if os.path.exists(REQ_PATH): 50 - logging.info(f"Installing missing packages from {REQ_PATH}...") 51 - try: 52 - subprocess.check_call([sys.executable, "-m", "pip", "install", "-r", REQ_PATH]) 53 - logging.info("Packages installed successfully. Restarting script...") 54 - os.execv(sys.executable, [sys.executable] + sys.argv) 55 - except subprocess.CalledProcessError as e: 56 - logging.error(f"Failed to install packages: {e}") 57 - sys.exit(1) 58 - else: 59 - logging.error(f"requirements.txt not found at {REQ_PATH}, cannot install missing packages.") 60 - sys.exit(1) 61 - 62 - # Check for required packages and install if missing 63 - try: 64 - import requests 65 - import magic 66 - from atproto import Client, models 67 - from atproto.exceptions import BadRequestError 68 - from dotenv import load_dotenv 69 - except ImportError as e: 70 - logging.error(f"Missing package(s): {e}") 71 - install_and_rerun() 72 - 73 - def ensure_https(url): 74 - """Ensure the URL starts with https://""" 75 - if not url.startswith("http://") and not url.startswith("https://"): 76 - return "https://" + url 77 - if url.startswith("http://"): 78 - return "https://" + url[7:] 79 - return url 80 - 81 - def is_endpoint_alive(url): 82 - """Check if the endpoint is alive by making a health check request.""" 83 - health_url = f"{url.rstrip('/')}/xrpc/_health" 84 - logging.info(f"Checking endpoint health: {health_url}") 85 - try: 86 - response = requests.get(health_url, timeout=5) 87 - if response.status_code == 200: 88 - logging.info("Endpoint is alive.") 89 - return True 90 - else: 91 - logging.warning(f"Endpoint returned status code {response.status_code}") 92 - return False 93 - except requests.RequestException as e: 94 - logging.error(f"Health check failed for {health_url}: {e}") 95 - return False 96 - 97 - def fetch_blob(did, cid, endpoint): 98 - """Fetch blob data from the given endpoint.""" 99 - url = f"{endpoint}/xrpc/com.atproto.sync.getBlob?did={did}&cid={cid}" 100 - logging.info(f"Fetching blob: {url}") 101 - try: 102 - response = requests.get(url, timeout=5) 103 - response.raise_for_status() 104 - logging.info(f"Successfully fetched blob {cid} for DID {did}.") 105 - return response.content 106 - except requests.RequestException as e: 107 - logging.error(f"Failed to fetch blob {cid} for DID {did}: {e}") 108 - return None 109 - 110 - def get_blob_metadata(cid, did, endpoint): 111 - """Retrieve metadata for a given blob CID.""" 112 - blob_data = fetch_blob(did, cid, endpoint) 113 - if blob_data is None: 114 - logging.error("Blob data is empty.") 115 - return None 116 - 117 - mime = magic.Magic(mime=True) 118 - mime_type = mime.from_buffer(blob_data) 119 - size = len(blob_data) 120 - 121 - logging.info(f"Retrieved metadata - MIME Type: {mime_type}, Size: {size} bytes") 122 - 123 - return { 124 - "$type": "blob", 125 - "ref": {"$link": cid}, 126 - "mimeType": mime_type, 127 - "size": size, 128 - } 129 - 130 - def setup_cron_job(): 131 - """Set up a cron job to run the script hourly.""" 132 - cron_job_command = f"0 * * * * {sys.executable} {os.path.abspath(__file__)} >> {LOG_PATH} 2>&1" 133 - logging.info("Setting up cron job...") 134 - 135 - try: 136 - result = subprocess.run(["crontab", "-l"], capture_output=True, text=True) 137 - cron_jobs = result.stdout.strip() if result.returncode == 0 else "" 138 - 139 - if cron_job_command in cron_jobs: 140 - logging.info("Cron job is already set.") 141 - return 142 - 143 - new_cron_jobs = cron_jobs + "\n" + cron_job_command if cron_jobs else cron_job_command 144 - subprocess.run(["crontab"], input=new_cron_jobs, text=True, check=True) 145 - logging.info("Cron job added successfully.") 146 - except Exception as e: 147 - logging.error(f"Failed to set up cron job: {e}") 31 + formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") 32 + console_handler.setFormatter(formatter) 33 + logging.getLogger().addHandler(console_handler) 148 34 149 35 def main(): 150 36 logging.info("Starting avatar update script...") ··· 158 44 endpoint = os.getenv("ENDPOINT") 159 45 handle = os.getenv("HANDLE") 160 46 password = os.getenv("PASSWORD") 161 - did = os.getenv("DID") 162 - 163 - if not (endpoint and handle and password and did): 164 - logging.error("Missing environment variables. Check .env file.") 165 - return 166 47 167 - endpoint = ensure_https(endpoint) 168 - if not is_endpoint_alive(endpoint): 169 - logging.error(f"Endpoint {endpoint} is not responding.") 48 + if not (endpoint and handle and password): 49 + logging.error("Missing environment variables. Ensure ENDPOINT, HANDLE, and PASSWORD are set in .env file.") 170 50 return 171 51 172 52 if not os.path.exists(JSON_PATH) or os.path.getsize(JSON_PATH) == 0: ··· 192 72 client = Client(endpoint) 193 73 194 74 try: 195 - client.login(handle, password) 196 - logging.info("Authentication successful.") 75 + profile = client.login(handle, password) 76 + logging.info(f"Authentication successful. Welcome, {profile.display_name}") 77 + did = profile.did 78 + logging.info(f"User DID: {did}") 197 79 except Exception as e: 198 80 logging.error(f"Authentication failed: {e}") 199 81 return 200 82 201 - blob_metadata = get_blob_metadata(new_blob_cid, did, endpoint) 202 - if blob_metadata is None: 203 - logging.error("Blob metadata retrieval failed.") 204 - return 83 + updated_profile_data = { 84 + "$type": "app.bsky.actor.profile", 85 + "avatar": { 86 + "cid": new_blob_cid 87 + } 88 + } 89 + 90 + logging.debug(f"Updated profile data: {updated_profile_data}") 205 91 206 92 try: 207 93 client.com.atproto.repo.put_record( 208 - models.ComAtprotoRepoPutRecord.Data( 209 - collection=models.ids.AppBskyActorProfile, 210 - repo=client.me.did, 211 - rkey="self", 212 - record=models.AppBskyActorProfile.Record( 213 - avatar=blob_metadata, 214 - ), 215 - ) 94 + repo=did, 95 + collection="app.bsky.actor.profile", 96 + rkey="self", 97 + record=updated_profile_data 216 98 ) 217 99 logging.info("Avatar updated successfully!") 218 100 except Exception as e: