Files
SageTube/ytsage/gui/ytsage_gui_account.py
T
Homer fd744a1a85 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>
2026-08-09 01:15:21 +02:00

83 lines
3.2 KiB
Python

"""
The YouTube account indicator
=============================
SageTube can use browser cookies to reach a signed-in YouTube: the account
feed, age-restricted and members-only videos, and premium formats. All of that
worked -- but the only way to switch it on was Downloads tab -> Custom Options
-> the "Login with Cookies" tab, and Downloads is one tab among five. The three
features that need it (the Feed's account mode, Search, Browse) had no route to
it at all, and `show_cookie_login_dialog()` existed with no caller anywhere in
the codebase.
So this is a button in the tab bar's corner, visible from every tab, that says
whether cookies are active and opens the existing dialog. Nothing about the
cookie handling itself changes; it just became findable.
"""
from typing import Optional
from PySide6.QtCore import Qt, Signal
from PySide6.QtWidgets import QPushButton, QWidget
from . import ytsage_icons as icons
from . import ytsage_theme as theme
from ..utils.ytsage_config_manager import ConfigManager
from ..utils.ytsage_localization import _
class AccountStatusButton(QPushButton):
"""Shows the cookie state and opens the login dialog when pressed."""
loginRequested = Signal()
def __init__(self, parent: Optional[QWidget] = None) -> None:
super().__init__(parent)
self.setObjectName("accountStatusButton")
self.setCursor(Qt.CursorShape.PointingHandCursor)
# Not a call to action -- it sits in the chrome, so it should not
# compete with the accent-coloured buttons in the pages.
self.setStyleSheet(
f"""
QPushButton#accountStatusButton {{
background-color: transparent;
color: {theme.TEXT_MUTED};
border: 1px solid {theme.BORDER};
border-radius: 4px;
padding: 5px 12px;
margin: 4px 8px 4px 4px;
font-weight: normal;
}}
QPushButton#accountStatusButton:hover {{
color: {theme.TEXT};
background-color: {theme.SURFACE_HOVER};
border-color: {theme.BORDER_STRONG};
}}
QPushButton#accountStatusButton:pressed {{
background-color: {theme.BORDER};
}}
"""
)
self.clicked.connect(self.loginRequested)
self.refresh()
def refresh(self) -> None:
"""Re-read the cookie config and restate what it says."""
active = bool(ConfigManager.get("cookie_active"))
if not active:
self.setIcon(icons.icon("user", theme.TEXT_MUTED))
self.setText(_("account.signed_out"))
self.setToolTip(_("account.signed_out_tooltip"))
return
if (ConfigManager.get("cookie_source") or "browser") == "file":
source = _("account.source_file")
else:
browser = ConfigManager.get("cookie_browser") or "?"
profile = ConfigManager.get("cookie_browser_profile")
source = f"{browser}:{profile}" if profile else str(browser)
self.setIcon(icons.icon("user-check", theme.TEXT))
self.setText(_("account.signed_in", source=source))
self.setToolTip(_("account.signed_in_tooltip", source=source))