main
 1#!/usr/bin/env python
 2# -*- coding: utf-8 -*-
 3import json
 4from pathlib import Path
 5
 6from httpx import AsyncHTTPTransport
 7from loguru import logger
 8
 9from config import DOWNLOAD_DIR, cache
10from database.kv import get_cf_kv
11from emby.constant import DEVICE_ID, DEVICE_NAME, EMBY_PROXY, HEADERS, VERSION
12from networking import hx_req
13
14
15@cache.memoize(ttl=60)
16async def all_accounts() -> dict[str, dict]:
17    """Get all accounts from cloudflare KV.
18
19    Return:
20        dict[str, dict]:  {"account_name": {"bot": "bot_handle", "server": "https://example.com", "username": "username", "password": "password"}}
21    """
22    kv = await get_cf_kv("emby")
23    return {k: v for k, v in kv.items() if v.get("enable", True)}
24
25
26async def get_account(name: str) -> dict[str, str]:
27    """Get all accounts from cloudflare KV.
28
29    Return:
30        dict[str, str]:  {"bot": "bot_handle", "server": "https://example.com", "username": "username", "password": "password"}
31    """
32    accounts = await all_accounts()
33    return accounts.get(name, {})
34
35
36async def emby_login(account_name: str, *, refresh: bool = False) -> dict:
37    save_path = Path(DOWNLOAD_DIR) / "emby" / f"{account_name}.json"
38    if not refresh and save_path.exists():
39        return json.loads(save_path.read_text())
40    account = await get_account(account_name)  # {"bot": "bot_handle", "server": "https://example.com", "username": "username", "password": "password"}
41    if not account:
42        return {}
43    headers = HEADERS | {
44        "authorization": f'MediaBrowser Client="Hills Windows", Device="{DEVICE_NAME}", DeviceId="{DEVICE_ID}", Version="{VERSION}"',
45    }
46    params = {
47        "X-Emby-Authorization": f'Emby Client="Hills Windows", Device="{DEVICE_NAME}", DeviceId="{DEVICE_ID}", Version="{VERSION}"',
48        "X-Emby-Client": "Hills Windows",
49        "X-Emby-Device-Name": DEVICE_NAME,
50        "X-Emby-Device-Id": DEVICE_ID,
51        "X-Emby-Client-Version": VERSION,
52        "X-Emby-Language": "zh-cn",
53    }
54    resp = await hx_req(
55        f"{account['server']}/emby/System/Info/Public",
56        "GET",
57        headers=headers,
58        transport=AsyncHTTPTransport(),
59        params=params,
60        proxy=EMBY_PROXY,
61        verify=False,
62        timeout=5,
63        max_retry=1,
64    )
65    resp = await hx_req(
66        f"{account['server']}/emby/Users/AuthenticateByName",
67        "POST",
68        headers=headers | {"content-type": "application/json"},
69        transport=AsyncHTTPTransport(),
70        params=params,
71        json_data={"Username": account["username"].strip(), "Password": account["password"].strip(), "Pw": account["password"].strip()},
72        check_kv={"SessionInfo.DeviceId": DEVICE_ID},
73        proxy=EMBY_PROXY,
74        verify=False,
75        timeout=5,
76        max_retry=1,
77    )
78    if resp.get("hx_error"):
79        logger.error(f"Failed to login {account_name}:\n{resp['hx_error']}")
80        return {}
81    resp["Server"] = account["server"]
82    resp["ServerName"] = account_name
83    save_path.parent.mkdir(parents=True, exist_ok=True)
84    save_path.write_text(json.dumps(resp, ensure_ascii=False, indent=2, sort_keys=True))
85    return resp