The GitHub stargazer API used by star-history.com has become unreliable. This switches the chart/links in README.md to our alternative instance (star-history.dera.page) which requires no API token and works for both API and frontend on the same domain.
- _focus_desc_editor: locate the description editor with multiple fallback
strategies instead of a single brittle selector; dump page screenshot/HTML
on failure for easier selector updates
- cookie_auth: positive verification via the upload button presence, with
login-page / intro-page / legacy checks as fallbacks
- close_guide_overlay: also remove the Joyride portal and spotlight layers
that intercept clicks
- add collection_name support to KSVideo
- Open homepage first, then click the visible 'publish video' entry
button instead of loading /platform/post/create directly, which gets
bounced back to the homepage and leaves the form iframe un-mounted
- Detect expired cookies up front by watching for the /login.html
redirect and the qrconnect iframe
- Drop the redundant confirm_thumbnail_crop call that caused a 5s
timeout on cover upload
- Select collection by exact name after upload completes (form resets
selections made while the video is still uploading); keep it
unselected when no matching name is found instead of picking a
random one
- Scroll the target option into view and fall back to forced click /
native dispatch for headless visibility issues
- Tighten short-title length to 7~15 chars to pass platform validation
- Dismiss the occasional 'switch account' dialog that blocks the
description box and the publish button
- Set cover via native click with retries; skip gracefully instead of failing the whole order
- Select the collection via its dedicated Semi select with overlay cleanup
- Rewrite self-declaration dialog handling (entry/dialog/option/confirm) and reuse it in upload
- Type description before tags and fill via set_input_files with robust upload input detection
- Keep SMS verification code prompt as a publish-loop guard
- check_original_declaration: replace the original checkbox with the
'来源转载' (repost) declaration flow: open the declaration picker, select
'来源转载', fill the media name, confirm. Falls back to JS click when the
element text is wrapped in non-interactive spans
- set_thumbnail: switch to the '上传封面' tab and target the upload-wrapper
file input instead of the cover-plugin-preview selector; skip gracefully on
failure and let the video first frame be used
cv2.imread cannot open files under non-ASCII (e.g. Chinese) paths on
Windows, so decode_qrcode_from_path() always returned None when the
project lived under a directory like D:\视频全平台同步\, and the
terminal QR re-print silently failed. Use np.fromfile + cv2.imdecode
instead, which handles arbitrary paths.
The WeChat Channels login page now embeds the QR code in an
open.weixin.qq.com/connect/qrconnect iframe whose img.qrcode src is a
relative path (e.g. /connect/qrcode/xxxx) instead of an inline
data:image/ URL. The previous logic looked for a login-for-iframe
frame and only accepted data:image/ sources, so login always failed
with '未获取到视频号登录二维码地址'.
Changes:
- Detect the qrconnect iframe and resolve the relative img src,
download the QR image via the browser context and convert it to a
data URL so downstream save/decode logic stays unchanged
- Keep the legacy login-for-iframe and selector fallbacks
- Tolerate QR extraction failure: the login flow now continues and
lets the user scan directly in the headed browser instead of
aborting the whole login
4 commits squashed into 1 due to force-push via API. See PR #229 body for full description.
Key changes:
- cookie_auth: polling loop (10s) instead of single count() snapshot (race fix)
- cookie_auth: env var DOUYIN_COOKIE_AUTH_HEADLESS for linux server headless override
- _extract_douyin_qrcode_src: 4-tier selector fallback (animate_qrcode_container)
- _wait_for_douyin_login: 2FA detection with warning
- export_douyin_cookie: USERNAME from os.environ
- ks/xiaohongshu uploader: chromium default + cdp_url support for ks
Title and description were typed character-by-character, so a '#'
(e.g. '#Shorts') triggered YouTube's topic-autocomplete dropdown that
follows the caret and covers the Next/Publish buttons, stalling the
upload. Switch to fill() (one-shot insert, no per-keystroke autocomplete)
with a type() fallback, and add _dismiss_autocomplete (blur, then Escape
only when a dropdown is actually visible so the upload dialog is never
closed by mistake).
Same reason as the ks uploader: bundled patchright cannot reliably resolve the system 'chrome' channel on every platform, so use the bundled 'chromium' channel by default and rely on conf.py:LOCAL_CHROME_PATH for users who want real Chrome.
Two related changes for kuaishou uploader:
- Default browser channel is switched from 'chrome' to 'chromium'. The launcher binary that ships with patchright no longer reliably resolves the system Chrome channel on every platform, so falling back to bundled chromium avoids launch-time channel-resolution errors. The user can still force a real Chrome via conf.py:LOCAL_CHROME_PATH.
- New cdp_url parameter on ks_setup / get_ks_cookie. When set, the login flow uses connect_over_cdp() to drive the user's already-running real Chrome instead of spawning a separate browser. This is the supported way around strict anti-bot detection: real Chrome has a fingerprint that passes verification, while the bundled chromium does not. should_close_context tracks ownership so we don't close a context we didn't create.
The shell passed USERNAME as an environment variable to the embedded python heredoc (USERNAME=$USERNAME python3 ...), but the python block referenced USERNAME as if it were already a local variable. The result was NameError on every run, so the export script could never produce a cookies/<platform>_<account>.json file.
Fix: read the env var explicitly with os.environ.get('USERNAME', '') at the top of the embedded block, then use the local USERNAME as before.