Spaces:
Sleeping
Sleeping
Update streamlit_app.py
Browse files- streamlit_app.py +47 -30
streamlit_app.py
CHANGED
|
@@ -108,60 +108,77 @@ def _download_direct(url: str, dst: Path) -> Path:
|
|
| 108 |
|
| 109 |
|
| 110 |
def _download_with_yt_dlp(url: str, dst: Path, password: str = "") -> Path:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
tmpl = str(dst / "%(id)s.%(ext)s")
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
opts = {
|
| 115 |
"outtmpl": tmpl,
|
| 116 |
-
"format":
|
| 117 |
"quiet": True,
|
| 118 |
"noprogress": True,
|
| 119 |
"nocheckcertificate": True,
|
| 120 |
"merge_output_format": "mp4",
|
| 121 |
-
"fragment_retries": 0,
|
| 122 |
"force_ipv4": True,
|
| 123 |
"retries": 3,
|
| 124 |
"socket_timeout": 30,
|
|
|
|
| 125 |
}
|
| 126 |
if password:
|
| 127 |
-
|
| 128 |
|
| 129 |
-
|
| 130 |
-
|
| 131 |
|
| 132 |
-
def
|
| 133 |
if d["status"] == "downloading":
|
| 134 |
total = d.get("total_bytes") or d.get("total_bytes_estimate")
|
| 135 |
-
|
| 136 |
if total:
|
| 137 |
-
pct =
|
| 138 |
-
|
| 139 |
-
|
| 140 |
elif d["status"] == "finished":
|
| 141 |
-
|
| 142 |
-
|
| 143 |
|
| 144 |
-
|
| 145 |
|
|
|
|
| 146 |
try:
|
| 147 |
-
with yt_dlp.YoutubeDL(
|
| 148 |
ydl.extract_info(url, download=True)
|
| 149 |
finally:
|
| 150 |
-
|
| 151 |
-
|
| 152 |
|
| 153 |
mp4_files = list(dst.glob("*.mp4"))
|
| 154 |
-
if
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 165 |
|
| 166 |
|
| 167 |
def download_video(url: str, dst: Path, password: str = "") -> Path:
|
|
|
|
| 108 |
|
| 109 |
|
| 110 |
def _download_with_yt_dlp(url: str, dst: Path, password: str = "") -> Path:
|
| 111 |
+
"""
|
| 112 |
+
Download a video.
|
| 113 |
+
1️⃣ Try yt_dlp with MP4‑first format.
|
| 114 |
+
2️⃣ If yt_dlp returns no MP4, fall back to a direct HTTP GET.
|
| 115 |
+
Returns the final MP4 Path.
|
| 116 |
+
"""
|
| 117 |
+
# ---------- yt_dlp options ----------
|
| 118 |
tmpl = str(dst / "%(id)s.%(ext)s")
|
| 119 |
+
ydl_opts = {
|
|
|
|
|
|
|
| 120 |
"outtmpl": tmpl,
|
| 121 |
+
"format": "best[ext=mp4]/best", # prefer MP4
|
| 122 |
"quiet": True,
|
| 123 |
"noprogress": True,
|
| 124 |
"nocheckcertificate": True,
|
| 125 |
"merge_output_format": "mp4",
|
|
|
|
| 126 |
"force_ipv4": True,
|
| 127 |
"retries": 3,
|
| 128 |
"socket_timeout": 30,
|
| 129 |
+
"no_playlist": True,
|
| 130 |
}
|
| 131 |
if password:
|
| 132 |
+
ydl_opts["videopassword"] = password
|
| 133 |
|
| 134 |
+
# ---------- Streamlit progress UI ----------
|
| 135 |
+
bar, txt = st.empty(), st.empty()
|
| 136 |
|
| 137 |
+
def _hook(d):
|
| 138 |
if d["status"] == "downloading":
|
| 139 |
total = d.get("total_bytes") or d.get("total_bytes_estimate")
|
| 140 |
+
done = d.get("downloaded_bytes", 0)
|
| 141 |
if total:
|
| 142 |
+
pct = done / total
|
| 143 |
+
bar.progress(pct)
|
| 144 |
+
txt.caption(f"Downloading… {pct:.0%}")
|
| 145 |
elif d["status"] == "finished":
|
| 146 |
+
bar.progress(1.0)
|
| 147 |
+
txt.caption("Download complete, processing…")
|
| 148 |
|
| 149 |
+
ydl_opts["progress_hooks"] = [_hook]
|
| 150 |
|
| 151 |
+
# ---------- Attempt yt_dlp ----------
|
| 152 |
try:
|
| 153 |
+
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
| 154 |
ydl.extract_info(url, download=True)
|
| 155 |
finally:
|
| 156 |
+
bar.empty()
|
| 157 |
+
txt.empty()
|
| 158 |
|
| 159 |
mp4_files = list(dst.glob("*.mp4"))
|
| 160 |
+
if mp4_files: # yt_dlp succeeded
|
| 161 |
+
newest = max(mp4_files, key=lambda p: p.stat().st_mtime)
|
| 162 |
+
return newest
|
| 163 |
+
|
| 164 |
+
# ---------- Fallback: direct HTTP download ----------
|
| 165 |
+
try:
|
| 166 |
+
r = requests.get(url, stream=True, timeout=30)
|
| 167 |
+
r.raise_for_status()
|
| 168 |
+
fname = Path(url).name or f"download_{int(time.time())}.mp4"
|
| 169 |
+
out = dst / fname
|
| 170 |
+
with out.open("wb") as f:
|
| 171 |
+
for chunk in r.iter_content(chunk_size=8192):
|
| 172 |
+
if chunk:
|
| 173 |
+
f.write(chunk)
|
| 174 |
+
# Ensure MP4 extension
|
| 175 |
+
if out.suffix.lower() != ".mp4":
|
| 176 |
+
out = _convert_to_mp4(out)
|
| 177 |
+
return out
|
| 178 |
+
except Exception as e:
|
| 179 |
+
raise RuntimeError(
|
| 180 |
+
f"Unable to download video – yt_dlp and direct download both failed: {e}"
|
| 181 |
+
)
|
| 182 |
|
| 183 |
|
| 184 |
def download_video(url: str, dst: Path, password: str = "") -> Path:
|