- 新增 React + TDesign 管理端(sau_web_react),替代历史 Vue 前端 - 后端接入 11 平台登录/发布(视频+图文),check_cookie 扩展全平台 - 异步发布任务 + 实时进度监控 + 发布日志 - Open API 开放体系(API Key 鉴权 + 7 个开放接口 + API 文档页) - 账号单/批量校验与批量删除 - 全局配置(登录方式 + 发布静默模式) - 统一浏览器为系统 Chrome,品牌文案统一为 EveryPublish
278 lines
12 KiB
Python
278 lines
12 KiB
Python
import asyncio
|
|
from pathlib import Path
|
|
|
|
from conf import BASE_DIR
|
|
from uploader.douyin_uploader.main import DouYinVideo, DouYinNote
|
|
from uploader.ks_uploader.main import KSVideo, KSNote
|
|
from uploader.tencent_uploader.main import TencentVideo, TencentNote
|
|
from uploader.xiaohongshu_uploader.main import XiaoHongShuVideo, XiaoHongShuNote
|
|
from uploader.baijiahao_uploader.main import BaiJiaHaoVideo
|
|
from uploader.alipay_uploader.main import AlipayVideo
|
|
from uploader.weibo_uploader.main import WeiBoVideo
|
|
from uploader.hupu_uploader.main import HuPuVideo
|
|
from uploader.youtube_uploader.main import YouTubeVideo
|
|
from uploader.bilibili_uploader.runtime import run_biliup_command
|
|
from uploader.tk_uploader.main_chrome import TiktokVideo
|
|
from utils.settings import get_bool
|
|
from utils.constant import TencentZoneTypes
|
|
from utils.files_times import generate_schedule_time_next_day
|
|
|
|
|
|
def _publish_headless():
|
|
return get_bool("publish_headless", True)
|
|
|
|
|
|
def _resolve_files(files):
|
|
return [Path(BASE_DIR / "videoFile" / file) for file in files]
|
|
|
|
|
|
def _resolve_cookies(account_file):
|
|
return [Path(BASE_DIR / "cookiesFile" / file) for file in account_file]
|
|
|
|
|
|
def _extract_cover(video_path: Path) -> str | None:
|
|
"""提取视频第一帧作为封面(百家号发布必须提供横版封面)。"""
|
|
try:
|
|
import cv2
|
|
cap = cv2.VideoCapture(str(video_path))
|
|
ret, frame = cap.read()
|
|
cap.release()
|
|
if ret:
|
|
cover = Path(str(video_path) + ".cover.jpg")
|
|
cv2.imwrite(str(cover), frame)
|
|
return str(cover)
|
|
except Exception:
|
|
pass
|
|
return None
|
|
|
|
|
|
def post_video_tencent(title, files, tags, account_file, category=TencentZoneTypes.LIFESTYLE.value, enableTimer=False, videos_per_day=1, daily_times=None, start_days=0, is_draft=False):
|
|
account_file = _resolve_cookies(account_file)
|
|
files = _resolve_files(files)
|
|
if enableTimer:
|
|
publish_datetimes = generate_schedule_time_next_day(len(files), videos_per_day, daily_times, start_days)
|
|
else:
|
|
publish_datetimes = [0 for i in range(len(files))]
|
|
for index, file in enumerate(files):
|
|
for cookie in account_file:
|
|
print(f"视频文件名:{file}")
|
|
print(f"标题:{title}")
|
|
app = TencentVideo(title, str(file), tags, publish_datetimes[index], cookie, category, is_draft, headless=_publish_headless())
|
|
asyncio.run(app.main(), debug=False)
|
|
|
|
|
|
def post_video_DouYin(title, files, tags, account_file, category=TencentZoneTypes.LIFESTYLE.value, enableTimer=False, videos_per_day=1, daily_times=None, start_days=0,
|
|
thumbnail_path='',
|
|
productLink='', productTitle=''):
|
|
account_file = _resolve_cookies(account_file)
|
|
files = _resolve_files(files)
|
|
if enableTimer:
|
|
publish_datetimes = generate_schedule_time_next_day(len(files), videos_per_day, daily_times, start_days)
|
|
else:
|
|
publish_datetimes = [0 for i in range(len(files))]
|
|
for index, file in enumerate(files):
|
|
for cookie in account_file:
|
|
print(f"视频文件名:{file}")
|
|
print(f"标题:{title}")
|
|
app = DouYinVideo(title, str(file), tags, publish_datetimes[index], cookie, thumbnail_path, productLink, productTitle, headless=_publish_headless())
|
|
asyncio.run(app.douyin_upload_video(), debug=False)
|
|
|
|
|
|
def post_video_ks(title, files, tags, account_file, category=TencentZoneTypes.LIFESTYLE.value, enableTimer=False, videos_per_day=1, daily_times=None, start_days=0):
|
|
account_file = _resolve_cookies(account_file)
|
|
files = _resolve_files(files)
|
|
if enableTimer:
|
|
publish_datetimes = generate_schedule_time_next_day(len(files), videos_per_day, daily_times, start_days)
|
|
else:
|
|
publish_datetimes = [0 for i in range(len(files))]
|
|
for index, file in enumerate(files):
|
|
for cookie in account_file:
|
|
print(f"视频文件名:{file}")
|
|
print(f"标题:{title}")
|
|
app = KSVideo(title, str(file), tags, publish_datetimes[index], cookie, headless=_publish_headless())
|
|
asyncio.run(app.main(), debug=False)
|
|
|
|
|
|
def post_video_xhs(title, files, tags, account_file, category=TencentZoneTypes.LIFESTYLE.value, enableTimer=False, videos_per_day=1, daily_times=None, start_days=0):
|
|
account_file = _resolve_cookies(account_file)
|
|
files = _resolve_files(files)
|
|
file_num = len(files)
|
|
if enableTimer:
|
|
publish_datetimes = generate_schedule_time_next_day(file_num, videos_per_day, daily_times, start_days)
|
|
else:
|
|
publish_datetimes = 0
|
|
for index, file in enumerate(files):
|
|
for cookie in account_file:
|
|
print(f"视频文件名:{file}")
|
|
print(f"标题:{title}")
|
|
app = XiaoHongShuVideo(title, file, tags, publish_datetimes, cookie, headless=_publish_headless())
|
|
asyncio.run(app.main(), debug=False)
|
|
|
|
|
|
# ===== 新增:CLI 主线平台接入 Web 后端 =====
|
|
|
|
def post_video_bilibili(title, files, tags, account_file, category=None, enableTimer=False, videos_per_day=1, daily_times=None, start_days=0, desc='', tid=249):
|
|
"""B站视频发布(封装 biliup)。Web 端暂不支持定时(立即发布),定时请用 CLI。"""
|
|
account_file = _resolve_cookies(account_file)
|
|
files = _resolve_files(files)
|
|
for file in files:
|
|
for cookie in account_file:
|
|
args = ["-u", str(cookie), "upload", str(file), "--title", title, "--desc", desc or "", "--tid", str(tid)]
|
|
if tags:
|
|
args.extend(["--tag", ",".join(tags)])
|
|
print(f"biliup 命令: {' '.join(args)}")
|
|
result = run_biliup_command(args)
|
|
if result.returncode != 0:
|
|
raise RuntimeError((result.stderr or result.stdout or "").strip() or "B站上传失败")
|
|
|
|
|
|
def post_video_baijiahao(title, files, tags, account_file, category=None, enableTimer=False, videos_per_day=1, daily_times=None, start_days=0, thumbnail_path='', desc=''):
|
|
account_file = _resolve_cookies(account_file)
|
|
files = _resolve_files(files)
|
|
for file in files:
|
|
cover = thumbnail_path or _extract_cover(file)
|
|
for cookie in account_file:
|
|
app = BaiJiaHaoVideo(
|
|
title=title, file_path=str(file), tags=tags, account_file=str(cookie),
|
|
desc=desc or "", thumbnail_path=cover, collection_name=None, debug=False, headless=_publish_headless(),
|
|
)
|
|
asyncio.run(app.main(), debug=False)
|
|
|
|
|
|
def post_video_alipay(title, files, tags, account_file, category=None, enableTimer=False, videos_per_day=1, daily_times=None, start_days=0, thumbnail_path='', desc=''):
|
|
account_file = _resolve_cookies(account_file)
|
|
files = _resolve_files(files)
|
|
for file in files:
|
|
for cookie in account_file:
|
|
app = AlipayVideo(
|
|
title=title, file_path=str(file), tags=tags, account_file=str(cookie),
|
|
desc=desc or "", thumbnail_path=thumbnail_path or None, collection_name=None, debug=False, headless=_publish_headless(),
|
|
)
|
|
asyncio.run(app.main(), debug=False)
|
|
|
|
|
|
def post_video_weibo(title, files, tags, account_file, category=None, enableTimer=False, videos_per_day=1, daily_times=None, start_days=0, thumbnail_path='', desc=''):
|
|
account_file = _resolve_cookies(account_file)
|
|
files = _resolve_files(files)
|
|
for file in files:
|
|
for cookie in account_file:
|
|
app = WeiBoVideo(
|
|
title=title, file_path=str(file), tags=tags, account_file=str(cookie),
|
|
desc=desc or "", thumbnail_path=thumbnail_path or None, collection_name=None, debug=False, headless=_publish_headless(),
|
|
)
|
|
asyncio.run(app.main(), debug=False)
|
|
|
|
|
|
def post_video_hupu(title, files, tags, account_file, category=None, enableTimer=False, videos_per_day=1, daily_times=None, start_days=0, thumbnail_path='', desc=''):
|
|
account_file = _resolve_cookies(account_file)
|
|
files = _resolve_files(files)
|
|
for file in files:
|
|
for cookie in account_file:
|
|
app = HuPuVideo(
|
|
title=title, file_path=str(file), tags=tags, account_file=str(cookie),
|
|
desc=desc or "", thumbnail_path=thumbnail_path or None, debug=False, headless=_publish_headless(),
|
|
)
|
|
asyncio.run(app.main(), debug=False)
|
|
|
|
|
|
def post_video_youtube(title, files, tags, account_file, category=None, enableTimer=False, videos_per_day=1, daily_times=None, start_days=0, thumbnail_path='', desc=''):
|
|
account_file = _resolve_cookies(account_file)
|
|
files = _resolve_files(files)
|
|
for file in files:
|
|
for cookie in account_file:
|
|
app = YouTubeVideo(
|
|
title, str(file), tags, str(cookie),
|
|
description=desc or "", thumbnail_path=thumbnail_path or None,
|
|
playlist=None, visibility="public", debug=False, headless=_publish_headless(),
|
|
)
|
|
asyncio.run(app.main(), debug=False)
|
|
|
|
def post_video_tiktok(title, files, tags, account_file, category=None, enableTimer=False, videos_per_day=1, daily_times=None, start_days=0, thumbnail_path="", desc=""):
|
|
"""TikTok 视频发布(Chrome 版实现)。支持定时发布与封面(thumbnail)。"""
|
|
account_file = _resolve_cookies(account_file)
|
|
files = _resolve_files(files)
|
|
if enableTimer:
|
|
publish_datetimes = generate_schedule_time_next_day(len(files), videos_per_day, daily_times, start_days)
|
|
else:
|
|
publish_datetimes = [0 for i in range(len(files))]
|
|
for index, file in enumerate(files):
|
|
for cookie in account_file:
|
|
app = TiktokVideo(
|
|
title, str(file), tags, publish_datetimes[index], str(cookie),
|
|
thumbnail_path if thumbnail_path else None,
|
|
)
|
|
app.headless = _publish_headless()
|
|
asyncio.run(app.main(), debug=False)
|
|
|
|
|
|
# ===== 图文(note)发布 —— 小红书/抖音/快手 =====
|
|
|
|
def post_note_xiaohongshu(title, files, tags, account_file, desc=""):
|
|
account_files = _resolve_cookies(account_file)
|
|
image_files = _resolve_files(files)
|
|
for cookie in account_files:
|
|
app = XiaoHongShuNote(
|
|
image_paths=[str(f) for f in image_files],
|
|
note=desc or "",
|
|
tags=tags,
|
|
publish_date=0,
|
|
account_file=str(cookie),
|
|
title=title,
|
|
desc=desc or "",
|
|
debug=False,
|
|
headless=_publish_headless(),
|
|
)
|
|
asyncio.run(app.main(), debug=False)
|
|
|
|
|
|
def post_note_douyin(title, files, tags, account_file, desc=""):
|
|
account_files = _resolve_cookies(account_file)
|
|
image_files = _resolve_files(files)
|
|
for cookie in account_files:
|
|
app = DouYinNote(
|
|
image_paths=[str(f) for f in image_files],
|
|
note=desc or "",
|
|
tags=tags,
|
|
publish_date=0,
|
|
account_file=str(cookie),
|
|
title=title,
|
|
debug=False,
|
|
headless=_publish_headless(),
|
|
)
|
|
asyncio.run(app.douyin_upload_note(), debug=False)
|
|
|
|
|
|
def post_note_kuaishou(title, files, tags, account_file, desc=""):
|
|
account_files = _resolve_cookies(account_file)
|
|
image_files = _resolve_files(files)
|
|
for cookie in account_files:
|
|
app = KSNote(
|
|
image_paths=[str(f) for f in image_files],
|
|
note=desc or "",
|
|
tags=tags,
|
|
publish_date=0,
|
|
account_file=str(cookie),
|
|
title=title,
|
|
debug=False,
|
|
headless=_publish_headless(),
|
|
)
|
|
asyncio.run(app.main(), debug=False)
|
|
|
|
|
|
def post_note_tencent(title, files, tags, account_file, desc="", is_draft=False):
|
|
account_files = _resolve_cookies(account_file)
|
|
image_files = _resolve_files(files)
|
|
for cookie in account_files:
|
|
app = TencentNote(
|
|
image_paths=[str(f) for f in image_files],
|
|
note=desc or "",
|
|
tags=tags,
|
|
publish_date=0,
|
|
account_file=str(cookie),
|
|
title=title,
|
|
debug=False,
|
|
headless=_publish_headless(),
|
|
is_draft=is_draft,
|
|
)
|
|
asyncio.run(app.main(), debug=False)
|