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)