124afb6d20
Docker / docker (push) Has been cancelled
Format : Title.Event.Year.FRENCH.Resolution.WEBRip.x264|HEVC.AAC-ReMoRa.mp4 - build_release_name() : slugify avec strip accents, apostrophe→point, déduplique l'année si présente dans le titre ET passée séparément, détecte la résolution et le codec depuis les infos yt-dlp - enqueue() : reçoit subtitle + year depuis l'API - _run() : renomme le fichier après download, met à jour le filename en DB - DownloadRequest : subtitle + year ajoutés - app.js : extrait l'année du subtitle via regex avant d'envoyer la requête Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
84 lines
2.3 KiB
Python
84 lines
2.3 KiB
Python
import asyncio
|
|
import json
|
|
import logging
|
|
|
|
from fastapi import BackgroundTasks, FastAPI, HTTPException, Request
|
|
from fastapi.responses import HTMLResponse, StreamingResponse
|
|
from fastapi.staticfiles import StaticFiles
|
|
from fastapi.templating import Jinja2Templates
|
|
from pydantic import BaseModel
|
|
|
|
from arte_api import fetch_concerts, invalidate_cache, CATEGORIES
|
|
from downloader import DownloadManager
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
app = FastAPI(title="Arte-dl")
|
|
app.mount("/static", StaticFiles(directory="static"), name="static")
|
|
templates = Jinja2Templates(directory="templates")
|
|
|
|
dm = DownloadManager()
|
|
|
|
|
|
# ------------------------------------------------------------------ pages
|
|
|
|
|
|
@app.get("/", response_class=HTMLResponse)
|
|
async def index(request: Request):
|
|
return templates.TemplateResponse("index.html", {"request": request})
|
|
|
|
|
|
# ------------------------------------------------------------------ API: concerts
|
|
|
|
|
|
@app.get("/api/categories")
|
|
async def api_categories():
|
|
return CATEGORIES
|
|
|
|
|
|
@app.get("/api/concerts")
|
|
async def api_concerts(page: int = 1, search: str = "", page_size: int = 24, category: str = ""):
|
|
return await fetch_concerts(page=page, search=search, page_size=page_size, category=category)
|
|
|
|
|
|
@app.post("/api/refresh")
|
|
async def api_refresh():
|
|
count = await invalidate_cache()
|
|
return {"count": count}
|
|
|
|
|
|
# ------------------------------------------------------------------ API: downloads
|
|
|
|
|
|
class DownloadRequest(BaseModel):
|
|
url: str
|
|
title: str
|
|
subtitle: str = ""
|
|
year: int | None = None
|
|
|
|
|
|
@app.post("/api/download")
|
|
async def api_download(req: DownloadRequest, bg: BackgroundTasks):
|
|
if not req.url:
|
|
raise HTTPException(status_code=400, detail="url required")
|
|
dl_id = dm.enqueue(req.url, req.title, req.subtitle, req.year, bg)
|
|
return {"id": dl_id}
|
|
|
|
|
|
@app.get("/api/downloads")
|
|
async def api_downloads():
|
|
return dm.history()
|
|
|
|
|
|
@app.get("/api/progress/{dl_id}")
|
|
async def api_progress(dl_id: str):
|
|
async def stream():
|
|
while True:
|
|
s = dm.status(dl_id)
|
|
yield f"data: {json.dumps(s)}\n\n"
|
|
if s.get("state") in ("done", "error", "unknown"):
|
|
break
|
|
await asyncio.sleep(0.8)
|
|
|
|
return StreamingResponse(stream(), media_type="text/event-stream")
|