Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d46960433d | ||
|
|
2f2150d2f6 |
@@ -818,7 +818,22 @@ class DouyinImHttpClient:
|
|||||||
"""通过 IM API 发送 Protobuf 编码的私信(带接口签名)
|
"""通过 IM API 发送 Protobuf 编码的私信(带接口签名)
|
||||||
|
|
||||||
content 可为纯文本,或 JSON 格式的结构化回复(文本/网址/卡片)。
|
content 可为纯文本,或 JSON 格式的结构化回复(文本/网址/卡片)。
|
||||||
|
所有出站发送(自动回复/手动 API/脚本)都经过全局限流器,
|
||||||
|
防止大量托管账号同时发送占满出站带宽或触发平台级风控。
|
||||||
"""
|
"""
|
||||||
|
from .rate_limit import get_send_limiter
|
||||||
|
|
||||||
|
async with get_send_limiter():
|
||||||
|
return await self._send_text_message_unthrottled(
|
||||||
|
conversation_id, content, conversation_short_id
|
||||||
|
)
|
||||||
|
|
||||||
|
async def _send_text_message_unthrottled(
|
||||||
|
self,
|
||||||
|
conversation_id: str,
|
||||||
|
content: str,
|
||||||
|
conversation_short_id: str = "",
|
||||||
|
) -> bool:
|
||||||
from .auth import DouyinAuth
|
from .auth import DouyinAuth
|
||||||
from .proto_builder import ProtoBuilder
|
from .proto_builder import ProtoBuilder
|
||||||
from .reply_payload import (
|
from .reply_payload import (
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
"""全局出站发送限流器。
|
||||||
|
|
||||||
|
目的:托管账号数量多(如 1000 个)时,避免自动回复/手动发送在同一时刻
|
||||||
|
大量并发打向抖音接口,占满服务器出站带宽或触发平台级风控。
|
||||||
|
|
||||||
|
机制(两层,先到先过):
|
||||||
|
1. 并发上限(Semaphore):同时在途的发送请求数不超过 KEFU_SEND_MAX_CONCURRENCY;
|
||||||
|
2. 令牌桶(QPS):平均发送速率不超过 KEFU_SEND_RATE_PER_SEC,允许 KEFU_SEND_BURST 的突发。
|
||||||
|
|
||||||
|
限流器按事件循环惰性创建(backend 主循环一个实例;独立脚本各自一个),
|
||||||
|
所有账号共享同一个实例,因此是跨账号的全局闸门。
|
||||||
|
|
||||||
|
环境变量:
|
||||||
|
KEFU_SEND_MAX_CONCURRENCY 同时在途发送数上限,默认 20,<=0 表示不限
|
||||||
|
KEFU_SEND_RATE_PER_SEC 平均每秒发送数上限,默认 10,<=0 表示不限
|
||||||
|
KEFU_SEND_BURST 令牌桶容量(突发上限),默认与并发上限相同
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
logger = logging.getLogger("douyin_im.rate_limit")
|
||||||
|
|
||||||
|
|
||||||
|
def _env_float(name: str, default: float) -> float:
|
||||||
|
try:
|
||||||
|
return float(os.getenv(name, "") or default)
|
||||||
|
except ValueError:
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
class GlobalSendLimiter:
|
||||||
|
"""并发上限 + 令牌桶。用法:async with limiter: await 发送。"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
max_concurrency: int = 20,
|
||||||
|
rate_per_sec: float = 10.0,
|
||||||
|
burst: float | None = None,
|
||||||
|
):
|
||||||
|
self.max_concurrency = int(max_concurrency)
|
||||||
|
self.rate_per_sec = float(rate_per_sec)
|
||||||
|
self.burst = float(burst if burst is not None else max(1, max_concurrency))
|
||||||
|
self._sem = (
|
||||||
|
asyncio.Semaphore(self.max_concurrency) if self.max_concurrency > 0 else None
|
||||||
|
)
|
||||||
|
self._tokens = self.burst
|
||||||
|
self._last_refill = time.monotonic()
|
||||||
|
self._token_lock = asyncio.Lock()
|
||||||
|
# 统计:便于日志观察限流是否生效
|
||||||
|
self._waited_total = 0.0
|
||||||
|
self._acquired_count = 0
|
||||||
|
|
||||||
|
async def _take_token(self) -> None:
|
||||||
|
if self.rate_per_sec <= 0:
|
||||||
|
return
|
||||||
|
async with self._token_lock:
|
||||||
|
while True:
|
||||||
|
now = time.monotonic()
|
||||||
|
self._tokens = min(
|
||||||
|
self.burst, self._tokens + (now - self._last_refill) * self.rate_per_sec
|
||||||
|
)
|
||||||
|
self._last_refill = now
|
||||||
|
if self._tokens >= 1.0:
|
||||||
|
self._tokens -= 1.0
|
||||||
|
return
|
||||||
|
await asyncio.sleep((1.0 - self._tokens) / self.rate_per_sec)
|
||||||
|
|
||||||
|
async def __aenter__(self) -> "GlobalSendLimiter":
|
||||||
|
start = time.monotonic()
|
||||||
|
if self._sem is not None:
|
||||||
|
await self._sem.acquire()
|
||||||
|
try:
|
||||||
|
await self._take_token()
|
||||||
|
except BaseException:
|
||||||
|
if self._sem is not None:
|
||||||
|
self._sem.release()
|
||||||
|
raise
|
||||||
|
waited = time.monotonic() - start
|
||||||
|
self._waited_total += waited
|
||||||
|
self._acquired_count += 1
|
||||||
|
if waited > 1.0:
|
||||||
|
logger.info(
|
||||||
|
"send throttled: waited %.1fs (in-flight cap=%s, rate=%s/s)",
|
||||||
|
waited, self.max_concurrency or "∞", self.rate_per_sec or "∞",
|
||||||
|
)
|
||||||
|
return self
|
||||||
|
|
||||||
|
async def __aexit__(self, *exc) -> None:
|
||||||
|
if self._sem is not None:
|
||||||
|
self._sem.release()
|
||||||
|
|
||||||
|
|
||||||
|
# 每个事件循环一个实例(backend 主循环即全局唯一;脚本自用循环互不影响)
|
||||||
|
_limiters: dict[int, GlobalSendLimiter] = {}
|
||||||
|
|
||||||
|
|
||||||
|
def get_send_limiter() -> GlobalSendLimiter:
|
||||||
|
loop = asyncio.get_running_loop()
|
||||||
|
key = id(loop)
|
||||||
|
limiter = _limiters.get(key)
|
||||||
|
if limiter is None:
|
||||||
|
max_conc = int(_env_float("KEFU_SEND_MAX_CONCURRENCY", 20))
|
||||||
|
rate = _env_float("KEFU_SEND_RATE_PER_SEC", 10.0)
|
||||||
|
burst = _env_float("KEFU_SEND_BURST", max(1, max_conc))
|
||||||
|
limiter = GlobalSendLimiter(max_conc, rate, burst)
|
||||||
|
_limiters[key] = limiter
|
||||||
|
logger.info(
|
||||||
|
"global send limiter ready: concurrency=%s, rate=%s/s, burst=%s",
|
||||||
|
max_conc if max_conc > 0 else "unlimited",
|
||||||
|
rate if rate > 0 else "unlimited",
|
||||||
|
burst,
|
||||||
|
)
|
||||||
|
return limiter
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
import random
|
||||||
import time
|
import time
|
||||||
from typing import Awaitable, Callable, Optional
|
from typing import Awaitable, Callable, Optional
|
||||||
|
|
||||||
@@ -374,6 +376,22 @@ class DouyinImService:
|
|||||||
)
|
)
|
||||||
await self._ws_client.start()
|
await self._ws_client.start()
|
||||||
|
|
||||||
|
# 轮询错峰:多账号同时托管时,若所有账号按同一节奏轮询,请求会在同一
|
||||||
|
# 时刻叠峰。这里给每个账号随机相位偏移 + 每轮 ±20% 抖动,把请求摊平。
|
||||||
|
# WS 可用时轮询只是兜底,可以适当放缓(KEFU_IM_POLL_INTERVAL_SECONDS 可调)。
|
||||||
|
try:
|
||||||
|
poll_interval = float(os.getenv("KEFU_IM_POLL_INTERVAL_SECONDS", "") or 15)
|
||||||
|
except ValueError:
|
||||||
|
poll_interval = 15.0
|
||||||
|
poll_interval = max(5.0, poll_interval)
|
||||||
|
if has_ws:
|
||||||
|
poll_interval = max(poll_interval, 30.0)
|
||||||
|
|
||||||
|
# 首轮轮询前的随机延迟(相位偏移),批量启动时错开各账号的首波请求
|
||||||
|
await asyncio.sleep(random.uniform(0.5, min(10.0, poll_interval)))
|
||||||
|
if not self._running:
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await self._poll_conversations()
|
await self._poll_conversations()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -387,10 +405,12 @@ class DouyinImService:
|
|||||||
)
|
)
|
||||||
|
|
||||||
loop_count = 0
|
loop_count = 0
|
||||||
|
next_poll = time.monotonic() + poll_interval * random.uniform(0.8, 1.2)
|
||||||
while self._running:
|
while self._running:
|
||||||
loop_count += 1
|
loop_count += 1
|
||||||
try:
|
try:
|
||||||
if loop_count % 3 == 1:
|
if time.monotonic() >= next_poll:
|
||||||
|
next_poll = time.monotonic() + poll_interval * random.uniform(0.8, 1.2)
|
||||||
await self._poll_conversations()
|
await self._poll_conversations()
|
||||||
if loop_count % 6 == 1:
|
if loop_count % 6 == 1:
|
||||||
logger.info(f"IM direct tick #{loop_count} account={self.account_id}")
|
logger.info(f"IM direct tick #{loop_count} account={self.account_id}")
|
||||||
|
|||||||
@@ -49,6 +49,36 @@ async def _launch_chromium(pw, args: list[str], headless: Optional[bool] = None)
|
|||||||
return await pw.chromium.launch(**launch_kwargs)
|
return await pw.chromium.launch(**launch_kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# 启动错峰门:批量启动大量账号时,把各 worker 的启动时刻按固定间隔排开,
|
||||||
|
# 避免同一瞬间大量凭证校验/WS 建连/首轮拉取叠峰。
|
||||||
|
# 空闲时单个账号启动无需等待;只有短时间内大量启动才会排队。
|
||||||
|
# KEFU_WORKER_START_INTERVAL_SECONDS:相邻两个 worker 启动的最小间隔,默认 1.5s,<=0 关闭。
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
_start_gate = {"lock": None, "next_at": 0.0}
|
||||||
|
|
||||||
|
|
||||||
|
async def _startup_stagger(account_id: int) -> None:
|
||||||
|
try:
|
||||||
|
interval = float(os.getenv("KEFU_WORKER_START_INTERVAL_SECONDS", "") or 1.5)
|
||||||
|
except ValueError:
|
||||||
|
interval = 1.5
|
||||||
|
if interval <= 0:
|
||||||
|
return
|
||||||
|
if _start_gate["lock"] is None:
|
||||||
|
_start_gate["lock"] = asyncio.Lock()
|
||||||
|
async with _start_gate["lock"]:
|
||||||
|
now = time.monotonic()
|
||||||
|
wait = max(0.0, _start_gate["next_at"] - now)
|
||||||
|
_start_gate["next_at"] = max(now, _start_gate["next_at"]) + interval
|
||||||
|
if wait > 0:
|
||||||
|
if wait > 5:
|
||||||
|
logger.info(
|
||||||
|
f"Account {account_id}: start queued, waiting {wait:.1f}s to smooth batch startup"
|
||||||
|
)
|
||||||
|
await asyncio.sleep(wait)
|
||||||
|
|
||||||
|
|
||||||
def format_error(exc: BaseException) -> str:
|
def format_error(exc: BaseException) -> str:
|
||||||
message = str(exc).strip()
|
message = str(exc).strip()
|
||||||
if "Target page, context or browser has been closed" in message:
|
if "Target page, context or browser has been closed" in message:
|
||||||
@@ -995,6 +1025,9 @@ class DouyinWorker:
|
|||||||
logger.info(f"Starting worker loop for account {self.account_id}")
|
logger.info(f"Starting worker loop for account {self.account_id}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
await _startup_stagger(self.account_id)
|
||||||
|
if self.stopping:
|
||||||
|
return
|
||||||
storage_state = await self._load_storage_state()
|
storage_state = await self._load_storage_state()
|
||||||
cookie_info = analyze_cookie(
|
cookie_info = analyze_cookie(
|
||||||
json.dumps(storage_state, ensure_ascii=False) if storage_state else None
|
json.dumps(storage_state, ensure_ascii=False) if storage_state else None
|
||||||
|
|||||||
@@ -139,9 +139,17 @@ def open_logged_in_browser(
|
|||||||
log(f"页面加载提示:{e}(可在浏览器里手动刷新)")
|
log(f"页面加载提示:{e}(可在浏览器里手动刷新)")
|
||||||
log("浏览器已打开,登录态已注入。关闭浏览器窗口即可结束。")
|
log("浏览器已打开,登录态已注入。关闭浏览器窗口即可结束。")
|
||||||
|
|
||||||
|
# 保活等待必须用 Playwright 的 wait_for_timeout(内部持续处理浏览器事件),
|
||||||
|
# 不能用 time.sleep:sleep 会卡住 Playwright 客户端线程,导致页面里
|
||||||
|
# 新开的标签页(如抖音「视频管理」)永远停在 about:blank 无法加载。
|
||||||
try:
|
try:
|
||||||
while browser.is_connected() and context.pages:
|
while browser.is_connected() and context.pages:
|
||||||
time.sleep(1)
|
pg = context.pages[0]
|
||||||
|
try:
|
||||||
|
pg.wait_for_timeout(1000)
|
||||||
|
except Exception:
|
||||||
|
# 该页面刚被用户关闭等瞬态情况,稍候重查
|
||||||
|
time.sleep(0.2)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
(['D:\\file\\kefu\\douyin-login-launcher\\desktop_app.py'],
|
(['D:\\file\\douyin\\douyin-login-launcher\\desktop_app.py'],
|
||||||
['D:\\file\\kefu\\douyin-login-launcher'],
|
['D:\\file\\douyin\\douyin-login-launcher'],
|
||||||
['playwright',
|
['playwright',
|
||||||
'playwright.__main__',
|
'playwright.__main__',
|
||||||
'playwright._impl',
|
'playwright._impl',
|
||||||
@@ -2485,7 +2485,7 @@
|
|||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\_pyinstaller_hooks_contrib\\rthooks\\pyi_rth_cryptography_openssl.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\_pyinstaller_hooks_contrib\\rthooks\\pyi_rth_cryptography_openssl.py',
|
||||||
'PYSOURCE'),
|
'PYSOURCE'),
|
||||||
('desktop_app',
|
('desktop_app',
|
||||||
'D:\\file\\kefu\\douyin-login-launcher\\desktop_app.py',
|
'D:\\file\\douyin\\douyin-login-launcher\\desktop_app.py',
|
||||||
'PYSOURCE')],
|
'PYSOURCE')],
|
||||||
[('pkg_resources',
|
[('pkg_resources',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\pkg_resources\\__init__.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\pkg_resources\\__init__.py',
|
||||||
@@ -2559,9 +2559,6 @@
|
|||||||
('gettext',
|
('gettext',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\gettext.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\gettext.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('urllib',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\urllib\\__init__.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('email.charset',
|
('email.charset',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\charset.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\charset.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
@@ -3130,30 +3127,6 @@
|
|||||||
('xml.sax.saxutils',
|
('xml.sax.saxutils',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\xml\\sax\\saxutils.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\xml\\sax\\saxutils.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('urllib.request',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\urllib\\request.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('getpass',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\getpass.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('nturl2path',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\nturl2path.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('ftplib',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\ftplib.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('netrc',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\netrc.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('http.cookiejar',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\http\\cookiejar.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('urllib.response',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\urllib\\response.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('urllib.error',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\urllib\\error.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('xml.sax',
|
('xml.sax',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\xml\\sax\\__init__.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\xml\\sax\\__init__.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
@@ -3346,6 +3319,9 @@
|
|||||||
('setuptools._distutils.command.register',
|
('setuptools._distutils.command.register',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\setuptools\\_distutils\\command\\register.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\setuptools\\_distutils\\command\\register.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
|
('getpass',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\getpass.py',
|
||||||
|
'PYMODULE'),
|
||||||
('setuptools._distutils.command.py37compat',
|
('setuptools._distutils.command.py37compat',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\setuptools\\_distutils\\command\\py37compat.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\setuptools\\_distutils\\command\\py37compat.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
@@ -4969,31 +4945,47 @@
|
|||||||
('playwright',
|
('playwright',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\playwright\\__init__.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\playwright\\__init__.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
|
('stringprep',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\stringprep.py',
|
||||||
|
'PYMODULE'),
|
||||||
('tracemalloc',
|
('tracemalloc',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tracemalloc.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tracemalloc.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('_py_abc',
|
('_py_abc',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_py_abc.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_py_abc.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('stringprep',
|
('urllib.request',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\stringprep.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\urllib\\request.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('json',
|
('nturl2path',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\json\\__init__.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\nturl2path.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('json.encoder',
|
('ftplib',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\json\\encoder.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\ftplib.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('json.decoder',
|
('netrc',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\json\\decoder.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\netrc.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('json.scanner',
|
('http.cookiejar',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\json\\scanner.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\http\\cookiejar.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('urllib.response',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\urllib\\response.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('urllib.error',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\urllib\\error.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('urllib',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\urllib\\__init__.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('version',
|
||||||
|
'D:\\file\\douyin\\douyin-login-launcher\\version.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('updater',
|
||||||
|
'D:\\file\\douyin\\douyin-login-launcher\\updater.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('version', 'D:\\file\\kefu\\douyin-login-launcher\\version.py', 'PYMODULE'),
|
|
||||||
('updater', 'D:\\file\\kefu\\douyin-login-launcher\\updater.py', 'PYMODULE'),
|
|
||||||
('browser_open',
|
('browser_open',
|
||||||
'D:\\file\\kefu\\douyin-login-launcher\\browser_open.py',
|
'D:\\file\\douyin\\douyin-login-launcher\\browser_open.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('webview',
|
('webview',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\webview\\__init__.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\webview\\__init__.py',
|
||||||
@@ -5175,6 +5167,18 @@
|
|||||||
('subprocess',
|
('subprocess',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\subprocess.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\subprocess.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
|
('json',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\json\\__init__.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('json.encoder',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\json\\encoder.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('json.decoder',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\json\\decoder.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('json.scanner',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\json\\scanner.py',
|
||||||
|
'PYMODULE'),
|
||||||
('ctypes',
|
('ctypes',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\ctypes\\__init__.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\ctypes\\__init__.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
@@ -7270,15 +7274,6 @@
|
|||||||
('webview\\window.py',
|
('webview\\window.py',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\webview\\window.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\webview\\window.py',
|
||||||
'DATA'),
|
'DATA'),
|
||||||
('cryptography-48.0.0.dist-info\\WHEEL',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\cryptography-48.0.0.dist-info\\WHEEL',
|
|
||||||
'DATA'),
|
|
||||||
('cryptography-48.0.0.dist-info\\METADATA',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\cryptography-48.0.0.dist-info\\METADATA',
|
|
||||||
'DATA'),
|
|
||||||
('cryptography-48.0.0.dist-info\\INSTALLER',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\cryptography-48.0.0.dist-info\\INSTALLER',
|
|
||||||
'DATA'),
|
|
||||||
('cryptography-48.0.0.dist-info\\sboms\\cryptography-rust.cyclonedx.json',
|
('cryptography-48.0.0.dist-info\\sboms\\cryptography-rust.cyclonedx.json',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\cryptography-48.0.0.dist-info\\sboms\\cryptography-rust.cyclonedx.json',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\cryptography-48.0.0.dist-info\\sboms\\cryptography-rust.cyclonedx.json',
|
||||||
'DATA'),
|
'DATA'),
|
||||||
@@ -7288,17 +7283,44 @@
|
|||||||
('cryptography-48.0.0.dist-info\\RECORD',
|
('cryptography-48.0.0.dist-info\\RECORD',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\cryptography-48.0.0.dist-info\\RECORD',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\cryptography-48.0.0.dist-info\\RECORD',
|
||||||
'DATA'),
|
'DATA'),
|
||||||
('cryptography-48.0.0.dist-info\\licenses\\LICENSE.APACHE',
|
('cryptography-48.0.0.dist-info\\METADATA',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\cryptography-48.0.0.dist-info\\licenses\\LICENSE.APACHE',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\cryptography-48.0.0.dist-info\\METADATA',
|
||||||
|
'DATA'),
|
||||||
|
('cryptography-48.0.0.dist-info\\INSTALLER',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\cryptography-48.0.0.dist-info\\INSTALLER',
|
||||||
'DATA'),
|
'DATA'),
|
||||||
('cryptography-48.0.0.dist-info\\licenses\\LICENSE',
|
('cryptography-48.0.0.dist-info\\licenses\\LICENSE',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\cryptography-48.0.0.dist-info\\licenses\\LICENSE',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\cryptography-48.0.0.dist-info\\licenses\\LICENSE',
|
||||||
'DATA'),
|
'DATA'),
|
||||||
|
('cryptography-48.0.0.dist-info\\WHEEL',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\cryptography-48.0.0.dist-info\\WHEEL',
|
||||||
|
'DATA'),
|
||||||
('cryptography-48.0.0.dist-info\\licenses\\LICENSE.BSD',
|
('cryptography-48.0.0.dist-info\\licenses\\LICENSE.BSD',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\cryptography-48.0.0.dist-info\\licenses\\LICENSE.BSD',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\cryptography-48.0.0.dist-info\\licenses\\LICENSE.BSD',
|
||||||
'DATA'),
|
'DATA'),
|
||||||
('attrs-26.1.0.dist-info\\METADATA',
|
('cryptography-48.0.0.dist-info\\licenses\\LICENSE.APACHE',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\attrs-26.1.0.dist-info\\METADATA',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\cryptography-48.0.0.dist-info\\licenses\\LICENSE.APACHE',
|
||||||
|
'DATA'),
|
||||||
|
('wheel-0.45.1.dist-info\\WHEEL',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\wheel-0.45.1.dist-info\\WHEEL',
|
||||||
|
'DATA'),
|
||||||
|
('attrs-26.1.0.dist-info\\INSTALLER',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\attrs-26.1.0.dist-info\\INSTALLER',
|
||||||
|
'DATA'),
|
||||||
|
('wheel-0.45.1.dist-info\\RECORD',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\wheel-0.45.1.dist-info\\RECORD',
|
||||||
|
'DATA'),
|
||||||
|
('setuptools-65.5.0.dist-info\\WHEEL',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\setuptools-65.5.0.dist-info\\WHEEL',
|
||||||
|
'DATA'),
|
||||||
|
('wheel-0.45.1.dist-info\\LICENSE.txt',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\wheel-0.45.1.dist-info\\LICENSE.txt',
|
||||||
|
'DATA'),
|
||||||
|
('setuptools-65.5.0.dist-info\\INSTALLER',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\setuptools-65.5.0.dist-info\\INSTALLER',
|
||||||
|
'DATA'),
|
||||||
|
('setuptools-65.5.0.dist-info\\RECORD',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\setuptools-65.5.0.dist-info\\RECORD',
|
||||||
'DATA'),
|
'DATA'),
|
||||||
('wheel-0.45.1.dist-info\\REQUESTED',
|
('wheel-0.45.1.dist-info\\REQUESTED',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\wheel-0.45.1.dist-info\\REQUESTED',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\wheel-0.45.1.dist-info\\REQUESTED',
|
||||||
@@ -7309,129 +7331,48 @@
|
|||||||
('setuptools-65.5.0.dist-info\\LICENSE',
|
('setuptools-65.5.0.dist-info\\LICENSE',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\setuptools-65.5.0.dist-info\\LICENSE',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\setuptools-65.5.0.dist-info\\LICENSE',
|
||||||
'DATA'),
|
'DATA'),
|
||||||
('wheel-0.45.1.dist-info\\entry_points.txt',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\wheel-0.45.1.dist-info\\entry_points.txt',
|
|
||||||
'DATA'),
|
|
||||||
('wheel-0.45.1.dist-info\\RECORD',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\wheel-0.45.1.dist-info\\RECORD',
|
|
||||||
'DATA'),
|
|
||||||
('attrs-26.1.0.dist-info\\INSTALLER',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\attrs-26.1.0.dist-info\\INSTALLER',
|
|
||||||
'DATA'),
|
|
||||||
('wheel-0.45.1.dist-info\\LICENSE.txt',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\wheel-0.45.1.dist-info\\LICENSE.txt',
|
|
||||||
'DATA'),
|
|
||||||
('attrs-26.1.0.dist-info\\RECORD',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\attrs-26.1.0.dist-info\\RECORD',
|
|
||||||
'DATA'),
|
|
||||||
('setuptools-65.5.0.dist-info\\INSTALLER',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\setuptools-65.5.0.dist-info\\INSTALLER',
|
|
||||||
'DATA'),
|
|
||||||
('setuptools-65.5.0.dist-info\\WHEEL',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\setuptools-65.5.0.dist-info\\WHEEL',
|
|
||||||
'DATA'),
|
|
||||||
('wheel-0.45.1.dist-info\\METADATA',
|
('wheel-0.45.1.dist-info\\METADATA',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\wheel-0.45.1.dist-info\\METADATA',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\wheel-0.45.1.dist-info\\METADATA',
|
||||||
'DATA'),
|
'DATA'),
|
||||||
('wheel-0.45.1.dist-info\\INSTALLER',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\wheel-0.45.1.dist-info\\INSTALLER',
|
|
||||||
'DATA'),
|
|
||||||
('setuptools-65.5.0.dist-info\\METADATA',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\setuptools-65.5.0.dist-info\\METADATA',
|
|
||||||
'DATA'),
|
|
||||||
('wheel-0.45.1.dist-info\\WHEEL',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\wheel-0.45.1.dist-info\\WHEEL',
|
|
||||||
'DATA'),
|
|
||||||
('setuptools-65.5.0.dist-info\\entry_points.txt',
|
('setuptools-65.5.0.dist-info\\entry_points.txt',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\setuptools-65.5.0.dist-info\\entry_points.txt',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\setuptools-65.5.0.dist-info\\entry_points.txt',
|
||||||
'DATA'),
|
'DATA'),
|
||||||
('setuptools-65.5.0.dist-info\\RECORD',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\setuptools-65.5.0.dist-info\\RECORD',
|
|
||||||
'DATA'),
|
|
||||||
('setuptools-65.5.0.dist-info\\top_level.txt',
|
('setuptools-65.5.0.dist-info\\top_level.txt',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\setuptools-65.5.0.dist-info\\top_level.txt',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\setuptools-65.5.0.dist-info\\top_level.txt',
|
||||||
'DATA'),
|
'DATA'),
|
||||||
|
('wheel-0.45.1.dist-info\\entry_points.txt',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\wheel-0.45.1.dist-info\\entry_points.txt',
|
||||||
|
'DATA'),
|
||||||
('attrs-26.1.0.dist-info\\licenses\\LICENSE',
|
('attrs-26.1.0.dist-info\\licenses\\LICENSE',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\attrs-26.1.0.dist-info\\licenses\\LICENSE',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\attrs-26.1.0.dist-info\\licenses\\LICENSE',
|
||||||
'DATA'),
|
'DATA'),
|
||||||
|
('attrs-26.1.0.dist-info\\RECORD',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\attrs-26.1.0.dist-info\\RECORD',
|
||||||
|
'DATA'),
|
||||||
|
('setuptools-65.5.0.dist-info\\METADATA',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\setuptools-65.5.0.dist-info\\METADATA',
|
||||||
|
'DATA'),
|
||||||
|
('wheel-0.45.1.dist-info\\INSTALLER',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\wheel-0.45.1.dist-info\\INSTALLER',
|
||||||
|
'DATA'),
|
||||||
|
('attrs-26.1.0.dist-info\\METADATA',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\attrs-26.1.0.dist-info\\METADATA',
|
||||||
|
'DATA'),
|
||||||
('attrs-26.1.0.dist-info\\WHEEL',
|
('attrs-26.1.0.dist-info\\WHEEL',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\attrs-26.1.0.dist-info\\WHEEL',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\attrs-26.1.0.dist-info\\WHEEL',
|
||||||
'DATA'),
|
'DATA'),
|
||||||
('base_library.zip',
|
('base_library.zip',
|
||||||
'D:\\file\\kefu\\douyin-login-launcher\\build\\desktop\\base_library.zip',
|
'D:\\file\\douyin\\douyin-login-launcher\\build\\desktop\\base_library.zip',
|
||||||
'DATA')],
|
'DATA')],
|
||||||
[('_weakrefset',
|
[('functools',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_weakrefset.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\functools.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('copyreg',
|
('locale',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\copyreg.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\locale.py',
|
||||||
'PYMODULE'),
|
|
||||||
('posixpath',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\posixpath.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('stat',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\stat.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('warnings',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\warnings.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('traceback',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\traceback.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('reprlib',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\reprlib.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('re._parser',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\re\\_parser.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('re._constants',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\re\\_constants.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('re._compiler',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\re\\_compiler.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('re._casefix',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\re\\_casefix.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('re',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\re\\__init__.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('ntpath',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\ntpath.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('enum',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\enum.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('abc',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\abc.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('_collections_abc',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_collections_abc.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('keyword',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\keyword.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('sre_constants',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\sre_constants.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('heapq',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\heapq.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('sre_compile',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\sre_compile.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('sre_parse',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\sre_parse.py',
|
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('genericpath',
|
('genericpath',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\genericpath.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\genericpath.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('collections.abc',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\collections\\abc.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('collections',
|
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\collections\\__init__.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('encodings.zlib_codec',
|
('encodings.zlib_codec',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\encodings\\zlib_codec.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\encodings\\zlib_codec.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
@@ -7798,30 +7739,93 @@
|
|||||||
('encodings',
|
('encodings',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\encodings\\__init__.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\encodings\\__init__.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('locale',
|
('sre_parse',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\locale.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\sre_parse.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('types',
|
('warnings',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\types.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\warnings.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('linecache',
|
('re._parser',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\linecache.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\re\\_parser.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('io',
|
('re._constants',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\io.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\re\\_constants.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('weakref',
|
('re._compiler',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\weakref.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\re\\_compiler.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('functools',
|
('re._casefix',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\functools.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\re\\_casefix.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('re',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\re\\__init__.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('operator',
|
('operator',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\operator.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\operator.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
|
('stat',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\stat.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('posixpath',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\posixpath.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('enum',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\enum.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('reprlib',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\reprlib.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('heapq',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\heapq.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('abc',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\abc.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('sre_constants',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\sre_constants.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('copyreg',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\copyreg.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('_weakrefset',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_weakrefset.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('types',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\types.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('sre_compile',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\sre_compile.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('_collections_abc',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_collections_abc.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('ntpath',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\ntpath.py',
|
||||||
|
'PYMODULE'),
|
||||||
('codecs',
|
('codecs',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\codecs.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\codecs.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
|
('linecache',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\linecache.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('weakref',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\weakref.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('traceback',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\traceback.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('io',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\io.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('keyword',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\keyword.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('collections.abc',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\collections\\abc.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('collections',
|
||||||
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\collections\\__init__.py',
|
||||||
|
'PYMODULE'),
|
||||||
('os',
|
('os',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\os.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\os.py',
|
||||||
'PYMODULE')])
|
'PYMODULE')])
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
([('DouyinDesktop.exe',
|
([('DouyinDesktop.exe',
|
||||||
'D:\\file\\kefu\\douyin-login-launcher\\build\\desktop\\DouyinDesktop.exe',
|
'D:\\file\\douyin\\douyin-login-launcher\\build\\desktop\\DouyinDesktop.exe',
|
||||||
'EXECUTABLE'),
|
'EXECUTABLE'),
|
||||||
('Pythonwin\\mfc140u.dll',
|
('Pythonwin\\mfc140u.dll',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\Pythonwin\\mfc140u.dll',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\Pythonwin\\mfc140u.dll',
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\attrs-26.1.0.dist-info\\licenses\\LICENSE',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\attrs-26.1.0.dist-info\\licenses\\LICENSE',
|
||||||
'DATA'),
|
'DATA'),
|
||||||
('base_library.zip',
|
('base_library.zip',
|
||||||
'D:\\file\\kefu\\douyin-login-launcher\\build\\desktop\\base_library.zip',
|
'D:\\file\\douyin\\douyin-login-launcher\\build\\desktop\\base_library.zip',
|
||||||
'DATA'),
|
'DATA'),
|
||||||
('bcrypt\\_bcrypt.pyd',
|
('bcrypt\\_bcrypt.pyd',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\bcrypt\\_bcrypt.pyd',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\bcrypt\\_bcrypt.pyd',
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -1,8 +1,8 @@
|
|||||||
('D:\\file\\kefu\\douyin-login-launcher\\build\\desktop\\DouyinDesktop.exe',
|
('D:\\file\\douyin\\douyin-login-launcher\\build\\desktop\\DouyinDesktop.exe',
|
||||||
False,
|
False,
|
||||||
False,
|
False,
|
||||||
True,
|
True,
|
||||||
['D:\\file\\kefu\\douyin-login-launcher\\app.ico'],
|
['D:\\file\\douyin\\douyin-login-launcher\\app.ico'],
|
||||||
None,
|
None,
|
||||||
False,
|
False,
|
||||||
False,
|
False,
|
||||||
@@ -29,25 +29,25 @@
|
|||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
'D:\\file\\kefu\\douyin-login-launcher\\build\\desktop\\DouyinDesktop.pkg',
|
'D:\\file\\douyin\\douyin-login-launcher\\build\\desktop\\DouyinDesktop.pkg',
|
||||||
[('pyi-contents-directory _internal', '', 'OPTION'),
|
[('pyi-contents-directory _internal', '', 'OPTION'),
|
||||||
('PYZ-00.pyz',
|
('PYZ-00.pyz',
|
||||||
'D:\\file\\kefu\\douyin-login-launcher\\build\\desktop\\PYZ-00.pyz',
|
'D:\\file\\douyin\\douyin-login-launcher\\build\\desktop\\PYZ-00.pyz',
|
||||||
'PYZ'),
|
'PYZ'),
|
||||||
('struct',
|
('struct',
|
||||||
'D:\\file\\kefu\\douyin-login-launcher\\build\\desktop\\localpycs\\struct.pyc',
|
'D:\\file\\douyin\\douyin-login-launcher\\build\\desktop\\localpycs\\struct.pyc',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('pyimod01_archive',
|
('pyimod01_archive',
|
||||||
'D:\\file\\kefu\\douyin-login-launcher\\build\\desktop\\localpycs\\pyimod01_archive.pyc',
|
'D:\\file\\douyin\\douyin-login-launcher\\build\\desktop\\localpycs\\pyimod01_archive.pyc',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('pyimod02_importers',
|
('pyimod02_importers',
|
||||||
'D:\\file\\kefu\\douyin-login-launcher\\build\\desktop\\localpycs\\pyimod02_importers.pyc',
|
'D:\\file\\douyin\\douyin-login-launcher\\build\\desktop\\localpycs\\pyimod02_importers.pyc',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('pyimod03_ctypes',
|
('pyimod03_ctypes',
|
||||||
'D:\\file\\kefu\\douyin-login-launcher\\build\\desktop\\localpycs\\pyimod03_ctypes.pyc',
|
'D:\\file\\douyin\\douyin-login-launcher\\build\\desktop\\localpycs\\pyimod03_ctypes.pyc',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('pyimod04_pywin32',
|
('pyimod04_pywin32',
|
||||||
'D:\\file\\kefu\\douyin-login-launcher\\build\\desktop\\localpycs\\pyimod04_pywin32.pyc',
|
'D:\\file\\douyin\\douyin-login-launcher\\build\\desktop\\localpycs\\pyimod04_pywin32.pyc',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('pyiboot01_bootstrap',
|
('pyiboot01_bootstrap',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
|
||||||
@@ -77,12 +77,12 @@
|
|||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\_pyinstaller_hooks_contrib\\rthooks\\pyi_rth_cryptography_openssl.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\_pyinstaller_hooks_contrib\\rthooks\\pyi_rth_cryptography_openssl.py',
|
||||||
'PYSOURCE'),
|
'PYSOURCE'),
|
||||||
('desktop_app',
|
('desktop_app',
|
||||||
'D:\\file\\kefu\\douyin-login-launcher\\desktop_app.py',
|
'D:\\file\\douyin\\douyin-login-launcher\\desktop_app.py',
|
||||||
'PYSOURCE')],
|
'PYSOURCE')],
|
||||||
[],
|
[],
|
||||||
False,
|
False,
|
||||||
False,
|
False,
|
||||||
1782438587,
|
1784257587,
|
||||||
[('runw.exe',
|
[('runw.exe',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\PyInstaller\\bootloader\\Windows-64bit-intel\\runw.exe',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\PyInstaller\\bootloader\\Windows-64bit-intel\\runw.exe',
|
||||||
'EXECUTABLE')],
|
'EXECUTABLE')],
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
('D:\\file\\kefu\\douyin-login-launcher\\build\\desktop\\DouyinDesktop.pkg',
|
('D:\\file\\douyin\\douyin-login-launcher\\build\\desktop\\DouyinDesktop.pkg',
|
||||||
{'BINARY': True,
|
{'BINARY': True,
|
||||||
'DATA': True,
|
'DATA': True,
|
||||||
'EXECUTABLE': True,
|
'EXECUTABLE': True,
|
||||||
@@ -10,22 +10,22 @@
|
|||||||
'SYMLINK': False},
|
'SYMLINK': False},
|
||||||
[('pyi-contents-directory _internal', '', 'OPTION'),
|
[('pyi-contents-directory _internal', '', 'OPTION'),
|
||||||
('PYZ-00.pyz',
|
('PYZ-00.pyz',
|
||||||
'D:\\file\\kefu\\douyin-login-launcher\\build\\desktop\\PYZ-00.pyz',
|
'D:\\file\\douyin\\douyin-login-launcher\\build\\desktop\\PYZ-00.pyz',
|
||||||
'PYZ'),
|
'PYZ'),
|
||||||
('struct',
|
('struct',
|
||||||
'D:\\file\\kefu\\douyin-login-launcher\\build\\desktop\\localpycs\\struct.pyc',
|
'D:\\file\\douyin\\douyin-login-launcher\\build\\desktop\\localpycs\\struct.pyc',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('pyimod01_archive',
|
('pyimod01_archive',
|
||||||
'D:\\file\\kefu\\douyin-login-launcher\\build\\desktop\\localpycs\\pyimod01_archive.pyc',
|
'D:\\file\\douyin\\douyin-login-launcher\\build\\desktop\\localpycs\\pyimod01_archive.pyc',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('pyimod02_importers',
|
('pyimod02_importers',
|
||||||
'D:\\file\\kefu\\douyin-login-launcher\\build\\desktop\\localpycs\\pyimod02_importers.pyc',
|
'D:\\file\\douyin\\douyin-login-launcher\\build\\desktop\\localpycs\\pyimod02_importers.pyc',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('pyimod03_ctypes',
|
('pyimod03_ctypes',
|
||||||
'D:\\file\\kefu\\douyin-login-launcher\\build\\desktop\\localpycs\\pyimod03_ctypes.pyc',
|
'D:\\file\\douyin\\douyin-login-launcher\\build\\desktop\\localpycs\\pyimod03_ctypes.pyc',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('pyimod04_pywin32',
|
('pyimod04_pywin32',
|
||||||
'D:\\file\\kefu\\douyin-login-launcher\\build\\desktop\\localpycs\\pyimod04_pywin32.pyc',
|
'D:\\file\\douyin\\douyin-login-launcher\\build\\desktop\\localpycs\\pyimod04_pywin32.pyc',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('pyiboot01_bootstrap',
|
('pyiboot01_bootstrap',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\_pyinstaller_hooks_contrib\\rthooks\\pyi_rth_cryptography_openssl.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\_pyinstaller_hooks_contrib\\rthooks\\pyi_rth_cryptography_openssl.py',
|
||||||
'PYSOURCE'),
|
'PYSOURCE'),
|
||||||
('desktop_app',
|
('desktop_app',
|
||||||
'D:\\file\\kefu\\douyin-login-launcher\\desktop_app.py',
|
'D:\\file\\douyin\\douyin-login-launcher\\desktop_app.py',
|
||||||
'PYSOURCE')],
|
'PYSOURCE')],
|
||||||
'python311.dll',
|
'python311.dll',
|
||||||
True,
|
True,
|
||||||
|
|||||||
Binary file not shown.
@@ -1,4 +1,4 @@
|
|||||||
('D:\\file\\kefu\\douyin-login-launcher\\build\\desktop\\PYZ-00.pyz',
|
('D:\\file\\douyin\\douyin-login-launcher\\build\\desktop\\PYZ-00.pyz',
|
||||||
[('PyInstaller',
|
[('PyInstaller',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\PyInstaller\\__init__.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\PyInstaller\\__init__.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
@@ -294,7 +294,7 @@
|
|||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\bottle.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\bottle.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('browser_open',
|
('browser_open',
|
||||||
'D:\\file\\kefu\\douyin-login-launcher\\browser_open.py',
|
'D:\\file\\douyin\\douyin-login-launcher\\browser_open.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('bz2',
|
('bz2',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\bz2.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\bz2.py',
|
||||||
@@ -2346,7 +2346,9 @@
|
|||||||
('unittest.util',
|
('unittest.util',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\unittest\\util.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\unittest\\util.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('updater', 'D:\\file\\kefu\\douyin-login-launcher\\updater.py', 'PYMODULE'),
|
('updater',
|
||||||
|
'D:\\file\\douyin\\douyin-login-launcher\\updater.py',
|
||||||
|
'PYMODULE'),
|
||||||
('urllib',
|
('urllib',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\urllib\\__init__.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\urllib\\__init__.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
@@ -2365,7 +2367,9 @@
|
|||||||
('uuid',
|
('uuid',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\uuid.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\uuid.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('version', 'D:\\file\\kefu\\douyin-login-launcher\\version.py', 'PYMODULE'),
|
('version',
|
||||||
|
'D:\\file\\douyin\\douyin-login-launcher\\version.py',
|
||||||
|
'PYMODULE'),
|
||||||
('webbrowser',
|
('webbrowser',
|
||||||
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\webbrowser.py',
|
'C:\\Users\\pc\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\webbrowser.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
|
|||||||
Binary file not shown.
@@ -15,11 +15,8 @@ IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
|
|||||||
tracking down the missing module yourself. Thanks!
|
tracking down the missing module yourself. Thanks!
|
||||||
|
|
||||||
missing module named pyimod02_importers - imported by C:\Users\pc\AppData\Local\Programs\Python\Python311\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py (delayed), C:\Users\pc\AppData\Local\Programs\Python\Python311\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgres.py (delayed)
|
missing module named pyimod02_importers - imported by C:\Users\pc\AppData\Local\Programs\Python\Python311\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py (delayed), C:\Users\pc\AppData\Local\Programs\Python\Python311\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgres.py (delayed)
|
||||||
missing module named 'org.python' - imported by copy (optional), xml.sax (delayed, conditional)
|
missing module named org - imported by copy (optional)
|
||||||
missing module named org - imported by pickle (optional)
|
missing module named 'org.python' - imported by pickle (optional), xml.sax (delayed, conditional)
|
||||||
missing module named urllib.unquote - imported by urllib (conditional), bottle (conditional)
|
|
||||||
missing module named urllib.quote - imported by urllib (conditional), bottle (conditional)
|
|
||||||
missing module named urllib.urlencode - imported by urllib (conditional), bottle (conditional)
|
|
||||||
missing module named pwd - imported by posixpath (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional), subprocess (delayed, conditional, optional), http.server (delayed, optional), webbrowser (delayed), distutils.util (delayed, conditional, optional), distutils.archive_util (optional), netrc (delayed, conditional), getpass (delayed), setuptools._distutils.archive_util (optional), setuptools._distutils.util (delayed, conditional, optional)
|
missing module named pwd - imported by posixpath (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional), subprocess (delayed, conditional, optional), http.server (delayed, optional), webbrowser (delayed), distutils.util (delayed, conditional, optional), distutils.archive_util (optional), netrc (delayed, conditional), getpass (delayed), setuptools._distutils.archive_util (optional), setuptools._distutils.util (delayed, conditional, optional)
|
||||||
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional), subprocess (delayed, conditional, optional), distutils.archive_util (optional), setuptools._distutils.archive_util (optional)
|
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional), subprocess (delayed, conditional, optional), distutils.archive_util (optional), setuptools._distutils.archive_util (optional)
|
||||||
missing module named posix - imported by os (conditional, optional), posixpath (optional), shutil (conditional), importlib._bootstrap_external (conditional)
|
missing module named posix - imported by os (conditional, optional), posixpath (optional), shutil (conditional), importlib._bootstrap_external (conditional)
|
||||||
@@ -42,7 +39,6 @@ missing module named _winreg - imported by platform (delayed, optional), pkg_res
|
|||||||
missing module named pkg_resources.extern.packaging - imported by pkg_resources.extern (top-level), pkg_resources (top-level)
|
missing module named pkg_resources.extern.packaging - imported by pkg_resources.extern (top-level), pkg_resources (top-level)
|
||||||
missing module named pkg_resources.extern.appdirs - imported by pkg_resources.extern (top-level), pkg_resources (top-level)
|
missing module named pkg_resources.extern.appdirs - imported by pkg_resources.extern (top-level), pkg_resources (top-level)
|
||||||
missing module named 'pkg_resources.extern.jaraco' - imported by pkg_resources (top-level), pkg_resources._vendor.jaraco.text (top-level)
|
missing module named 'pkg_resources.extern.jaraco' - imported by pkg_resources (top-level), pkg_resources._vendor.jaraco.text (top-level)
|
||||||
missing module named _scproxy - imported by urllib.request (conditional)
|
|
||||||
missing module named 'java.lang' - imported by platform (delayed, optional), xml.sax._exceptions (conditional)
|
missing module named 'java.lang' - imported by platform (delayed, optional), xml.sax._exceptions (conditional)
|
||||||
missing module named vms_lib - imported by platform (delayed, optional)
|
missing module named vms_lib - imported by platform (delayed, optional)
|
||||||
missing module named java - imported by platform (delayed)
|
missing module named java - imported by platform (delayed)
|
||||||
@@ -104,6 +100,9 @@ missing module named ConfigParser - imported by bottle (conditional)
|
|||||||
missing module named StringIO - imported by bottle (conditional)
|
missing module named StringIO - imported by bottle (conditional)
|
||||||
missing module named cPickle - imported by bottle (conditional)
|
missing module named cPickle - imported by bottle (conditional)
|
||||||
missing module named Cookie - imported by bottle (conditional)
|
missing module named Cookie - imported by bottle (conditional)
|
||||||
|
missing module named urllib.unquote - imported by urllib (conditional), bottle (conditional)
|
||||||
|
missing module named urllib.quote - imported by urllib (conditional), bottle (conditional)
|
||||||
|
missing module named urllib.urlencode - imported by urllib (conditional), bottle (conditional)
|
||||||
missing module named urlparse - imported by bottle (conditional)
|
missing module named urlparse - imported by bottle (conditional)
|
||||||
missing module named thread - imported by bottle (conditional), cffi.lock (conditional, optional), cffi.cparser (conditional, optional), sortedcontainers.sortedlist (conditional, optional)
|
missing module named thread - imported by bottle (conditional), cffi.lock (conditional, optional), cffi.cparser (conditional, optional), sortedcontainers.sortedlist (conditional, optional)
|
||||||
missing module named httplib - imported by bottle (conditional)
|
missing module named httplib - imported by bottle (conditional)
|
||||||
@@ -173,4 +172,5 @@ missing module named collections.Set - imported by collections (optional), sorte
|
|||||||
missing module named collections.MutableSequence - imported by collections (optional), sortedcontainers.sortedlist (optional)
|
missing module named collections.MutableSequence - imported by collections (optional), sortedcontainers.sortedlist (optional)
|
||||||
missing module named _typeshed - imported by trio._file_io (conditional), trio._path (conditional)
|
missing module named _typeshed - imported by trio._file_io (conditional), trio._path (conditional)
|
||||||
missing module named OpenSSL - imported by trio._dtls (delayed, conditional)
|
missing module named OpenSSL - imported by trio._dtls (delayed, conditional)
|
||||||
|
missing module named _scproxy - imported by urllib.request (conditional)
|
||||||
missing module named fcntl - imported by subprocess (optional)
|
missing module named fcntl - imported by subprocess (optional)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
<div class="node">
|
<div class="node">
|
||||||
<a name="desktop_app.py"></a>
|
<a name="desktop_app.py"></a>
|
||||||
<a target="code" href="///D:/file/kefu/douyin-login-launcher/desktop_app.py" type="text/plain"><tt>desktop_app.py</tt></a>
|
<a target="code" href="///D:/file/douyin/douyin-login-launcher/desktop_app.py" type="text/plain"><tt>desktop_app.py</tt></a>
|
||||||
<span class="moduletype">Script</span> <div class="import">
|
<span class="moduletype">Script</span> <div class="import">
|
||||||
imports:
|
imports:
|
||||||
<a href="#__future__">__future__</a>
|
<a href="#__future__">__future__</a>
|
||||||
@@ -262,10 +262,14 @@ imports:
|
|||||||
• <a href="#stat">stat</a>
|
• <a href="#stat">stat</a>
|
||||||
• <a href="#subprocess">subprocess</a>
|
• <a href="#subprocess">subprocess</a>
|
||||||
• <a href="#threading">threading</a>
|
• <a href="#threading">threading</a>
|
||||||
|
• <a href="#time">time</a>
|
||||||
• <a href="#traceback">traceback</a>
|
• <a href="#traceback">traceback</a>
|
||||||
• <a href="#types">types</a>
|
• <a href="#types">types</a>
|
||||||
• <a href="#updater">updater</a>
|
• <a href="#updater">updater</a>
|
||||||
|
• <a href="#urllib">urllib</a>
|
||||||
|
• <a href="#urllib.error">urllib.error</a>
|
||||||
• <a href="#urllib.parse">urllib.parse</a>
|
• <a href="#urllib.parse">urllib.parse</a>
|
||||||
|
• <a href="#urllib.request">urllib.request</a>
|
||||||
• <a href="#version">version</a>
|
• <a href="#version">version</a>
|
||||||
• <a href="#warnings">warnings</a>
|
• <a href="#warnings">warnings</a>
|
||||||
• <a href="#weakref">weakref</a>
|
• <a href="#weakref">weakref</a>
|
||||||
@@ -683,7 +687,7 @@ imported by:
|
|||||||
<a target="code" href="" type="text/plain"><tt>'org.python'</tt></a>
|
<a target="code" href="" type="text/plain"><tt>'org.python'</tt></a>
|
||||||
<span class="moduletype">MissingModule</span> <div class="import">
|
<span class="moduletype">MissingModule</span> <div class="import">
|
||||||
imported by:
|
imported by:
|
||||||
<a href="#copy">copy</a>
|
<a href="#pickle">pickle</a>
|
||||||
• <a href="#xml.sax">xml.sax</a>
|
• <a href="#xml.sax">xml.sax</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -4941,7 +4945,7 @@ imported by:
|
|||||||
|
|
||||||
<div class="node">
|
<div class="node">
|
||||||
<a name="browser_open"></a>
|
<a name="browser_open"></a>
|
||||||
<a target="code" href="///D:/file/kefu/douyin-login-launcher/browser_open.py" type="text/plain"><tt>browser_open</tt></a>
|
<a target="code" href="///D:/file/douyin/douyin-login-launcher/browser_open.py" type="text/plain"><tt>browser_open</tt></a>
|
||||||
<span class="moduletype">SourceModule</span> <div class="import">
|
<span class="moduletype">SourceModule</span> <div class="import">
|
||||||
imports:
|
imports:
|
||||||
<a href="#__future__">__future__</a>
|
<a href="#__future__">__future__</a>
|
||||||
@@ -6783,8 +6787,8 @@ imported by:
|
|||||||
<a target="code" href="///C:/Users/pc/AppData/Local/Programs/Python/Python311/Lib/copy.py" type="text/plain"><tt>copy</tt></a>
|
<a target="code" href="///C:/Users/pc/AppData/Local/Programs/Python/Python311/Lib/copy.py" type="text/plain"><tt>copy</tt></a>
|
||||||
<span class="moduletype">SourceModule</span> <div class="import">
|
<span class="moduletype">SourceModule</span> <div class="import">
|
||||||
imports:
|
imports:
|
||||||
<a href="#'org.python'">'org.python'</a>
|
<a href="#copyreg">copyreg</a>
|
||||||
• <a href="#copyreg">copyreg</a>
|
• <a href="#org">org</a>
|
||||||
• <a href="#types">types</a>
|
• <a href="#types">types</a>
|
||||||
• <a href="#weakref">weakref</a>
|
• <a href="#weakref">weakref</a>
|
||||||
|
|
||||||
@@ -16230,7 +16234,7 @@ imported by:
|
|||||||
<a target="code" href="" type="text/plain"><tt>org</tt></a>
|
<a target="code" href="" type="text/plain"><tt>org</tt></a>
|
||||||
<span class="moduletype">MissingModule</span> <div class="import">
|
<span class="moduletype">MissingModule</span> <div class="import">
|
||||||
imported by:
|
imported by:
|
||||||
<a href="#pickle">pickle</a>
|
<a href="#copy">copy</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -17235,14 +17239,14 @@ imported by:
|
|||||||
<a target="code" href="///C:/Users/pc/AppData/Local/Programs/Python/Python311/Lib/pickle.py" type="text/plain"><tt>pickle</tt></a>
|
<a target="code" href="///C:/Users/pc/AppData/Local/Programs/Python/Python311/Lib/pickle.py" type="text/plain"><tt>pickle</tt></a>
|
||||||
<span class="moduletype">SourceModule</span> <div class="import">
|
<span class="moduletype">SourceModule</span> <div class="import">
|
||||||
imports:
|
imports:
|
||||||
<a href="#_compat_pickle">_compat_pickle</a>
|
<a href="#'org.python'">'org.python'</a>
|
||||||
|
• <a href="#_compat_pickle">_compat_pickle</a>
|
||||||
• <a href="#_pickle">_pickle</a>
|
• <a href="#_pickle">_pickle</a>
|
||||||
• <a href="#codecs">codecs</a>
|
• <a href="#codecs">codecs</a>
|
||||||
• <a href="#copyreg">copyreg</a>
|
• <a href="#copyreg">copyreg</a>
|
||||||
• <a href="#functools">functools</a>
|
• <a href="#functools">functools</a>
|
||||||
• <a href="#io">io</a>
|
• <a href="#io">io</a>
|
||||||
• <a href="#itertools">itertools</a>
|
• <a href="#itertools">itertools</a>
|
||||||
• <a href="#org">org</a>
|
|
||||||
• <a href="#pprint">pprint</a>
|
• <a href="#pprint">pprint</a>
|
||||||
• <a href="#re">re</a>
|
• <a href="#re">re</a>
|
||||||
• <a href="#struct">struct</a>
|
• <a href="#struct">struct</a>
|
||||||
@@ -27029,6 +27033,7 @@ imported by:
|
|||||||
• <a href="#browser_open">browser_open</a>
|
• <a href="#browser_open">browser_open</a>
|
||||||
• <a href="#concurrent.futures._base">concurrent.futures._base</a>
|
• <a href="#concurrent.futures._base">concurrent.futures._base</a>
|
||||||
• <a href="#datetime">datetime</a>
|
• <a href="#datetime">datetime</a>
|
||||||
|
• <a href="#desktop_app.py">desktop_app.py</a>
|
||||||
• <a href="#email._parseaddr">email._parseaddr</a>
|
• <a href="#email._parseaddr">email._parseaddr</a>
|
||||||
• <a href="#email.generator">email.generator</a>
|
• <a href="#email.generator">email.generator</a>
|
||||||
• <a href="#email.utils">email.utils</a>
|
• <a href="#email.utils">email.utils</a>
|
||||||
@@ -30095,7 +30100,7 @@ imported by:
|
|||||||
|
|
||||||
<div class="node">
|
<div class="node">
|
||||||
<a name="updater"></a>
|
<a name="updater"></a>
|
||||||
<a target="code" href="///D:/file/kefu/douyin-login-launcher/updater.py" type="text/plain"><tt>updater</tt></a>
|
<a target="code" href="///D:/file/douyin/douyin-login-launcher/updater.py" type="text/plain"><tt>updater</tt></a>
|
||||||
<span class="moduletype">SourceModule</span> <div class="import">
|
<span class="moduletype">SourceModule</span> <div class="import">
|
||||||
imports:
|
imports:
|
||||||
<a href="#__future__">__future__</a>
|
<a href="#__future__">__future__</a>
|
||||||
@@ -30129,6 +30134,7 @@ imports:
|
|||||||
<div class="import">
|
<div class="import">
|
||||||
imported by:
|
imported by:
|
||||||
<a href="#bottle">bottle</a>
|
<a href="#bottle">bottle</a>
|
||||||
|
• <a href="#desktop_app.py">desktop_app.py</a>
|
||||||
• <a href="#email._header_value_parser">email._header_value_parser</a>
|
• <a href="#email._header_value_parser">email._header_value_parser</a>
|
||||||
• <a href="#playwright._impl._network">playwright._impl._network</a>
|
• <a href="#playwright._impl._network">playwright._impl._network</a>
|
||||||
• <a href="#updater">updater</a>
|
• <a href="#updater">updater</a>
|
||||||
@@ -30153,7 +30159,8 @@ imports:
|
|||||||
</div>
|
</div>
|
||||||
<div class="import">
|
<div class="import">
|
||||||
imported by:
|
imported by:
|
||||||
<a href="#urllib.request">urllib.request</a>
|
<a href="#desktop_app.py">desktop_app.py</a>
|
||||||
|
• <a href="#urllib.request">urllib.request</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -30263,6 +30270,7 @@ imports:
|
|||||||
imported by:
|
imported by:
|
||||||
<a href="#PyInstaller.lib.modulegraph.modulegraph">PyInstaller.lib.modulegraph.modulegraph</a>
|
<a href="#PyInstaller.lib.modulegraph.modulegraph">PyInstaller.lib.modulegraph.modulegraph</a>
|
||||||
• <a href="#clr_loader.util.coreclr_errors">clr_loader.util.coreclr_errors</a>
|
• <a href="#clr_loader.util.coreclr_errors">clr_loader.util.coreclr_errors</a>
|
||||||
|
• <a href="#desktop_app.py">desktop_app.py</a>
|
||||||
• <a href="#http.cookiejar">http.cookiejar</a>
|
• <a href="#http.cookiejar">http.cookiejar</a>
|
||||||
• <a href="#setuptools._distutils.command.register">setuptools._distutils.command.register</a>
|
• <a href="#setuptools._distutils.command.register">setuptools._distutils.command.register</a>
|
||||||
• <a href="#setuptools._distutils.command.upload">setuptools._distutils.command.upload</a>
|
• <a href="#setuptools._distutils.command.upload">setuptools._distutils.command.upload</a>
|
||||||
@@ -30385,7 +30393,7 @@ imported by:
|
|||||||
|
|
||||||
<div class="node">
|
<div class="node">
|
||||||
<a name="version"></a>
|
<a name="version"></a>
|
||||||
<a target="code" href="///D:/file/kefu/douyin-login-launcher/version.py" type="text/plain"><tt>version</tt></a>
|
<a target="code" href="///D:/file/douyin/douyin-login-launcher/version.py" type="text/plain"><tt>version</tt></a>
|
||||||
<span class="moduletype">SourceModule</span> <div class="import">
|
<span class="moduletype">SourceModule</span> <div class="import">
|
||||||
imported by:
|
imported by:
|
||||||
<a href="#desktop_app.py">desktop_app.py</a>
|
<a href="#desktop_app.py">desktop_app.py</a>
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
"""抖音托管客服 · 桌面整合版
|
"""抖音托管客服 · 桌面整合版
|
||||||
|
|
||||||
一个软件搞定一切:
|
一个软件搞定一切:
|
||||||
1) 启动后默认打开云端网站(dev.zhenyangtang.com.cn);
|
1) 启动后先显示「站点选择」界面(内置 dev / dev1,可自行添加更多站点,
|
||||||
2) 页面右下角自动出现「一键本地登录」悬浮按钮;
|
可勾选“记住选择”下次直接进入);
|
||||||
3) 点它 → 弹出你的托管账号列表 → 选一个 → 本机直接打开一个
|
2) 进入站点后,页面右下角自动出现「一键本地登录」悬浮按钮,
|
||||||
已登录该托管账号的浏览器,进入抖音。
|
以及「切换站点」按钮可随时换环境;
|
||||||
|
3) 点「一键本地登录」→ 弹出你的托管账号列表 → 选一个 → 本机直接打开
|
||||||
|
一个已登录该托管账号的浏览器,进入抖音。
|
||||||
|
|
||||||
原理:桌面壳(pywebview)把云端网页装进原生窗口,并注入一段脚本。该脚本
|
原理:桌面壳(pywebview)把云端网页装进原生窗口,并注入一段脚本。该脚本
|
||||||
用网页里已有的登录令牌(localStorage.kefu_token)调用云端接口取账号与凭证,
|
用网页里已有的登录令牌(localStorage.kefu_token)调用云端接口取账号与凭证,
|
||||||
@@ -18,6 +20,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import ctypes
|
import ctypes
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import threading
|
import threading
|
||||||
@@ -29,10 +32,276 @@ from browser_open import normalize_storage_state, open_logged_in_browser
|
|||||||
from updater import check_update, download_installer
|
from updater import check_update, download_installer
|
||||||
from version import __version__
|
from version import __version__
|
||||||
|
|
||||||
CLOUD_URL = "https://dev.zhenyangtang.com.cn/"
|
|
||||||
CLOUD_HOST = urlparse(CLOUD_URL).hostname or ""
|
|
||||||
WINDOW_TITLE = f"抖音托管客服 · 桌面版 v{__version__}"
|
WINDOW_TITLE = f"抖音托管客服 · 桌面版 v{__version__}"
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# 多站点配置:内置站点 + 用户自定义站点(保存在用户目录,升级软件不丢失)。
|
||||||
|
# 以后要新增内置环境,往 BUILTIN_SITES 里加一行即可。
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
BUILTIN_SITES = [
|
||||||
|
{"name": "节点1", "url": "https://dev.zhenyangtang.com.cn/"},
|
||||||
|
{"name": "节点2", "url": "https://dev1.zhenyangtang.com.cn/"},
|
||||||
|
]
|
||||||
|
CONFIG_PATH = os.path.join(os.path.expanduser("~"), ".douyin_desktop_config.json")
|
||||||
|
|
||||||
|
|
||||||
|
def load_config() -> dict:
|
||||||
|
try:
|
||||||
|
with open(CONFIG_PATH, "r", encoding="utf-8") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
return data if isinstance(data, dict) else {}
|
||||||
|
except Exception: # noqa: BLE001
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
def save_config(cfg: dict) -> None:
|
||||||
|
try:
|
||||||
|
with open(CONFIG_PATH, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(cfg, f, ensure_ascii=False, indent=2)
|
||||||
|
except Exception: # noqa: BLE001
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_site_url(url: str) -> str:
|
||||||
|
url = (url or "").strip()
|
||||||
|
if not url:
|
||||||
|
return ""
|
||||||
|
if not url.startswith(("http://", "https://")):
|
||||||
|
url = "https://" + url
|
||||||
|
if not url.endswith("/"):
|
||||||
|
url += "/"
|
||||||
|
return url
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_sites() -> list[dict]:
|
||||||
|
"""内置站点 + 自定义站点(去重,按 URL)。"""
|
||||||
|
cfg = load_config()
|
||||||
|
sites: list[dict] = []
|
||||||
|
seen: set[str] = set()
|
||||||
|
for s in BUILTIN_SITES:
|
||||||
|
u = normalize_site_url(s["url"])
|
||||||
|
sites.append({"name": s["name"], "url": u, "builtin": True})
|
||||||
|
seen.add(u)
|
||||||
|
for s in cfg.get("custom_sites", []):
|
||||||
|
u = normalize_site_url(s.get("url", ""))
|
||||||
|
if u and u not in seen:
|
||||||
|
sites.append({"name": s.get("name") or urlparse(u).hostname, "url": u, "builtin": False})
|
||||||
|
seen.add(u)
|
||||||
|
return sites
|
||||||
|
|
||||||
|
|
||||||
|
def site_hosts() -> set[str]:
|
||||||
|
return {urlparse(s["url"]).hostname or "" for s in get_all_sites()} - {""}
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# 站点选择界面(软件启动首页)。与注入浮层同一套视觉语言:#fe2c55 主色 + 玻璃拟态。
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
PICKER_HTML = r"""<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>选择站点</title>
|
||||||
|
<style>
|
||||||
|
*{box-sizing:border-box;margin:0;padding:0;
|
||||||
|
font-family:'PingFang SC','Microsoft YaHei',system-ui,-apple-system,'Segoe UI',sans-serif;}
|
||||||
|
html,body{height:100%;}
|
||||||
|
body{display:flex;align-items:center;justify-content:center;padding:28px;
|
||||||
|
background:#0f1023;
|
||||||
|
background-image:radial-gradient(900px 500px at 15% -10%,rgba(254,44,85,.28),transparent 60%),
|
||||||
|
radial-gradient(800px 500px at 110% 110%,rgba(99,102,241,.25),transparent 60%);}
|
||||||
|
.card{width:520px;max-width:100%;max-height:92vh;display:flex;flex-direction:column;
|
||||||
|
background:rgba(255,255,255,.06);backdrop-filter:blur(24px);-webkit-backdrop-filter:blur(24px);
|
||||||
|
border:1px solid rgba(255,255,255,.14);border-radius:20px;overflow:hidden;
|
||||||
|
box-shadow:0 30px 80px rgba(0,0,0,.45);}
|
||||||
|
.head{padding:26px 28px 18px;}
|
||||||
|
.brand{display:flex;align-items:center;gap:12px;}
|
||||||
|
.logo{width:42px;height:42px;border-radius:12px;flex:none;display:flex;align-items:center;justify-content:center;
|
||||||
|
background:linear-gradient(135deg,#fe2c55,#ff7a59);box-shadow:0 8px 20px rgba(254,44,85,.4);}
|
||||||
|
.logo svg{width:22px;height:22px;color:#fff;}
|
||||||
|
h1{font-size:18px;font-weight:600;color:#fff;line-height:1.3;}
|
||||||
|
.sub{margin-top:3px;font-size:12.5px;color:rgba(255,255,255,.55);}
|
||||||
|
.body{padding:4px 20px 8px;overflow:auto;}
|
||||||
|
.site{display:flex;align-items:center;gap:12px;width:100%;text-align:left;
|
||||||
|
padding:13px 14px;margin-bottom:10px;border:1px solid rgba(255,255,255,.12);
|
||||||
|
border-radius:14px;background:rgba(255,255,255,.04);cursor:pointer;
|
||||||
|
transition:border-color .18s ease,background .18s ease,transform .18s ease;}
|
||||||
|
.site:hover{border-color:#fe2c55;background:rgba(254,44,85,.12);transform:translateY(-1px);}
|
||||||
|
.site:focus-visible{outline:2px solid #fe2c55;outline-offset:2px;}
|
||||||
|
.dot{width:36px;height:36px;border-radius:10px;flex:none;display:flex;align-items:center;justify-content:center;
|
||||||
|
background:rgba(255,255,255,.08);color:rgba(255,255,255,.85);font-weight:600;font-size:15px;}
|
||||||
|
.site:hover .dot{background:rgba(254,44,85,.9);color:#fff;}
|
||||||
|
.si{flex:1;min-width:0;}
|
||||||
|
.sn{font-size:14.5px;font-weight:600;color:#fff;display:flex;align-items:center;gap:8px;}
|
||||||
|
.tag{font-size:10.5px;font-weight:500;padding:1px 7px;border-radius:999px;
|
||||||
|
background:rgba(255,255,255,.1);color:rgba(255,255,255,.6);}
|
||||||
|
.su{margin-top:3px;font-size:12px;color:rgba(255,255,255,.5);
|
||||||
|
white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
|
||||||
|
.ping{flex:none;display:inline-flex;align-items:center;gap:5px;padding:3px 9px;
|
||||||
|
border-radius:999px;font-size:11px;font-weight:500;
|
||||||
|
background:rgba(255,255,255,.08);color:rgba(255,255,255,.55);}
|
||||||
|
.ping i{width:7px;height:7px;border-radius:50%;background:rgba(255,255,255,.35);flex:none;}
|
||||||
|
.ping.fast{background:rgba(34,197,94,.15);color:#4ade80;}
|
||||||
|
.ping.fast i{background:#22c55e;}
|
||||||
|
.ping.mid{background:rgba(245,158,11,.15);color:#fbbf24;}
|
||||||
|
.ping.mid i{background:#f59e0b;}
|
||||||
|
.ping.slow{background:rgba(239,68,68,.15);color:#f87171;}
|
||||||
|
.ping.slow i{background:#ef4444;}
|
||||||
|
.ping.fail{background:rgba(239,68,68,.15);color:#f87171;}
|
||||||
|
.ping.fail i{background:#ef4444;}
|
||||||
|
@keyframes blink{50%{opacity:.35;}}
|
||||||
|
.ping.wait i{animation:blink 1s ease infinite;}
|
||||||
|
.arrow{flex:none;color:rgba(255,255,255,.3);transition:color .18s ease,transform .18s ease;}
|
||||||
|
.site:hover .arrow{color:#fff;transform:translateX(2px);}
|
||||||
|
.arrow svg{width:18px;height:18px;display:block;}
|
||||||
|
.del{flex:none;border:none;background:transparent;color:rgba(255,255,255,.35);cursor:pointer;
|
||||||
|
width:28px;height:28px;border-radius:8px;display:flex;align-items:center;justify-content:center;
|
||||||
|
transition:background .18s ease,color .18s ease;}
|
||||||
|
.del:hover{background:rgba(239,68,68,.2);color:#f87171;}
|
||||||
|
.del svg{width:15px;height:15px;}
|
||||||
|
.foot{padding:6px 20px 22px;}
|
||||||
|
.remember{display:flex;align-items:center;gap:8px;padding:6px 2px 14px;
|
||||||
|
font-size:12.5px;color:rgba(255,255,255,.65);cursor:pointer;user-select:none;}
|
||||||
|
.remember input{width:15px;height:15px;accent-color:#fe2c55;cursor:pointer;}
|
||||||
|
.addbar{display:flex;gap:8px;}
|
||||||
|
.addbar input{flex:1;min-width:0;padding:10px 12px;font-size:13px;color:#fff;
|
||||||
|
background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.14);border-radius:10px;outline:none;
|
||||||
|
transition:border-color .18s ease;}
|
||||||
|
.addbar input::placeholder{color:rgba(255,255,255,.35);}
|
||||||
|
.addbar input:focus{border-color:#fe2c55;}
|
||||||
|
.addbar input.name{flex:0 0 120px;}
|
||||||
|
.addbar button{flex:none;padding:10px 16px;font-size:13px;font-weight:600;color:#fff;
|
||||||
|
background:#fe2c55;border:none;border-radius:10px;cursor:pointer;
|
||||||
|
transition:background .18s ease,box-shadow .18s ease;}
|
||||||
|
.addbar button:hover{background:#e0214a;box-shadow:0 6px 18px rgba(254,44,85,.4);}
|
||||||
|
.err{margin-top:8px;font-size:12px;color:#f87171;min-height:16px;}
|
||||||
|
.empty{padding:20px;text-align:center;font-size:13px;color:rgba(255,255,255,.45);}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="card">
|
||||||
|
<div class="head">
|
||||||
|
<div class="brand">
|
||||||
|
<div class="logo"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||||||
|
stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2"/>
|
||||||
|
<line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg></div>
|
||||||
|
<div>
|
||||||
|
<h1>抖音托管客服 · 桌面版</h1>
|
||||||
|
<div class="sub">请选择要进入的站点,也可以在下方添加新站点</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="body" id="list"><div class="empty">正在加载站点…</div></div>
|
||||||
|
<div class="foot">
|
||||||
|
<label class="remember"><input type="checkbox" id="remember">记住选择,下次启动直接进入(可在站点内切换)</label>
|
||||||
|
<div class="addbar">
|
||||||
|
<input class="name" id="addName" placeholder="名称(选填)" maxlength="20">
|
||||||
|
<input id="addUrl" placeholder="https://xxx.zhenyangtang.com.cn/" spellcheck="false">
|
||||||
|
<button id="addBtn">添加</button>
|
||||||
|
</div>
|
||||||
|
<div class="err" id="err"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var CHEV = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>';
|
||||||
|
var X = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>';
|
||||||
|
|
||||||
|
function esc(s) {
|
||||||
|
return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) {
|
||||||
|
return {'&':'&','<':'<','>':'>','"':'"',"'":'''}[c];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function api() { return window.pywebview && window.pywebview.api; }
|
||||||
|
function setErr(msg) { document.getElementById('err').textContent = msg || ''; }
|
||||||
|
|
||||||
|
function pingSite(url, badge) {
|
||||||
|
if (!badge) return;
|
||||||
|
api().ping_site(url).then(function (r) {
|
||||||
|
if (!r || !r.ok) {
|
||||||
|
badge.className = 'ping fail';
|
||||||
|
badge.innerHTML = '<i></i>不可达';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var ms = r.ms;
|
||||||
|
var cls = ms <= 300 ? 'fast' : (ms <= 800 ? 'mid' : 'slow');
|
||||||
|
badge.className = 'ping ' + cls;
|
||||||
|
badge.innerHTML = '<i></i>' + ms + ' ms';
|
||||||
|
}).catch(function () {
|
||||||
|
badge.className = 'ping fail';
|
||||||
|
badge.innerHTML = '<i></i>检测失败';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function render(sites) {
|
||||||
|
var list = document.getElementById('list');
|
||||||
|
if (!sites || !sites.length) {
|
||||||
|
list.innerHTML = '<div class="empty">暂无站点,请在下方添加</div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
list.innerHTML = '';
|
||||||
|
sites.forEach(function (s) {
|
||||||
|
var host = '';
|
||||||
|
try { host = new URL(s.url).hostname; } catch (e) { host = s.url; }
|
||||||
|
var initial = esc((s.name || host || '?').trim().charAt(0).toUpperCase());
|
||||||
|
var el = document.createElement('button');
|
||||||
|
el.className = 'site';
|
||||||
|
el.type = 'button';
|
||||||
|
el.innerHTML = '<span class="dot">' + initial + '</span>'
|
||||||
|
+ '<span class="si"><span class="sn">' + esc(s.name || host)
|
||||||
|
+ (s.builtin ? '<span class="tag">内置</span>' : '') + '</span>'
|
||||||
|
+ '<span class="su">' + esc(s.url) + '</span></span>'
|
||||||
|
+ '<span class="ping wait"><i></i>检测中</span>'
|
||||||
|
+ (s.builtin ? '' : '<span class="del" title="删除该站点" role="button">' + X + '</span>')
|
||||||
|
+ '<span class="arrow">' + CHEV + '</span>';
|
||||||
|
pingSite(s.url, el.querySelector('.ping'));
|
||||||
|
el.addEventListener('click', function (e) {
|
||||||
|
var del = e.target.closest && e.target.closest('.del');
|
||||||
|
if (del) {
|
||||||
|
e.stopPropagation();
|
||||||
|
api().remove_site(s.url).then(function (r) { render(r.sites); });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var remember = document.getElementById('remember').checked;
|
||||||
|
el.style.opacity = '.6';
|
||||||
|
api().open_site(s.url, remember);
|
||||||
|
});
|
||||||
|
list.appendChild(el);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSite() {
|
||||||
|
var name = document.getElementById('addName').value.trim();
|
||||||
|
var url = document.getElementById('addUrl').value.trim();
|
||||||
|
if (!url) { setErr('请填写站点网址'); return; }
|
||||||
|
setErr('');
|
||||||
|
api().add_site(name, url).then(function (r) {
|
||||||
|
if (r.error) { setErr(r.error); return; }
|
||||||
|
document.getElementById('addName').value = '';
|
||||||
|
document.getElementById('addUrl').value = '';
|
||||||
|
render(r.sites);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
api().get_sites().then(function (r) {
|
||||||
|
render(r.sites);
|
||||||
|
document.getElementById('remember').checked = !!r.remember;
|
||||||
|
});
|
||||||
|
document.getElementById('addBtn').addEventListener('click', addSite);
|
||||||
|
document.getElementById('addUrl').addEventListener('keydown', function (e) {
|
||||||
|
if (e.key === 'Enter') addSite();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (api()) init();
|
||||||
|
else window.addEventListener('pywebviewready', init);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
# 注入到云端页面的脚本:加悬浮按钮 + 账号选择浮层,调用本机桥打开浏览器。
|
# 注入到云端页面的脚本:加悬浮按钮 + 账号选择浮层,调用本机桥打开浏览器。
|
||||||
# 设计:Glassmorphism 浮层 + SVG 图标(无 emoji)+ 悬浮过渡 + 可访问性(焦点/Esc/减少动效)。
|
# 设计:Glassmorphism 浮层 + SVG 图标(无 emoji)+ 悬浮过渡 + 可访问性(焦点/Esc/减少动效)。
|
||||||
@@ -47,7 +316,8 @@ INJECT_JS = r"""
|
|||||||
close: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>',
|
close: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>',
|
||||||
chevron: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>',
|
chevron: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>',
|
||||||
monitor: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>',
|
monitor: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>',
|
||||||
alert: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>'
|
alert: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>',
|
||||||
|
swap: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="17 1 21 5 17 9"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/><polyline points="7 23 3 19 7 15"/><path d="M21 13v2a4 4 0 0 1-4 4H3"/></svg>'
|
||||||
};
|
};
|
||||||
|
|
||||||
var ROOT = null; // Shadow root,隔离宿主站点 CSS,避免错位/层级冲突
|
var ROOT = null; // Shadow root,隔离宿主站点 CSS,避免错位/层级冲突
|
||||||
@@ -91,6 +361,16 @@ INJECT_JS = r"""
|
|||||||
.${NS}-btn:focus-visible{outline:3px solid rgba(254,44,85,.4);outline-offset:2px;}
|
.${NS}-btn:focus-visible{outline:3px solid rgba(254,44,85,.4);outline-offset:2px;}
|
||||||
.${NS}-btn svg{width:18px;height:18px;}
|
.${NS}-btn svg{width:18px;height:18px;}
|
||||||
|
|
||||||
|
.${NS}-switch{position:fixed;right:24px;bottom:76px;z-index:2147483646;display:inline-flex;
|
||||||
|
align-items:center;gap:6px;background:rgba(15,23,42,.72);color:#fff;
|
||||||
|
border:1px solid rgba(255,255,255,.18);border-radius:999px;padding:8px 14px 8px 12px;
|
||||||
|
font-size:12.5px;font-weight:500;cursor:pointer;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
|
||||||
|
box-shadow:0 6px 18px rgba(15,23,42,.3);transition:background .2s ease,transform .2s ease;}
|
||||||
|
.${NS}-switch:hover{background:rgba(15,23,42,.88);}
|
||||||
|
.${NS}-switch:active{transform:translateY(1px);}
|
||||||
|
.${NS}-switch:focus-visible{outline:2px solid #fe2c55;outline-offset:2px;}
|
||||||
|
.${NS}-switch svg{width:14px;height:14px;}
|
||||||
|
|
||||||
.${NS}-mask{position:fixed;inset:0;z-index:2147483647;background:rgba(15,23,42,.45);
|
.${NS}-mask{position:fixed;inset:0;z-index:2147483647;background:rgba(15,23,42,.45);
|
||||||
display:flex;align-items:center;justify-content:center;padding:20px;
|
display:flex;align-items:center;justify-content:center;padding:20px;
|
||||||
animation:${NS}-fade .18s ease;}
|
animation:${NS}-fade .18s ease;}
|
||||||
@@ -316,7 +596,7 @@ INJECT_JS = r"""
|
|||||||
|
|
||||||
function ensureButton() {
|
function ensureButton() {
|
||||||
var root = ensureRoot();
|
var root = ensureRoot();
|
||||||
if (root.querySelector('.' + NS + '-btn')) return;
|
if (!root.querySelector('.' + NS + '-btn')) {
|
||||||
var btn = document.createElement('button');
|
var btn = document.createElement('button');
|
||||||
btn.className = NS + '-btn';
|
btn.className = NS + '-btn';
|
||||||
btn.innerHTML = ICON.login + '<span>一键本地登录</span>';
|
btn.innerHTML = ICON.login + '<span>一键本地登录</span>';
|
||||||
@@ -324,6 +604,18 @@ INJECT_JS = r"""
|
|||||||
btn.addEventListener('click', showPanel);
|
btn.addEventListener('click', showPanel);
|
||||||
root.appendChild(btn);
|
root.appendChild(btn);
|
||||||
}
|
}
|
||||||
|
if (!root.querySelector('.' + NS + '-switch')) {
|
||||||
|
var sw = document.createElement('button');
|
||||||
|
sw.className = NS + '-switch';
|
||||||
|
sw.innerHTML = ICON.swap + '<span>切换站点</span>';
|
||||||
|
sw.title = '返回站点选择界面';
|
||||||
|
sw.addEventListener('click', function () {
|
||||||
|
var a = api();
|
||||||
|
if (a && a.go_picker) a.go_picker();
|
||||||
|
});
|
||||||
|
root.appendChild(sw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 供 Python 端回报本地登录错误:右下角弹出可关闭的提示条
|
// 供 Python 端回报本地登录错误:右下角弹出可关闭的提示条
|
||||||
window.__dylNotify = function (msg, ok) {
|
window.__dylNotify = function (msg, ok) {
|
||||||
@@ -415,6 +707,76 @@ class Api:
|
|||||||
self._window = None
|
self._window = None
|
||||||
self._update_info: dict | None = None
|
self._update_info: dict | None = None
|
||||||
|
|
||||||
|
# ---- 站点选择 ----
|
||||||
|
def get_sites(self) -> dict:
|
||||||
|
cfg = load_config()
|
||||||
|
return {"sites": get_all_sites(), "remember": bool(cfg.get("default_url"))}
|
||||||
|
|
||||||
|
def add_site(self, name: str, url: str) -> dict:
|
||||||
|
u = normalize_site_url(url)
|
||||||
|
host = urlparse(u).hostname if u else None
|
||||||
|
if not u or not host or "." not in host:
|
||||||
|
return {"error": "网址格式不对,示例:https://dev1.zhenyangtang.com.cn/", "sites": get_all_sites()}
|
||||||
|
if any(s["url"] == u for s in get_all_sites()):
|
||||||
|
return {"error": "该站点已存在", "sites": get_all_sites()}
|
||||||
|
cfg = load_config()
|
||||||
|
custom = cfg.get("custom_sites", [])
|
||||||
|
custom.append({"name": (name or "").strip() or host, "url": u})
|
||||||
|
cfg["custom_sites"] = custom
|
||||||
|
save_config(cfg)
|
||||||
|
return {"sites": get_all_sites()}
|
||||||
|
|
||||||
|
def remove_site(self, url: str) -> dict:
|
||||||
|
u = normalize_site_url(url)
|
||||||
|
cfg = load_config()
|
||||||
|
cfg["custom_sites"] = [
|
||||||
|
s for s in cfg.get("custom_sites", []) if normalize_site_url(s.get("url", "")) != u
|
||||||
|
]
|
||||||
|
if normalize_site_url(cfg.get("default_url", "")) == u:
|
||||||
|
cfg.pop("default_url", None)
|
||||||
|
save_config(cfg)
|
||||||
|
return {"sites": get_all_sites()}
|
||||||
|
|
||||||
|
def ping_site(self, url: str) -> dict:
|
||||||
|
"""测量站点响应时间(毫秒)。服务器有响应即算可达,包括 4xx/5xx。"""
|
||||||
|
import time
|
||||||
|
from urllib import error as _err, request as _req
|
||||||
|
|
||||||
|
u = normalize_site_url(url)
|
||||||
|
if not u:
|
||||||
|
return {"ok": False}
|
||||||
|
req = _req.Request(u, method="HEAD", headers={"User-Agent": "Mozilla/5.0"})
|
||||||
|
start = time.perf_counter()
|
||||||
|
try:
|
||||||
|
with _req.urlopen(req, timeout=8):
|
||||||
|
pass
|
||||||
|
except _err.HTTPError:
|
||||||
|
pass # 服务器已响应(如 403/405),延迟有效
|
||||||
|
except Exception: # noqa: BLE001
|
||||||
|
return {"ok": False}
|
||||||
|
return {"ok": True, "ms": int((time.perf_counter() - start) * 1000)}
|
||||||
|
|
||||||
|
def open_site(self, url: str, remember: bool = False) -> dict:
|
||||||
|
u = normalize_site_url(url)
|
||||||
|
cfg = load_config()
|
||||||
|
if remember:
|
||||||
|
cfg["default_url"] = u
|
||||||
|
else:
|
||||||
|
cfg.pop("default_url", None)
|
||||||
|
save_config(cfg)
|
||||||
|
if self._window:
|
||||||
|
self._window.load_url(u)
|
||||||
|
return {"ok": True}
|
||||||
|
|
||||||
|
def go_picker(self) -> dict:
|
||||||
|
"""从站点页面返回选择界面,并取消“记住选择”。"""
|
||||||
|
cfg = load_config()
|
||||||
|
cfg.pop("default_url", None)
|
||||||
|
save_config(cfg)
|
||||||
|
if self._window:
|
||||||
|
self._window.load_html(PICKER_HTML)
|
||||||
|
return {"ok": True}
|
||||||
|
|
||||||
# ---- 本地登录 ----
|
# ---- 本地登录 ----
|
||||||
def _notify(self, msg: str, ok: bool = False) -> None:
|
def _notify(self, msg: str, ok: bool = False) -> None:
|
||||||
if not self._window:
|
if not self._window:
|
||||||
@@ -547,10 +909,23 @@ def _check_update_async(window, api) -> None:
|
|||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
api = Api()
|
api = Api()
|
||||||
# 直接打开云端主界面,更新检测放到后台线程做,避免启动时同步联网卡住窗口。
|
# 上次勾选了“记住选择”则直接进该站点,否则先显示站点选择界面。
|
||||||
|
# 更新检测放到后台线程做,避免启动时同步联网卡住窗口。
|
||||||
|
cfg = load_config()
|
||||||
|
default_url = normalize_site_url(cfg.get("default_url", ""))
|
||||||
|
if default_url and any(s["url"] == default_url for s in get_all_sites()):
|
||||||
window = webview.create_window(
|
window = webview.create_window(
|
||||||
WINDOW_TITLE,
|
WINDOW_TITLE,
|
||||||
CLOUD_URL,
|
default_url,
|
||||||
|
js_api=api,
|
||||||
|
width=1280,
|
||||||
|
height=860,
|
||||||
|
text_select=True,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
window = webview.create_window(
|
||||||
|
WINDOW_TITLE,
|
||||||
|
html=PICKER_HTML,
|
||||||
js_api=api,
|
js_api=api,
|
||||||
width=1280,
|
width=1280,
|
||||||
height=860,
|
height=860,
|
||||||
@@ -560,12 +935,13 @@ def main() -> None:
|
|||||||
_update_checked = {"done": False}
|
_update_checked = {"done": False}
|
||||||
|
|
||||||
def on_loaded():
|
def on_loaded():
|
||||||
# 仅在云端站点页面注入悬浮按钮脚本;about:blank 等不注入。
|
# 仅在已配置站点的页面注入悬浮按钮脚本;选择页/about:blank 等不注入。
|
||||||
try:
|
try:
|
||||||
current = window.get_current_url() or ""
|
current = window.get_current_url() or ""
|
||||||
except Exception: # noqa: BLE001
|
except Exception: # noqa: BLE001
|
||||||
current = ""
|
current = ""
|
||||||
if CLOUD_HOST and CLOUD_HOST in current:
|
host = urlparse(current).hostname or ""
|
||||||
|
if host and host in site_hosts():
|
||||||
try:
|
try:
|
||||||
window.evaluate_js(INJECT_JS)
|
window.evaluate_js(INJECT_JS)
|
||||||
except Exception as e: # noqa: BLE001
|
except Exception as e: # noqa: BLE001
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
@@ -5,4 +5,4 @@
|
|||||||
2) 同步修改 installer.iss 顶部的 AppVersion;
|
2) 同步修改 installer.iss 顶部的 AppVersion;
|
||||||
3) 重新打包,把新的 installer 与 latest.json 上传到服务器 /desktop/ 目录。
|
3) 重新打包,把新的 installer 与 latest.json 上传到服务器 /desktop/ 目录。
|
||||||
"""
|
"""
|
||||||
__version__ = "1.0.0"
|
__version__ = "1.1.0"
|
||||||
|
|||||||
@@ -11,10 +11,15 @@
|
|||||||
【推荐:桌面整合版 desktop_app.py】——一个软件搞定
|
【推荐:桌面整合版 desktop_app.py】——一个软件搞定
|
||||||
====================================================================
|
====================================================================
|
||||||
效果:
|
效果:
|
||||||
打开软件 → 默认加载云端网站 https://dev.zhenyangtang.com.cn/
|
打开软件 → 先显示「站点选择」界面,内置两个站点:
|
||||||
→ 你在里面正常登录后台
|
- 节点1 https://dev.zhenyangtang.com.cn/
|
||||||
→ 页面右下角出现「🚀 一键本地登录」按钮
|
- 节点2 https://dev1.zhenyangtang.com.cn/
|
||||||
→ 点它 → 弹出托管账号列表 → 选一个
|
以后有新环境,可直接在界面下方填名称+网址「添加」(保存在本机,升级不丢)。
|
||||||
|
勾选「记住选择」后,下次启动直接进入该站点,跳过选择页。
|
||||||
|
→ 选一个站点进入 → 你在里面正常登录后台
|
||||||
|
→ 页面右下角出现「一键本地登录」按钮(上方还有「切换站点」按钮,
|
||||||
|
点击可随时返回站点选择界面,并自动取消“记住选择”)
|
||||||
|
→ 点「一键本地登录」→ 弹出托管账号列表 → 选一个
|
||||||
→ 本机直接打开一个“已登录该托管账号”的浏览器进入抖音。
|
→ 本机直接打开一个“已登录该托管账号”的浏览器进入抖音。
|
||||||
|
|
||||||
运行方式一(推荐,无黑窗):
|
运行方式一(推荐,无黑窗):
|
||||||
|
|||||||
@@ -19,18 +19,33 @@ echo [3/4] Building exe (windowed, no cmd window)...
|
|||||||
if errorlevel 1 ( echo [ERROR] PyInstaller build failed & pause & exit /b 1 )
|
if errorlevel 1 ( echo [ERROR] PyInstaller build failed & pause & exit /b 1 )
|
||||||
|
|
||||||
echo [4/4] Building installer...
|
echo [4/4] Building installer...
|
||||||
set "ISCC=%LOCALAPPDATA%\Programs\Inno Setup 6\ISCC.exe"
|
call :find_iscc
|
||||||
if not exist "%ISCC%" set "ISCC=C:\Program Files (x86)\Inno Setup 6\ISCC.exe"
|
if not exist "%ISCC%" (
|
||||||
if not exist "%ISCC%" set "ISCC=C:\Program Files\Inno Setup 6\ISCC.exe"
|
echo [setup] Inno Setup not found; installing via winget...
|
||||||
|
winget install JRSoftware.InnoSetup --accept-source-agreements --accept-package-agreements --silent --disable-interactivity
|
||||||
|
call :find_iscc
|
||||||
|
)
|
||||||
if exist "%ISCC%" (
|
if exist "%ISCC%" (
|
||||||
"%ISCC%" installer.iss
|
"%ISCC%" installer.iss
|
||||||
|
if errorlevel 1 ( echo [ERROR] Installer build failed & pause & exit /b 1 )
|
||||||
echo.
|
echo.
|
||||||
echo [OK] Installer: installer\DouyinHostedDesktop-Setup.exe
|
echo [OK] Installer: installer\DouyinHostedDesktop-Setup.exe
|
||||||
) else (
|
) else (
|
||||||
echo [WARN] Inno Setup not found.
|
echo [ERROR] Inno Setup still not found. Install manually:
|
||||||
echo Install it: winget install JRSoftware.InnoSetup
|
echo winget install JRSoftware.InnoSetup
|
||||||
echo Or just distribute the folder: dist\DouyinDesktop\
|
echo Or just distribute the folder: dist\DouyinDesktop\
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
)
|
)
|
||||||
|
goto :after_installer
|
||||||
|
|
||||||
|
:find_iscc
|
||||||
|
set "ISCC=%LOCALAPPDATA%\Programs\Inno Setup 6\ISCC.exe"
|
||||||
|
if not exist "%ISCC%" set "ISCC=C:\Program Files (x86)\Inno Setup 6\ISCC.exe"
|
||||||
|
if not exist "%ISCC%" set "ISCC=C:\Program Files\Inno Setup 6\ISCC.exe"
|
||||||
|
exit /b 0
|
||||||
|
|
||||||
|
:after_installer
|
||||||
echo.
|
echo.
|
||||||
echo [OK] Portable app folder: dist\DouyinDesktop\ (run DouyinDesktop.exe)
|
echo [OK] Portable app folder: dist\DouyinDesktop\ (run DouyinDesktop.exe)
|
||||||
pause
|
pause
|
||||||
|
|||||||
Reference in New Issue
Block a user