feat: EveryPublish Web 管理端重构与全平台发布接入
- 新增 React + TDesign 管理端(sau_web_react),替代历史 Vue 前端 - 后端接入 11 平台登录/发布(视频+图文),check_cookie 扩展全平台 - 异步发布任务 + 实时进度监控 + 发布日志 - Open API 开放体系(API Key 鉴权 + 7 个开放接口 + API 文档页) - 账号单/批量校验与批量删除 - 全局配置(登录方式 + 发布静默模式) - 统一浏览器为系统 Chrome,品牌文案统一为 EveryPublish
This commit is contained in:
@@ -116,6 +116,31 @@ async def check_cookie(type, file_path):
|
||||
# 快手
|
||||
case 4:
|
||||
return await cookie_auth_ks(Path(BASE_DIR / "cookiesFile" / file_path))
|
||||
case 5:
|
||||
from uploader.bilibili_uploader.runtime import run_biliup_command
|
||||
account_file = Path(BASE_DIR / "cookiesFile" / file_path)
|
||||
if not account_file.exists():
|
||||
return False
|
||||
result = run_biliup_command(["-u", str(account_file), "renew"])
|
||||
return result.returncode == 0
|
||||
case 6:
|
||||
from uploader.baijiahao_uploader.main import cookie_auth as baijiahao_cookie_auth
|
||||
return await baijiahao_cookie_auth(str(Path(BASE_DIR / "cookiesFile" / file_path)))
|
||||
case 7:
|
||||
from uploader.alipay_uploader.main import cookie_auth as alipay_cookie_auth
|
||||
return await alipay_cookie_auth(str(Path(BASE_DIR / "cookiesFile" / file_path)))
|
||||
case 8:
|
||||
from uploader.weibo_uploader.main import cookie_auth as weibo_cookie_auth
|
||||
return await weibo_cookie_auth(str(Path(BASE_DIR / "cookiesFile" / file_path)))
|
||||
case 9:
|
||||
from uploader.hupu_uploader.main import cookie_auth as hupu_cookie_auth
|
||||
return await hupu_cookie_auth(str(Path(BASE_DIR / "cookiesFile" / file_path)))
|
||||
case 10:
|
||||
from uploader.youtube_uploader.main import cookie_auth as youtube_cookie_auth
|
||||
return await youtube_cookie_auth(str(Path(BASE_DIR / "cookiesFile" / file_path)))
|
||||
case 11:
|
||||
from uploader.tk_uploader.main_chrome import cookie_auth as tiktok_cookie_auth
|
||||
return await tiktok_cookie_auth(str(Path(BASE_DIR / "cookiesFile" / file_path)))
|
||||
case _:
|
||||
return False
|
||||
|
||||
|
||||
+228
-43
@@ -2,91 +2,276 @@ import asyncio
|
||||
from pathlib import Path
|
||||
|
||||
from conf import BASE_DIR
|
||||
from uploader.douyin_uploader.main import DouYinVideo
|
||||
from uploader.ks_uploader.main import KSVideo
|
||||
from uploader.tencent_uploader.main import TencentVideo
|
||||
from uploader.xiaohongshu_uploader.main import XiaoHongShuVideo
|
||||
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 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 = [Path(BASE_DIR / "cookiesFile" / file) for file in account_file]
|
||||
files = [Path(BASE_DIR / "videoFile" / file) for file in files]
|
||||
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)
|
||||
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"文件路径{str(file)}")
|
||||
# 打印视频文件名、标题和 hashtag
|
||||
print(f"视频文件名:{file}")
|
||||
print(f"标题:{title}")
|
||||
print(f"Hashtag:{tags}")
|
||||
app = TencentVideo(title, str(file), tags, publish_datetimes[index], cookie, category, is_draft)
|
||||
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 = [Path(BASE_DIR / "cookiesFile" / file) for file in account_file]
|
||||
files = [Path(BASE_DIR / "videoFile" / file) for file in files]
|
||||
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)
|
||||
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"文件路径{str(file)}")
|
||||
# 打印视频文件名、标题和 hashtag
|
||||
print(f"视频文件名:{file}")
|
||||
print(f"标题:{title}")
|
||||
print(f"Hashtag:{tags}")
|
||||
app = DouYinVideo(title, str(file), tags, publish_datetimes[index], cookie, thumbnail_path, productLink, productTitle)
|
||||
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 = [Path(BASE_DIR / "cookiesFile" / file) for file in account_file]
|
||||
files = [Path(BASE_DIR / "videoFile" / file) for file in files]
|
||||
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)
|
||||
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"文件路径{str(file)}")
|
||||
# 打印视频文件名、标题和 hashtag
|
||||
print(f"视频文件名:{file}")
|
||||
print(f"标题:{title}")
|
||||
print(f"Hashtag:{tags}")
|
||||
app = KSVideo(title, str(file), tags, publish_datetimes[index], cookie)
|
||||
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 = [Path(BASE_DIR / "cookiesFile" / file) for file in account_file]
|
||||
files = [Path(BASE_DIR / "videoFile" / file) for file in files]
|
||||
|
||||
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)
|
||||
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:
|
||||
# 打印视频文件名、标题和 hashtag
|
||||
print(f"视频文件名:{file}")
|
||||
print(f"标题:{title}")
|
||||
print(f"Hashtag:{tags}")
|
||||
app = XiaoHongShuVideo(title, file, tags, publish_datetimes, cookie)
|
||||
app = XiaoHongShuVideo(title, file, tags, publish_datetimes, cookie, headless=_publish_headless())
|
||||
asyncio.run(app.main(), debug=False)
|
||||
|
||||
|
||||
# ===== 新增:CLI 主线平台接入 Web 后端 =====
|
||||
|
||||
# post_video("333",["demo.mp4"],"d","d")
|
||||
# post_video_DouYin("333",["demo.mp4"],"d","d")
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user