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