Make the YouTube account reachable, and applied without a restart
The cookie login was not missing, it was buried: Downloads tab -> Custom Options -> the "Login with Cookies" tab, where Downloads is one tab of five. The three features that depend on it -- the Feed's account mode, Search and Browse -- are other tabs, with no route to it. show_cookie_login_dialog(), which opens that dialog on the right tab, had no caller anywhere in the codebase; it does now. An account button sits in the corner of the tab bar, visible from every tab, saying whether cookies are in use and where they came from. The Feed offers the same thing next to its account mode rather than greying the option out and leaving it at that, and the disabled entry now says why it is disabled. Applying cookies used to require a restart before playback saw them: _build_ytdl_raw_options was read once, when the player widget was built. A cookiesChanged signal now reaches the account button, the Feed and the live mpv handle, and the player reloads at its current position -- ytdl_hook consults the option when it resolves a URL, so anything already playing keeps the streams it resolved with. YtdlpClient needed no change: it re-reads config per call. Two bugs in the same function: the options are joined with commas and were never escaped, so a cookie path or a proxy URL containing one silently ended the option and started a bogus one; and geo_proxy_url was honoured by the downloader but never passed to the player, so a geo-restricted video would download and then refuse to play. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -65,22 +65,38 @@ def _ytdl_format_for(height: Optional[int]) -> str:
|
||||
|
||||
|
||||
def _build_ytdl_raw_options() -> str:
|
||||
"""Mirror the app's cookie/proxy config into ytdl_hook raw options."""
|
||||
"""
|
||||
Mirror the app's cookie/proxy config into ytdl_hook raw options.
|
||||
|
||||
mpv splits this option on commas, so any comma inside a value would end
|
||||
the option and start a bogus one -- silently, and a Windows cookie path or
|
||||
a proxy URL with credentials can easily contain one. mpv's own escape for
|
||||
that is a backslash, so values are escaped rather than trusted.
|
||||
"""
|
||||
|
||||
def esc(value) -> str:
|
||||
return str(value).replace("\\", "\\\\").replace(",", "\\,")
|
||||
|
||||
opts = []
|
||||
if ConfigManager.get("cookie_active"):
|
||||
if ConfigManager.get("cookie_source") == "file":
|
||||
path = ConfigManager.get("cookie_file_path")
|
||||
if path:
|
||||
opts.append(f"cookies={path}")
|
||||
opts.append(f"cookies={esc(path)}")
|
||||
else:
|
||||
browser = ConfigManager.get("cookie_browser")
|
||||
profile = ConfigManager.get("cookie_browser_profile")
|
||||
if browser:
|
||||
value = f"{browser}:{profile}" if profile else browser
|
||||
opts.append(f"cookies-from-browser={value}")
|
||||
opts.append(f"cookies-from-browser={esc(value)}")
|
||||
proxy = ConfigManager.get("proxy_url")
|
||||
if proxy:
|
||||
opts.append(f"proxy={proxy}")
|
||||
opts.append(f"proxy={esc(proxy)}")
|
||||
# The downloader honours geo_proxy_url; the player was ignoring it, so a
|
||||
# geo-restricted video downloaded but would not play.
|
||||
geo_proxy = ConfigManager.get("geo_proxy_url")
|
||||
if geo_proxy:
|
||||
opts.append(f"geo-verification-proxy={esc(geo_proxy)}")
|
||||
return ",".join(opts)
|
||||
|
||||
|
||||
@@ -834,6 +850,32 @@ class PlayerPanel(QWidget):
|
||||
if url:
|
||||
webbrowser.open(str(url))
|
||||
|
||||
def reload_auth(self) -> None:
|
||||
"""
|
||||
Push changed cookie/proxy settings onto the live mpv handle.
|
||||
|
||||
These were read once, when the widget was built, so signing in only
|
||||
reached playback after restarting the app. ytdl_hook consults the
|
||||
option when it resolves a URL, so anything already playing keeps the
|
||||
streams it resolved with -- it is reloaded at its current position.
|
||||
"""
|
||||
mpv_inst = self.video.mpv
|
||||
if mpv_inst is None:
|
||||
return
|
||||
raw_opts = _build_ytdl_raw_options()
|
||||
try:
|
||||
mpv_inst["ytdl-raw-options"] = raw_opts
|
||||
except Exception as e:
|
||||
logger.debug(f"Could not update ytdl-raw-options: {e}")
|
||||
return
|
||||
logger.info("Player authentication settings reloaded.")
|
||||
|
||||
if self._current_entry and self._playback_started:
|
||||
position = self.current_position()
|
||||
entry = self._current_entry
|
||||
self._current_entry = {}
|
||||
self.play(entry, resume_pos=position)
|
||||
|
||||
def current_entry(self) -> Dict[str, Any]:
|
||||
return dict(self._current_entry)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user