diff --git a/main.py b/main.py index 2e26fcd..8008814 100755 --- a/main.py +++ b/main.py @@ -12,6 +12,7 @@ import pickle import re import sqlite3 import time +import urllib.parse from google.auth.transport.requests import Request from google_auth_oauthlib.flow import InstalledAppFlow @@ -184,14 +185,16 @@ def add_video_to_playlist(youtube, playlist_id, video_id, retry_count=6): def parse_iso8601_duration(duration_str): """Parse ISO 8601 duration string into seconds.""" - pattern = re.compile(r'PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?') + pattern = re.compile(r'^P(?:(\d+)W)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?$') match = pattern.match(duration_str) if not match: return 0 - hours = int(match.group(1)) if match.group(1) else 0 - minutes = int(match.group(2)) if match.group(2) else 0 - seconds = int(match.group(3)) if match.group(3) else 0 - return hours * 3600 + minutes * 60 + seconds + weeks = int(match.group(1)) if match.group(1) else 0 + days = int(match.group(2)) if match.group(2) else 0 + hours = int(match.group(3)) if match.group(3) else 0 + minutes = int(match.group(4)) if match.group(4) else 0 + seconds = int(match.group(5)) if match.group(5) else 0 + return weeks * 604800 + days * 86400 + hours * 3600 + minutes * 60 + seconds def get_video_info(youtube, video_id): @@ -347,10 +350,13 @@ async def message_callback(conn, cursor, youtube, client, room, event): "msgtype": "m.text", "body": warning_text, "format": "org.matrix.custom.html", - "formatted_body": f"{html.escape(warning_text)}", + "formatted_body": f"{html.escape(warning_text)}", }, ) + elif not is_music_vid: + print(f"📻 Skipping radio upload for {title} (Not categorized as Music/Entertainment)") + if is_music_vid: message_id = record_message(conn, cursor, sender, link, timestamp) if in_playlist(cursor, video_id, playlist_id): @@ -368,10 +374,13 @@ async def message_callback(conn, cursor, youtube, client, room, event): ) print(f"Added track to this week's playlist: {link}") if recent: - if duration <= 1200: + if 0 < duration <= 1200: asyncio.create_task(process_radio_track(link, video_id, title)) else: - print(f"📻 Skipping radio upload for {title} (duration: {duration}s > 1200s)") + if duration == 0: + print(f"📻 Skipping radio upload for {title} (duration unknown or live stream)") + else: + print(f"📻 Skipping radio upload for {title} (duration: {duration}s > 1200s)") def in_playlist(cursor, video_id, playlist_id): @@ -500,17 +509,16 @@ async def process_radio_track(video_link, video_id, title): print(f"📻 Uploading to AzuraCast: {title}") + encoded_path = urllib.parse.quote(filename) upload_cmd = [ "curl", "-s", "-X", "POST", - f"{base_url}/api/station/{AZURACAST_STATION_ID}/files/upload", + f"{base_url}/api/station/{AZURACAST_STATION_ID}/files/upload?path={encoded_path}", "-H", f"X-API-Key: {AZURACAST_API_KEY}", "-F", - f"path={filename}", - "-F", f"file=@{filepath}", ] @@ -621,36 +629,50 @@ async def process_radio_track(video_link, video_id, title): # 2. Issue the Play Next Request SECOND # Now that the file is legally in a playlist, AzuraCast will accept the request. - if unique_id: - req_cmd = [ + if target_path: + q_payload = { + "do": "queue", + "files": [target_path], + } + q_json_path = os.path.join(DATA_DIR, f"queue_{filename}.json") + with open(q_json_path, "w") as f: + json.dump(q_payload, f) + + q_batch_cmd = [ "curl", "-s", "-X", - "POST", - f"{base_url}/api/station/{AZURACAST_STATION_ID}/request/{unique_id}", + "PUT", + f"{base_url}/api/station/{AZURACAST_STATION_ID}/files/batch", "-H", f"X-API-Key: {AZURACAST_API_KEY}", + "-H", + "Content-Type: application/json", + "-d", + f"@{q_json_path}", ] - req_proc = await asyncio.create_subprocess_exec( - *req_cmd, + q_proc = await asyncio.create_subprocess_exec( + *q_batch_cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, ) - req_stdout, _ = await req_proc.communicate() + q_stdout, _ = await q_proc.communicate() + + if os.path.exists(q_json_path): + os.remove(q_json_path) try: - req_resp = json.loads(req_stdout.decode()) - # Check the JSON response directly so we don't lie about success - if req_resp.get("success") or req_resp.get("code") == 200: + q_resp = json.loads(q_stdout.decode()) + if q_resp.get("success") or q_resp.get("code") == 200: print(f"✅ Queued on radio to play next: {title}") else: print( - f"⚠️ AzuraCast rejected the request for {title}: {req_stdout.decode()}" + f"⚠️ AzuraCast rejected the queue request for {title}: {q_stdout.decode()}" ) except json.JSONDecodeError: - print(f"⚠️ Failed to queue {title}. API returned: {req_stdout.decode()}") + print(f"⚠️ Failed to queue {title}. API returned: {q_stdout.decode()}") else: - print("⚠️ Uploaded, but no unique_id returned to make the request.") + print("⚠️ Uploaded, but no path returned to make the request.") if os.path.exists(filepath): os.remove(filepath)