Fix cookie fallback breaking yt-dlp in Docker; add OAuth2 auth flow
- _cookie_args() no longer falls through to --cookies-from-browser when cookies_file is configured but missing. Firefox isn't installed in the Docker image, so that fallback caused yt-dlp to exit with empty stdout and every metadata fetch to return "Video not found on YouTube". - fetch_video_metadata() now retries without auth args if the first call fails, so a broken cookie config can't block public video fetches. - Add use_oauth2 setting + full device-auth flow (POST /settings/oauth2-init, GET /settings/oauth2-status) with OAuth2Section UI in Settings page. - Add GET /settings/ytdlp-test diagnostics endpoint. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,7 @@ class SettingsOut(BaseModel):
|
||||
feed_weight_recency: float = 5.0
|
||||
feed_weight_affinity: float = 5.0
|
||||
feed_weight_channel: float = 5.0
|
||||
use_oauth2: bool = False
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
@@ -53,6 +54,7 @@ class SettingsPatch(BaseModel):
|
||||
feed_weight_recency: Optional[float] = Field(None, ge=0.0, le=10.0)
|
||||
feed_weight_affinity: Optional[float] = Field(None, ge=0.0, le=10.0)
|
||||
feed_weight_channel: Optional[float] = Field(None, ge=0.0, le=10.0)
|
||||
use_oauth2: Optional[bool] = None
|
||||
|
||||
|
||||
def _get_or_create(db: Session, user_id: int) -> UserSettings:
|
||||
@@ -118,6 +120,9 @@ def update_settings(
|
||||
s.feed_weight_affinity = body.feed_weight_affinity
|
||||
if body.feed_weight_channel is not None:
|
||||
s.feed_weight_channel = body.feed_weight_channel
|
||||
if body.use_oauth2 is not None:
|
||||
s.use_oauth2 = body.use_oauth2
|
||||
ytdlp.set_oauth2(body.use_oauth2)
|
||||
|
||||
db.commit()
|
||||
db.refresh(s)
|
||||
@@ -165,3 +170,75 @@ def delete_cookies_file(
|
||||
db.commit()
|
||||
db.refresh(s)
|
||||
return s
|
||||
|
||||
|
||||
@router.post("/oauth2-init")
|
||||
def oauth2_init(
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
"""Start a yt-dlp OAuth2 device-auth flow. Returns the device URL and code immediately."""
|
||||
state = ytdlp.start_oauth2_flow()
|
||||
return state
|
||||
|
||||
|
||||
@router.get("/oauth2-status")
|
||||
def oauth2_status(
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
"""Poll the current OAuth2 flow status."""
|
||||
return ytdlp.get_oauth2_status()
|
||||
|
||||
|
||||
@router.post("/oauth2-enable", response_model=SettingsOut)
|
||||
def oauth2_enable(
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
"""Mark OAuth2 as the active auth method after a successful flow."""
|
||||
s = _get_or_create(db, current_user.id)
|
||||
s.use_oauth2 = True
|
||||
ytdlp.set_oauth2(True)
|
||||
db.commit()
|
||||
db.refresh(s)
|
||||
return s
|
||||
|
||||
|
||||
@router.post("/oauth2-disable", response_model=SettingsOut)
|
||||
def oauth2_disable(
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
"""Disable OAuth2 auth, falling back to cookies."""
|
||||
s = _get_or_create(db, current_user.id)
|
||||
s.use_oauth2 = False
|
||||
ytdlp.set_oauth2(False)
|
||||
db.commit()
|
||||
db.refresh(s)
|
||||
return s
|
||||
|
||||
|
||||
@router.get("/ytdlp-test")
|
||||
def ytdlp_test(
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
"""Run a quick yt-dlp metadata fetch on a public video and return raw output for diagnostics."""
|
||||
import subprocess
|
||||
cookie_args = ytdlp._cookie_args()
|
||||
result = subprocess.run(
|
||||
[
|
||||
"yt-dlp",
|
||||
"https://www.youtube.com/watch?v=dQw4w9WgXcQ",
|
||||
"--dump-json", "--no-download", "--no-playlist",
|
||||
"--extractor-args", "youtube:player_client=tv,ios,web",
|
||||
*cookie_args,
|
||||
],
|
||||
capture_output=True, text=True, timeout=30,
|
||||
)
|
||||
return {
|
||||
"returncode": result.returncode,
|
||||
"cookie_args": cookie_args,
|
||||
"stdout_lines": result.stdout.splitlines()[:5],
|
||||
"stderr_tail": result.stderr.splitlines()[-20:],
|
||||
"success": result.returncode == 0,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user