Flask + React web UI with audio player, podcast queue, feed management, episode browser, music library, schedule viewer, and log tail. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
64 lines
1.6 KiB
Python
64 lines
1.6 KiB
Python
"""GET /api/episodes — paginated episode browser."""
|
|
|
|
from flask import Blueprint, jsonify, request
|
|
|
|
from ..db import get_db
|
|
|
|
bp = Blueprint("episodes", __name__)
|
|
|
|
|
|
@bp.route("/episodes")
|
|
def list_episodes():
|
|
db = get_db()
|
|
page = request.args.get("page", 1, type=int)
|
|
per_page = request.args.get("per_page", 20, type=int)
|
|
per_page = min(per_page, 100)
|
|
feed = request.args.get("feed")
|
|
status = request.args.get("status")
|
|
|
|
conditions = []
|
|
params = []
|
|
|
|
if feed:
|
|
conditions.append("feed_name = ?")
|
|
params.append(feed)
|
|
|
|
if status == "downloaded":
|
|
conditions.append("downloaded = 1")
|
|
elif status == "queued":
|
|
conditions.append("queued = 1")
|
|
elif status == "played":
|
|
conditions.append("played = 1")
|
|
|
|
where = f"WHERE {' AND '.join(conditions)}" if conditions else ""
|
|
|
|
total = db.execute(
|
|
f"SELECT COUNT(*) as c FROM episodes {where}", params
|
|
).fetchone()["c"]
|
|
|
|
offset = (page - 1) * per_page
|
|
rows = db.execute(
|
|
f"""SELECT * FROM episodes {where}
|
|
ORDER BY discovered DESC
|
|
LIMIT ? OFFSET ?""",
|
|
params + [per_page, offset],
|
|
).fetchall()
|
|
|
|
return jsonify({
|
|
"episodes": [dict(r) for r in rows],
|
|
"total": total,
|
|
"page": page,
|
|
"per_page": per_page,
|
|
"pages": (total + per_page - 1) // per_page,
|
|
})
|
|
|
|
|
|
@bp.route("/episodes/feeds")
|
|
def list_episode_feeds():
|
|
"""Return distinct feed names for filter dropdowns."""
|
|
db = get_db()
|
|
rows = db.execute(
|
|
"SELECT DISTINCT feed_name FROM episodes ORDER BY feed_name"
|
|
).fetchall()
|
|
return jsonify([r["feed_name"] for r in rows])
|