fix(youtube): wait for upload to finish before publishing; add optional proxy
- Wait until the upload progress reaches 100% before clicking publish. The browser-based upload only progresses while the page is open, so publishing (and closing the browser) mid-upload cut it off and left the video stuck partway (e.g. 76%). - Add optional YT_PROXY (conf.py): where youtube.com is blocked, direct connections time out and the chromium does not use the system proxy, so allow pointing it at a local proxy explicitly.
This commit is contained in:
@@ -187,6 +187,8 @@ sau youtube upload-video --account <account_name> --file videos/demo.mp4 --title
|
||||
> 是因为**未通过 Google 合规审核的 API 项目上传的视频会被强制锁为私享、无法改公开**,对个人/单频道不实用;
|
||||
> 浏览器自动化没有此限制,可直接发布公开视频,也与本项目其它平台的 cookie 方案一致。
|
||||
> `--playlist` 适合连载/系列追更;`--visibility` 可选 `public`/`unlisted`/`private`。
|
||||
> 上传会**等进度到 100% 再点发布**(浏览器上传靠窗口开着传,传一半就发布会被掐断卡在中途)。
|
||||
> youtube.com 被墙的地区:在 `conf.py` 设 `YT_PROXY = "http://127.0.0.1:7890"`(chromium 不吃系统代理,需显式指定)。
|
||||
|
||||
补充说明:
|
||||
|
||||
|
||||
@@ -5,3 +5,7 @@ XHS_SERVER = "http://127.0.0.1:11901" # only used by xhs-related flows
|
||||
LOCAL_CHROME_PATH = "" # optional, e.g. C:/Program Files/Google/Chrome/Application/chrome.exe
|
||||
LOCAL_CHROME_HEADLESS = True # default headless behavior for uploader/examples
|
||||
DEBUG_MODE = True # default debug behavior
|
||||
# Optional proxy for the YouTube uploader. Where youtube.com is blocked, direct
|
||||
# connections time out and the (patchright) chromium does NOT use the system proxy.
|
||||
# Point this at your local proxy port, e.g. "http://127.0.0.1:7890". None = no proxy.
|
||||
YT_PROXY = None
|
||||
|
||||
@@ -21,6 +21,13 @@ from uploader.base_video import BaseVideoUploader
|
||||
from utils.base_social_media import set_init_script
|
||||
from utils.log import youtube_logger
|
||||
|
||||
try:
|
||||
# 国内直连 youtube.com 会超时,且 patchright 启的 chromium 不吃系统代理。
|
||||
# 在 conf.py 设 YT_PROXY = "http://127.0.0.1:7890"(本地代理端口)即可;不设则不走代理。
|
||||
from conf import YT_PROXY
|
||||
except Exception:
|
||||
YT_PROXY = None
|
||||
|
||||
STUDIO_URL = "https://studio.youtube.com"
|
||||
UPLOAD_URL = "https://www.youtube.com/upload"
|
||||
VISIBILITY = {"public": "PUBLIC", "unlisted": "UNLISTED", "private": "PRIVATE"}
|
||||
@@ -121,6 +128,34 @@ async def _click_if_present(page: Page, selector: str, timeout: int = 4000) -> b
|
||||
return False
|
||||
|
||||
|
||||
async def _wait_upload_complete(page: Page, max_polls: int = 360) -> bool:
|
||||
"""等网页上传从 X% 跑到 100% 再发布。浏览器上传靠窗口开着才传得完,
|
||||
若上传到一半就点发布并关闭浏览器,上传会被掐断卡在中途(如 76%)。
|
||||
出现“处理/检查/上传完成”或不再“正在上传”即视为传完。max_polls*5s=30min 上限。"""
|
||||
last = ""
|
||||
for _ in range(max_polls):
|
||||
txt = ""
|
||||
for sel in (".progress-label", "span.progress-label", "ytcp-video-upload-progress"):
|
||||
loc = page.locator(sel).first
|
||||
try:
|
||||
if await loc.count():
|
||||
txt = (await loc.inner_text()).strip()
|
||||
if txt:
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
if txt:
|
||||
if any(k in txt for k in ("处理", "检查", "上传完成", "已上传", "Processing", "complete", "Checks", "Finished")):
|
||||
youtube_logger.info(_msg("✅", f"上传完成: {txt[:40]}"))
|
||||
return True
|
||||
if txt != last:
|
||||
youtube_logger.info(_msg("⏳", f"上传中: {txt[:40]}"))
|
||||
last = txt
|
||||
await page.wait_for_timeout(5000)
|
||||
youtube_logger.warning(_msg("⚠️", "等上传超时(30min),仍尝试发布"))
|
||||
return False
|
||||
|
||||
|
||||
class YouTubeVideo(BaseVideoUploader):
|
||||
def __init__(self, title, file_path, tags, account_file, *,
|
||||
description="", thumbnail_path=None, playlist=None,
|
||||
@@ -137,7 +172,10 @@ class YouTubeVideo(BaseVideoUploader):
|
||||
self.headless = headless
|
||||
|
||||
async def upload(self, playwright: Playwright) -> None:
|
||||
browser = await playwright.chromium.launch(headless=self.headless, channel="chrome")
|
||||
browser = await playwright.chromium.launch(
|
||||
headless=self.headless, channel="chrome",
|
||||
proxy={"server": YT_PROXY} if YT_PROXY else None,
|
||||
)
|
||||
context = await browser.new_context(storage_state=self.account_file)
|
||||
context = await set_init_script(context)
|
||||
page = await context.new_page()
|
||||
@@ -235,6 +273,11 @@ class YouTubeVideo(BaseVideoUploader):
|
||||
youtube_logger.info(_msg("🌐", f"设置可见性 = {self.visibility}"))
|
||||
await _click_if_present(page, f"tp-yt-paper-radio-button[name='{VISIBILITY[self.visibility]}']", 10000)
|
||||
|
||||
# 10.5) 关键:等上传真正传完再发布。浏览器上传靠窗口开着传,
|
||||
# 传到一半就点发布+关浏览器 = 上传被掐断卡在中途(如 76%)。
|
||||
youtube_logger.info(_msg("📤", "等待上传完成(传完才发布)…"))
|
||||
await _wait_upload_complete(page)
|
||||
|
||||
# 11) 发布
|
||||
await page.wait_for_timeout(1200)
|
||||
if not await _click_if_present(page, "#done-button", 15000):
|
||||
|
||||
Reference in New Issue
Block a user