Add download preview flow and search fallback
Some checks failed
build-push / docker (push) Has been cancelled
Some checks failed
build-push / docker (push) Has been cancelled
This commit is contained in:
@@ -5,6 +5,7 @@ import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from typing import List
|
||||
|
||||
|
||||
def emit(status, progress, message="", output=""):
|
||||
@@ -25,14 +26,74 @@ def run(cmd):
|
||||
return proc
|
||||
|
||||
|
||||
def parse_duration(value):
|
||||
if value is None:
|
||||
return "00:00:10"
|
||||
total = int(float(value))
|
||||
hours = total // 3600
|
||||
minutes = (total % 3600) // 60
|
||||
seconds = total % 60
|
||||
return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
|
||||
|
||||
|
||||
def format_label(height, ext):
|
||||
if height:
|
||||
return f"{height}p ({ext})"
|
||||
return f"Best ({ext})"
|
||||
|
||||
|
||||
def build_quality_options(formats: List[dict]):
|
||||
heights = []
|
||||
for item in formats:
|
||||
height = item.get("height")
|
||||
if isinstance(height, int) and height > 0:
|
||||
heights.append(height)
|
||||
|
||||
unique_heights = sorted(set(heights))
|
||||
options = [{"value": "best", "label": "Best available"}]
|
||||
for height in unique_heights:
|
||||
options.append(
|
||||
{
|
||||
"value": f"bestvideo[height<={height}]+bestaudio/best[height<={height}]",
|
||||
"label": f"Up to {height}p",
|
||||
}
|
||||
)
|
||||
return options
|
||||
|
||||
|
||||
def probe(url):
|
||||
cmd = ["yt-dlp", "--dump-single-json", "--no-playlist", url]
|
||||
proc = run(cmd)
|
||||
payload = json.loads(proc.stdout)
|
||||
thumbnail = payload.get("thumbnail") or ""
|
||||
duration = payload.get("duration")
|
||||
formats = payload.get("formats") or []
|
||||
preview = {
|
||||
"title": payload.get("title") or "Untitled",
|
||||
"thumbnail": thumbnail,
|
||||
"durationSeconds": duration or 0,
|
||||
"duration": parse_duration(duration),
|
||||
"startDefault": "00:00:00",
|
||||
"endDefault": parse_duration(duration),
|
||||
"qualities": build_quality_options(formats),
|
||||
}
|
||||
print(json.dumps(preview), flush=True)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--mode", choices=["probe", "download"], default="download")
|
||||
parser.add_argument("--url", required=True)
|
||||
parser.add_argument("--start", default="00:00:00")
|
||||
parser.add_argument("--end", default="00:00:10")
|
||||
parser.add_argument("--output", required=True)
|
||||
parser.add_argument("--quality", default="best")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.mode == "probe":
|
||||
probe(args.url)
|
||||
return
|
||||
|
||||
os.makedirs(os.path.dirname(args.output), exist_ok=True)
|
||||
emit("starting", 5, "Resolving media stream")
|
||||
|
||||
@@ -42,7 +103,7 @@ def main():
|
||||
"yt-dlp",
|
||||
"--no-playlist",
|
||||
"-f",
|
||||
"mp4/bestvideo*+bestaudio/best",
|
||||
args.quality,
|
||||
"-o",
|
||||
source_path,
|
||||
args.url,
|
||||
|
||||
Reference in New Issue
Block a user