Files
Qiufeng fd944b08bd feat: EveryPublish Web 管理端重构与全平台发布接入
- 新增 React + TDesign 管理端(sau_web_react),替代历史 Vue 前端
- 后端接入 11 平台登录/发布(视频+图文),check_cookie 扩展全平台
- 异步发布任务 + 实时进度监控 + 发布日志
- Open API 开放体系(API Key 鉴权 + 7 个开放接口 + API 文档页)
- 账号单/批量校验与批量删除
- 全局配置(登录方式 + 发布静默模式)
- 统一浏览器为系统 Chrome,品牌文案统一为 EveryPublish
2026-08-21 14:41:47 +08:00

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)