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.
|
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
|
### Docker
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,13 @@ from __future__ import annotations
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
import web_app
|
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():
|
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",
|
"api_key": "env-key",
|
||||||
"model": "env-model",
|
"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:
|
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:
|
if not uploaded_file:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
source_path = Path(uploaded_file)
|
source_path = Path(uploaded_file)
|
||||||
if source_path.suffix.lower() != ".mp4":
|
suffix = source_path.suffix.lower()
|
||||||
raise ValueError("Only MP4 uploads are supported.")
|
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():
|
if not source_path.exists():
|
||||||
raise FileNotFoundError(f"Uploaded file not found: {source_path}")
|
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)
|
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)
|
UPLOAD_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
staged_path = UPLOAD_DIR / staged_name
|
staged_path = UPLOAD_DIR / staged_name
|
||||||
shutil.copy2(source_path, staged_path)
|
shutil.copy2(source_path, staged_path)
|
||||||
@@ -267,7 +285,7 @@ def _start_job(
|
|||||||
whisper_model: str,
|
whisper_model: str,
|
||||||
mix_mode: str,
|
mix_mode: str,
|
||||||
browser: str,
|
browser: str,
|
||||||
cookies: str,
|
cookies_upload: str | None,
|
||||||
lmstudio_base_url: str,
|
lmstudio_base_url: str,
|
||||||
lmstudio_api_key: str,
|
lmstudio_api_key: str,
|
||||||
lmstudio_model: str,
|
lmstudio_model: str,
|
||||||
@@ -282,6 +300,11 @@ def _start_job(
|
|||||||
except (OSError, ValueError) as exc:
|
except (OSError, ValueError) as exc:
|
||||||
message = str(exc) or "Invalid uploaded MP4."
|
message = str(exc) or "Invalid uploaded MP4."
|
||||||
return "", message, message, gr.update(choices=_output_choices())
|
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 = {
|
form = {
|
||||||
"url": url,
|
"url": url,
|
||||||
@@ -382,7 +405,11 @@ def create_app() -> gr.Blocks:
|
|||||||
choices=["", "chrome", "edge", "firefox", "brave"],
|
choices=["", "chrome", "edge", "firefox", "brave"],
|
||||||
value="",
|
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):
|
with gr.Accordion("OpenAI-Compatible Settings", open=False):
|
||||||
lmstudio_base_url = gr.Textbox(
|
lmstudio_base_url = gr.Textbox(
|
||||||
@@ -432,7 +459,7 @@ def create_app() -> gr.Blocks:
|
|||||||
whisper_model,
|
whisper_model,
|
||||||
mix_mode,
|
mix_mode,
|
||||||
browser,
|
browser,
|
||||||
cookies,
|
cookies_upload,
|
||||||
lmstudio_base_url,
|
lmstudio_base_url,
|
||||||
lmstudio_api_key,
|
lmstudio_api_key,
|
||||||
lmstudio_model,
|
lmstudio_model,
|
||||||
|
|||||||
Reference in New Issue
Block a user