Add cookie file upload
This commit is contained in:
@@ -78,7 +78,7 @@ Open `http://127.0.0.1:7860` and submit a YouTube URL. Jobs run through the same
|
||||
|
||||
The OpenAI-compatible translation endpoint, API key, and model can be changed in the UI under **OpenAI-Compatible Settings**. Click **Save Settings** to persist them to `.cache/web_settings.json` for future web jobs. Unsaved values in the fields are still used for the next job you start.
|
||||
|
||||
You can also upload a local `.mp4` instead of entering a YouTube URL. Uploaded videos are staged under `.cache/uploads` and processed with the same transcription, translation, dubbing, and render pipeline.
|
||||
You can also upload a local `.mp4` instead of entering a YouTube URL. Uploaded videos are staged under `.cache/uploads` and processed with the same transcription, translation, dubbing, and render pipeline. Restricted YouTube videos can use the **Upload Cookies File** control instead of typing a local cookies path.
|
||||
|
||||
### Docker
|
||||
|
||||
|
||||
@@ -5,7 +5,13 @@ from __future__ import annotations
|
||||
import sys
|
||||
|
||||
import web_app
|
||||
from web_app import build_pipeline_command, create_app, load_translation_settings, save_translation_settings
|
||||
from web_app import (
|
||||
_stage_uploaded_cookies,
|
||||
build_pipeline_command,
|
||||
create_app,
|
||||
load_translation_settings,
|
||||
save_translation_settings,
|
||||
)
|
||||
|
||||
|
||||
def test_build_pipeline_command_uses_cli_parser_defaults():
|
||||
@@ -91,3 +97,29 @@ def test_load_translation_settings_uses_env_defaults(tmp_path, monkeypatch):
|
||||
"api_key": "env-key",
|
||||
"model": "env-model",
|
||||
}
|
||||
|
||||
|
||||
def test_stage_uploaded_cookies_copies_to_upload_dir(tmp_path, monkeypatch):
|
||||
upload_dir = tmp_path / "uploads"
|
||||
source_file = tmp_path / "cookies.txt"
|
||||
source_file.write_text("# Netscape HTTP Cookie File\n", encoding="utf-8")
|
||||
monkeypatch.setattr(web_app, "UPLOAD_DIR", upload_dir)
|
||||
|
||||
staged_path = _stage_uploaded_cookies(str(source_file))
|
||||
|
||||
assert staged_path.endswith(".txt")
|
||||
assert staged_path != str(source_file)
|
||||
assert upload_dir in web_app.Path(staged_path).parents
|
||||
assert web_app.Path(staged_path).read_text(encoding="utf-8") == "# Netscape HTTP Cookie File\n"
|
||||
|
||||
|
||||
def test_stage_uploaded_cookies_rejects_unsupported_extension(tmp_path):
|
||||
source_file = tmp_path / "cookies.json"
|
||||
source_file.write_text("{}", encoding="utf-8")
|
||||
|
||||
try:
|
||||
_stage_uploaded_cookies(str(source_file))
|
||||
except ValueError as exc:
|
||||
assert "Expected one of" in str(exc)
|
||||
else:
|
||||
raise AssertionError("Expected ValueError for unsupported cookie upload")
|
||||
|
||||
39
web_app.py
39
web_app.py
@@ -179,17 +179,35 @@ def _form_to_cli_args(form: dict[str, str | bool]) -> list[str]:
|
||||
|
||||
|
||||
def _stage_uploaded_mp4(uploaded_file: str | None) -> str:
|
||||
return _stage_uploaded_file(uploaded_file, allowed_suffixes={".mp4"}, fallback_name="upload")
|
||||
|
||||
|
||||
def _stage_uploaded_cookies(uploaded_file: str | None) -> str:
|
||||
return _stage_uploaded_file(
|
||||
uploaded_file,
|
||||
allowed_suffixes={".txt", ".cookies", ".cookie"},
|
||||
fallback_name="cookies",
|
||||
)
|
||||
|
||||
|
||||
def _stage_uploaded_file(
|
||||
uploaded_file: str | None,
|
||||
allowed_suffixes: set[str],
|
||||
fallback_name: str,
|
||||
) -> str:
|
||||
if not uploaded_file:
|
||||
return ""
|
||||
|
||||
source_path = Path(uploaded_file)
|
||||
if source_path.suffix.lower() != ".mp4":
|
||||
raise ValueError("Only MP4 uploads are supported.")
|
||||
suffix = source_path.suffix.lower()
|
||||
if suffix not in allowed_suffixes:
|
||||
expected = ", ".join(sorted(allowed_suffixes))
|
||||
raise ValueError(f"Unsupported upload type. Expected one of: {expected}.")
|
||||
if not source_path.exists():
|
||||
raise FileNotFoundError(f"Uploaded file not found: {source_path}")
|
||||
|
||||
safe_stem = "".join(char if char.isalnum() or char in {"-", "_"} else "_" for char in source_path.stem)
|
||||
staged_name = f"{uuid.uuid4().hex[:12]}_{safe_stem or 'upload'}.mp4"
|
||||
staged_name = f"{uuid.uuid4().hex[:12]}_{safe_stem or fallback_name}{suffix}"
|
||||
UPLOAD_DIR.mkdir(parents=True, exist_ok=True)
|
||||
staged_path = UPLOAD_DIR / staged_name
|
||||
shutil.copy2(source_path, staged_path)
|
||||
@@ -267,7 +285,7 @@ def _start_job(
|
||||
whisper_model: str,
|
||||
mix_mode: str,
|
||||
browser: str,
|
||||
cookies: str,
|
||||
cookies_upload: str | None,
|
||||
lmstudio_base_url: str,
|
||||
lmstudio_api_key: str,
|
||||
lmstudio_model: str,
|
||||
@@ -282,6 +300,11 @@ def _start_job(
|
||||
except (OSError, ValueError) as exc:
|
||||
message = str(exc) or "Invalid uploaded MP4."
|
||||
return "", message, message, gr.update(choices=_output_choices())
|
||||
try:
|
||||
cookies = _stage_uploaded_cookies(cookies_upload)
|
||||
except (OSError, ValueError) as exc:
|
||||
message = str(exc) or "Invalid uploaded cookies file."
|
||||
return "", message, message, gr.update(choices=_output_choices())
|
||||
|
||||
form = {
|
||||
"url": url,
|
||||
@@ -382,7 +405,11 @@ def create_app() -> gr.Blocks:
|
||||
choices=["", "chrome", "edge", "firefox", "brave"],
|
||||
value="",
|
||||
)
|
||||
cookies = gr.Textbox(label="Cookies File", placeholder=r"C:\path\to\cookies.txt")
|
||||
cookies_upload = gr.File(
|
||||
label="Upload Cookies File",
|
||||
file_types=[".txt", ".cookies", ".cookie"],
|
||||
type="filepath",
|
||||
)
|
||||
|
||||
with gr.Accordion("OpenAI-Compatible Settings", open=False):
|
||||
lmstudio_base_url = gr.Textbox(
|
||||
@@ -432,7 +459,7 @@ def create_app() -> gr.Blocks:
|
||||
whisper_model,
|
||||
mix_mode,
|
||||
browser,
|
||||
cookies,
|
||||
cookies_upload,
|
||||
lmstudio_base_url,
|
||||
lmstudio_api_key,
|
||||
lmstudio_model,
|
||||
|
||||
Reference in New Issue
Block a user