"""Queue management API — GET/POST/DELETE /api/queue.""" import os import re import shutil from datetime import datetime from pathlib import Path from flask import Blueprint, jsonify, request from ..config import QUEUE_DIR, PODCAST_DIR from ..db import get_db bp = Blueprint("queue", __name__) @bp.route("/queue") def list_queue(): db = get_db() rows = db.execute(""" SELECT q.id, q.position, q.enqueued, q.played, e.id as episode_id, e.feed_name, e.title, e.pub_date, e.file_path FROM queue q JOIN episodes e ON e.id = q.episode_id WHERE q.played = 0 ORDER BY q.position """).fetchall() return jsonify([dict(r) for r in rows]) @bp.route("/queue", methods=["POST"]) def enqueue(): data = request.get_json() if not data: return jsonify({"error": "JSON body required"}), 400 episode_id = data.get("episode_id") file_path = data.get("file_path") db = get_db() if episode_id: row = db.execute( "SELECT * FROM episodes WHERE id=? AND downloaded=1", (episode_id,) ).fetchone() if not row: return jsonify({"error": "Episode not found or not downloaded"}), 404 file_path = row["file_path"] elif file_path: if not os.path.exists(file_path): return jsonify({"error": "File not found"}), 404 else: return jsonify({"error": "Provide episode_id or file_path"}), 400 # Create queue entry if episode_id is available if episode_id: existing = db.execute( "SELECT 1 FROM queue WHERE episode_id=? AND played=0", (episode_id,) ).fetchone() if existing: return jsonify({"error": "Episode already in queue"}), 409 next_pos = db.execute( "SELECT COALESCE(MAX(position), 0) + 1 as p FROM queue" ).fetchone()["p"] db.execute( "INSERT INTO queue (episode_id, position) VALUES (?, ?)", (episode_id, next_pos), ) db.execute( "UPDATE episodes SET queued=1, played=0 WHERE id=?", (episode_id,) ) db.commit() # Create symlink in queue directory QUEUE_DIR.mkdir(parents=True, exist_ok=True) timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") src = Path(file_path) eid = episode_id or 0 link_name = f"{timestamp}_{eid:06d}_{src.name}" link_path = QUEUE_DIR / link_name try: link_path.symlink_to(src.resolve()) except (OSError, FileExistsError): try: link_path.hardlink_to(src.resolve()) except (OSError, FileExistsError): shutil.copy2(str(src), str(link_path)) return jsonify({"status": "enqueued", "link": link_name}), 201 @bp.route("/queue/", methods=["DELETE"]) def dequeue(queue_id): db = get_db() row = db.execute( "SELECT q.*, e.id as eid FROM queue q JOIN episodes e ON e.id=q.episode_id WHERE q.id=?", (queue_id,), ).fetchone() if not row: return jsonify({"error": "Queue item not found"}), 404 # Remove symlink from queue directory eid = row["eid"] if QUEUE_DIR.exists(): pattern = re.compile(rf"_0*{eid}_") for item in QUEUE_DIR.iterdir(): if pattern.search(item.name): item.unlink(missing_ok=True) break db.execute("DELETE FROM queue WHERE id=?", (queue_id,)) db.execute("UPDATE episodes SET queued=0 WHERE id=?", (eid,)) db.commit() return jsonify({"status": "removed"})