File size: 4,212 Bytes
6cfe55f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import subprocess
import sys
import webbrowser
from typing import Optional

from app.services.cookie_manager import CookieConfigManager


PLATFORM_COOKIE_DOMAINS = {
    "bilibili": ("bilibili.com",),
    "youtube": ("youtube.com", "youtu.be"),
    "douyin": ("douyin.com", "iesdouyin.com"),
    "kuaishou": ("kuaishou.com",),
    "xiaohongshu": ("xiaohongshu.com", "xhslink.com"),
}

PLATFORM_LOGIN_URLS = {
    "bilibili": "https://www.bilibili.com/",
    "youtube": "https://www.youtube.com/",
    "douyin": "https://www.douyin.com/",
    "kuaishou": "https://www.kuaishou.com/",
    "xiaohongshu": "https://www.xiaohongshu.com/",
}

PLATFORM_LABELS = {
    "bilibili": "B站",
    "youtube": "YouTube",
    "douyin": "抖音",
    "kuaishou": "快手",
    "xiaohongshu": "小红书",
}


class BrowserCookieError(Exception):
    pass


def _extract_cookies_from_browser(browser: str):
    try:
        from yt_dlp.cookies import extract_cookies_from_browser
    except Exception as exc:
        raise BrowserCookieError("当前后端环境缺少 yt-dlp,无法从浏览器读取 Cookie") from exc
    return extract_cookies_from_browser(browser)


def _cookie_domains_for_platform(platform: str) -> tuple[str, ...]:
    return PLATFORM_COOKIE_DOMAINS.get(platform, (platform,))


def _matches_platform_domain(cookie_domain: str, platform: str) -> bool:
    domain = (cookie_domain or "").lstrip(".").lower()
    return any(
        domain == target or domain.endswith(f".{target}")
        for target in _cookie_domains_for_platform(platform)
    )


def _format_cookie_pairs(cookies, platform: str) -> list[str]:
    pairs = []
    seen = set()
    for cookie in cookies:
        name = getattr(cookie, "name", "")
        value = getattr(cookie, "value", "")
        domain = getattr(cookie, "domain", "")
        if not name or not value or not _matches_platform_domain(domain, platform):
            continue
        key = (name, value)
        if key in seen:
            continue
        seen.add(key)
        pairs.append(f"{name}={value}")
    return pairs


def _open_url_in_browser(url: str, browser: str) -> bool:
    browser = (browser or "").strip().lower()
    if sys.platform == "darwin" and browser:
        mac_apps = {
            "chrome": "Google Chrome",
            "edge": "Microsoft Edge",
            "firefox": "Firefox",
            "safari": "Safari",
            "brave": "Brave Browser",
            "chromium": "Chromium",
            "opera": "Opera",
            "vivaldi": "Vivaldi",
        }
        app_name = mac_apps.get(browser)
        if app_name:
            try:
                subprocess.Popen(["open", "-a", app_name, url])
                return True
            except Exception:
                pass
    return webbrowser.open_new_tab(url)


def sync_browser_cookie(
    platform: str,
    browser: str,
    manager: Optional[CookieConfigManager] = None,
) -> dict:
    platform = (platform or "").strip()
    browser = (browser or "").strip()
    if not platform:
        raise BrowserCookieError("平台不能为空")
    if not browser:
        raise BrowserCookieError("请选择浏览器")

    try:
        cookies = _extract_cookies_from_browser(browser)
    except Exception as exc:
        if isinstance(exc, BrowserCookieError):
            raise
        raise BrowserCookieError(f"从浏览器读取 Cookie 失败:{exc}") from exc

    pairs = _format_cookie_pairs(cookies, platform)
    if not pairs:
        login_url = PLATFORM_LOGIN_URLS.get(platform)
        opened = bool(login_url and _open_url_in_browser(login_url, browser))
        label = PLATFORM_LABELS.get(platform, platform)
        opened_hint = f"已打开{label}页面,登录后再点击一键获取。" if opened else ""
        raise BrowserCookieError(
            f"未找到 {platform} 对应的浏览器 Cookie,请先在该浏览器登录对应平台。{opened_hint}"
        )

    cookie_str = "; ".join(pairs)
    cookie_manager = manager or CookieConfigManager()
    cookie_manager.set(platform, cookie_str, browser=browser)
    return {
        "platform": platform,
        "browser": browser,
        "cookie": cookie_str,
        "count": len(pairs),
    }