Files
kino-app/backend/backfill_transcode.py
T
root b28a49e8fa Codec-aware transcode routing, two-stage queue, request candidate picker, admin reorg
- Requests approval now shows a Radarr/Sonarr candidate picker instead of grabbing the first search result (fixes wrong-title/wrong-year matches)
- approve_request reuses an existing Radarr/Sonarr entry instead of erroring when content is already in the library
- New codec-check queue (step 1) probes source codecs and skips transcoding entirely for already browser-native files; only non-native content reaches the transcode queue (step 2)
- Fixes ffmpeg hard-failing on non-H.264 sources via the h264_mp4toannexb bitstream filter (root cause of the fix-audio-all failures)
- Added Codec Check Worker / Transcode Worker to the services health panel with restart
- Reorganized the admin page into Pipeline/Utilities dropdowns; added the missing Sonarr Import link
- Bumped VERSION 1.0.0 -> 1.1.0
2026-07-30 20:41:11 -05:00

54 lines
2.2 KiB
Python

import asyncio
import os
import uuid
from datetime import datetime, timezone
from pathlib import Path
from motor.motor_asyncio import AsyncIOMotorClient
from transcode import classify_source
async def main():
client = AsyncIOMotorClient(os.environ["MONGO_URL"])
db = client[os.environ.get("DB_NAME", "kino")]
videos_dir = Path(os.environ.get("MEDIA_ROOT", "/media")) / "videos"
cancel_res = await db.transcode_queue.update_many(
{"status": "pending"},
{"$set": {"status": "cancelled", "finished_at": datetime.now(timezone.utc).isoformat()}},
)
print(f"cancelled stale pending jobs: {cancel_res.modified_count}")
stats = {"native": 0, "audio": 0, "abr": 0, "no_source": 0}
for coll_name, content_type in (("movies", "movie"), ("episodes", "episode")):
coll = db[coll_name]
async for doc in coll.find({"hls_status": {"$ne": "done"}}, {"_id": 0}):
storage_type = doc.get("storage_type")
storage_path = doc.get("storage_path")
if storage_type not in ("local", "radarr", "sonarr", "scan") or not storage_path:
stats["no_source"] += 1
continue
source = Path(storage_path) if storage_type in ("radarr", "sonarr", "scan") else videos_dir / storage_path
classification = await classify_source(source)
if classification == "native":
await coll.update_one({"id": doc["id"]}, {"$set": {"hls_status": "not_needed"}})
stats["native"] += 1
continue
quality = "abr" if classification == "abr" else "audio"
stats[quality] += 1
job = {
"id": str(uuid.uuid4()), "movie_id": doc["id"], "movie_title": doc.get("title", ""),
"content_type": content_type, "quality": quality, "status": "pending", "error": "",
"triggered_by": "backfill", "progress": 0.0, "superseded_by": None,
"created_at": datetime.now(timezone.utc).isoformat(), "started_at": None, "finished_at": None,
}
await db.transcode_queue.insert_one(job)
await coll.update_one({"id": doc["id"]}, {"$set": {"hls_status": "pending"}})
print(stats)
asyncio.run(main())