从 Telegram 公共频道 xinjingdaily 抓取图片,百度内容审核,生成竖屏幻灯片视频并上传到 WebDAV 和 B 站。Use ONLY when the user asks about xinjingdaily, 搬石, Telegram content fetching, slideshow generation, Baidu moderation, WebDAV upload, or Bilibili publishing.
Resources
8Install
npx skillscat add lq-259/banshit Install via the SkillsCat registry.
Xinjingdaily Slideshow Pipeline
从 Telegram 公共频道 t.me/xinjingdaily(心惊报)抓取纯图内容,百度内容审核、过滤广告和 NSFW,自动制作竖屏 9:16 幻灯片视频(90-120s),最后上传到 B 站。
首次部署
# 1. 克隆仓库
git clone <your-repo-url> && cd <project-dir>
# 2. 创建虚拟环境并安装依赖
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
# 3. 安装系统依赖
# - ffmpeg (视频编码)
# - chromium / google-chrome (B 站投稿)
# - Xvfb (虚拟显示,Linux 无桌面环境必需)
# - agent-browser (npm 全局安装)
sudo apt install ffmpeg chromium xvfb # Debian/Ubuntu
npm install -g agent-browser
# 4. 创建环境变量配置
cp .env.example .env
# 编辑 .env 填入你的 TG_API_ID, TG_API_HASH, BAIDU_AK, BAIDU_SK
# 5. 创建 B 站投稿配置
cp config/browser_bilibili_config.example.json config/browser_bilibili_config.json
# 编辑 browser_bilibili_config.json 填入你的 Chrome profile 路径和 B 站账号信息
# 6. 创建 WebDAV 配置(可选)
cp config/webdav_config.example.json config/webdav_config.json
# 7. 首次登录 Telegram
set -a && source .env && set +a
.venv/bin/python src/fetch_xinjingdaily.py --date 2026-01-01 --limit 1
# 按提示完成 Telegram 首次登录
# 8. 首次登录 B 站
# 启动 Chrome 后打开 bilibili.com 扫码登录,cookie 会自动保存到 profile核心原则
- 每个步骤的环境变量必须通过
set -a && source .env && set +a加载。 - 封面和标题必须在幻灯片生成之前设置,因为
create_slideshow.py读取title.txt。 - 标题不得重复使用过去日期用过的标题,避免 B 站判定重复内容。
- 标题必须口语化,15-28 字符,不含"心惊报"/"xinjingdaily"/"Telegram"。
- B 站浏览器必须用 Xvfb + 非 headless Chrome,确保 cookie 长存(6 个月)。
- 每次跑完流程必须刷新 cookie(访问 bilibili.com)并保存 profile 后再关闭浏览器。
- 创作声明固定为"内容无需标注"(
creationStatementId = -1)。 - 标签固定为:搞笑、沙雕图、每日趣图、生活记录。
- 筛选阶段优先图文内容(截图、段子图、对白图、文字梗),避免普通风景/自拍。
- 默认每天选择 25-35 张图片,无人值守时取 top 30。
架构
t.me/xinjingdaily (Telegram)
|
v
fetch_xinjingdaily.py -> dates/{DATE}/images/ + image_manifest.json
|
v
prepare_image_screening.py prepare -> screening_candidates.txt + 九宫格预览
|
v
prepare_image_screening.py apply -> 保留入选图片,其余移入 screening_pool/
|
v
baidu_moderate.py -> 百度审核,不合规移入 rejected/
|
v
prepare_image_order.py -> image_order.txt
|
v
save_cover_title.py -> cover.jpg + title.txt
|
v
create_slideshow.py -> output/slideshow_*.mp4
|
v
webdav_upload.py -> WebDAV 远端
|
v
browser_bilibili_upload.py -> B 站投稿项目配置
部署前定义以下变量(可写入 ~/.bashrc 或每次运行时设置):
# 项目根目录
export PROJECT_ROOT="/path/to/your/project"
# Python 虚拟环境
export PYTHON="${PROJECT_ROOT}/.venv/bin/python"
# Chrome / Chromium 可执行文件
export CHROME_BIN="chromium" # 或 "google-chrome-stable"
# B 站 Chrome profile 目录(浏览器登录态)
export BILI_PROFILE="/path/to/chrome/profile"
# agent-browser 会话配置
export BILI_SESSION="bili-account-a"
export BILI_PORT="9222"
# 浏览器操作别名
alias AB="agent-browser --session ${BILI_SESSION} --cdp ${BILI_PORT}"目录结构
${PROJECT_ROOT}/
├── SKILL.md # 本文档
├── .env.example # 环境变量模板
├── .gitignore
├── requirements.txt
├── config/
│ ├── browser_bilibili_config.example.json
│ └── webdav_config.example.json
├── src/
│ ├── fetch_xinjingdaily.py
│ ├── prepare_image_screening.py
│ ├── baidu_moderate.py
│ ├── prepare_image_order.py
│ ├── save_cover_title.py
│ ├── create_slideshow.py
│ ├── webdav_upload.py
│ ├── browser_bilibili_upload.py
│ └── date_context.py
├── output/
│ └── bg_music.flac # 背景音乐(需自行准备)
├── dates/
│ └── {YYYY-MM-DD}/ # 每日数据,自动创建
│ ├── images/ ← 原始图片
│ ├── videos/ ← 原始视频
│ ├── archived/ ← 已使用的图片
│ ├── rejected/ ← 审核不合规
│ ├── pending/ ← 待审核
│ ├── screening_pool/ ← 未被选中的图片
│ ├── output/ ← 生成的幻灯片视频
│ ├── image_manifest.json
│ ├── image_order.txt
│ ├── title.txt
│ └── cover.jpg
└── xinjingdaily_session.session ← Telegram 登录态环境变量
.env 文件模板(参考 .env.example):
TG_API_ID=your_telegram_api_id
TG_API_HASH=your_telegram_api_hash
TG_PHONE=+86your_phone_number
TG_SESSION=xinjingdaily_session
BAIDU_AK=your_baidu_api_key
BAIDU_SK=your_baidu_secret_key每次运行脚本前加载:
cd "${PROJECT_ROOT}" && set -a && source .env && set +aB 站配置
config/browser_bilibili_config.json:
{
"default_account": "account-a",
"accounts": {
"account-a": {
"session": "bili-account-a",
"cdp_port": 9222,
"profile_dir": "/path/to/chrome/profile",
"expected_account": {
"uname": "your_bilibili_name",
"mid": 0000000000
}
}
},
"title_template": "{date} 今日份离谱趣图合集",
"desc": "每日趣图合集,素材来自公开频道整理。",
"tags": ["搞笑", "沙雕图", "每日趣图", "生活记录"],
"creation_statement": "内容无需标注",
"upload_url": "https://member.bilibili.com/platform/upload/video/frame"
}浏览器启动
检查是否已运行:
python3 -c "import urllib.request; print(urllib.request.urlopen('http://127.0.0.1:${BILI_PORT}/json/version', timeout=5).read().decode()[:80])"如果未运行,启动 Xvfb + Chrome:
nohup Xvfb :99 -screen 0 1920x1080x24 &>/tmp/xvfb.log &
sleep 2
DISPLAY=:99 ${CHROME_BIN} \
--remote-debugging-port="${BILI_PORT}" \
--user-data-dir="${BILI_PROFILE}" \
--disable-blink-features=AutomationControlled \
--no-sandbox --disable-gpu \
&>/tmp/chrome.log &
sleep 5必须使用非 headless 模式:headless 模式下 User-Agent 含 HeadlessChrome,B 站 cookie 有效期仅数小时;非 headless 可达 6 个月。
完整运行流程
以下命令均使用 ${DATE} 变量,运行前先设置:
export DATE="2026-07-01" # 或省略 --date 参数,脚本默认使用北京时间昨天Step 1: 抓取 Telegram 内容
cd "${PROJECT_ROOT}" && set -a && source .env && set +a && ${PYTHON} src/fetch_xinjingdaily.py --date ${DATE}- 默认拉取北京时间前一天的消息媒体
- 过滤 NSFW 和广告(正文 >50 字)
- 图片 ->
dates/${DATE}/images/,视频 ->dates/${DATE}/videos/ - 元数据 ->
dates/${DATE}/image_manifest.json
常见问题:部分图片下载失败产生 0 字节文件,会导致后续 prepare 报错 cannot identify image file。删除损坏文件后重试:
rm -f "${PROJECT_ROOT}/dates/${DATE}/images/img_XXXXXX.jpg"Step 2: 图片筛选
生成候选清单:
cd "${PROJECT_ROOT}" && ${PYTHON} src/prepare_image_screening.py prepare --date ${DATE}产物:
screening_candidates.txt:所有图片的候选清单screening_sheets/screening_sheet_*.jpg:九宫格预览图screening_prompt.md:筛选任务说明screened_candidates.txt:agent 填写入选名单
自动选择 top 30(无人值守):
cd "${PROJECT_ROOT}" && ${PYTHON} -c "
from pathlib import Path
d = Path('dates/${DATE}')
lines = [l for l in (d/'screening_candidates.txt').read_text().splitlines() if l.strip() and not l.startswith('#')]
sel = [l.split('\t')[1] for l in lines[:30]]
(d/'screened_candidates.txt').write_text('\n'.join(sel)+'\n')
print(f'Selected {len(sel)}')
"应用筛选:
cd "${PROJECT_ROOT}" && ${PYTHON} src/prepare_image_screening.py apply --date ${DATE}Step 3: 百度内容审核
cd "${PROJECT_ROOT}" && set -a && source .env && set +a && ${PYTHON} src/baidu_moderate.py --date ${DATE}- 仅排除
conclusion == "不合规" && conclusionType == 2 合规、疑似、unknown均保留
Step 4: 排序
cd "${PROJECT_ROOT}" && ${PYTHON} src/prepare_image_order.py --date ${DATE}生成 dates/${DATE}/image_order.txt,一行一个文件名。
Step 5: 封面和标题(必须在幻灯片之前)
cd "${PROJECT_ROOT}" && ${PYTHON} src/save_cover_title.py --date ${DATE} --cover dates/${DATE}/images/img_XXXXXX.jpg --title "短视频标题"标题规则:
- 15-28 字符,口语化
- 不重复使用过去日期的标题
- 不含"心惊报"/"xinjingdaily"/"Telegram"
Step 6: 生成幻灯片视频
cd "${PROJECT_ROOT}" && ${PYTHON} src/create_slideshow.py --date ${DATE}输出 1080×1920 MP4,淡入淡出 0.3s,总时长 90-120s。
Step 7: 上传 WebDAV(可选)
cd "${PROJECT_ROOT}" && ${PYTHON} src/webdav_upload.py --date ${DATE}Step 8: B 站投稿
cd "${PROJECT_ROOT}" && ${PYTHON} src/browser_bilibili_upload.py --date ${DATE} --account account-a --publish脚本自动完成:
- 验证 Chrome profile 和 B 站账号
- 上传视频
- 填写元数据(标题、描述、标签、创作声明)
- 上传自定义封面
- 预发布校验(
validate_publish_ready) - 点击立即投稿
投稿脚本关键实现:
- 创作声明:通过 Vue 组件 setter 设置
selectedStatementId = -1,不依赖 DOM 点击 - 标签:直接操作
vm.$data.custom_tags数组 - 封面编辑器:多次重试关闭,处理多种弹窗
- 投稿按钮:3 次重试 + JS 兜底点击
- 定时发布:自动清理
dtime/premiere/isShowTimeReleaseDialog
Step 9: 验证稿件
AB open "https://member.bilibili.com/platform/upload-manager/article" && sleep 5
AB eval "Array.from(document.querySelectorAll('.common-article-card, .article-card, .card, .item, .article-item')).map(e=>e.innerText.slice(0,120)).slice(0,3)"确认稿件状态为 转码中 / 审核中。
Step 10: 刷新 Cookie 并保存 Profile
AB open "https://www.bilibili.com" && sleep 3
AB open "about:blank" && sleep 2
AB close --all
pkill -f chromium
pkill -f Xvfb违规图片处理
B 站审核退回稿件时的处理流程:
- 在稿件管理找到被退回的稿件,查看违规时间点
- 根据
image_order.txt计算违规图片(每张约 4.3s,总时长 116s ÷ 27 张) - 从
archived/删除违规图片 - 更新
image_order.txt移除对应行 - 将
archived/中剩余图片复制回images/ - 重新执行 Step 4-10
cd "${PROJECT_ROOT}"
# 删除违规图片
rm -f dates/${DATE}/archived/img_XXXXXX.jpg
# 还原剩余图片
cp dates/${DATE}/archived/*.jpg dates/${DATE}/images/
# 重新生成并投稿
${PYTHON} src/prepare_image_order.py --date ${DATE}
${PYTHON} src/create_slideshow.py --date ${DATE}
${PYTHON} src/browser_bilibili_upload.py --date ${DATE} --account account-a --publish一键发布流程
用户说"跑一遍流程"时执行:
# ===== 配置变量 =====
export DATE="2026-07-01"
export PROJECT_ROOT="/path/to/project"
export PYTHON="${PROJECT_ROOT}/.venv/bin/python"
export CHROME_BIN="chromium"
export BILI_PROFILE="/path/to/chrome/profile"
export BILI_SESSION="bili-account-a"
export BILI_PORT="9222"
alias AB="agent-browser --session ${BILI_SESSION} --cdp ${BILI_PORT}"
cd "${PROJECT_ROOT}"
# ===== 加载环境变量 =====
set -a && source .env && set +a
# ===== 启动浏览器 =====
# 检查是否已运行
python3 -c "import urllib.request; print(urllib.request.urlopen('http://127.0.0.1:${BILI_PORT}/json/version', timeout=5).read().decode()[:80])" 2>/dev/null || {
nohup Xvfb :99 -screen 0 1920x1080x24 &>/tmp/xvfb.log &
sleep 2
DISPLAY=:99 ${CHROME_BIN} \
--remote-debugging-port="${BILI_PORT}" \
--user-data-dir="${BILI_PROFILE}" \
--disable-blink-features=AutomationControlled \
--no-sandbox --disable-gpu \
&>/tmp/chrome.log &
sleep 5
}
# ===== 抓取 =====
${PYTHON} src/fetch_xinjingdaily.py --date ${DATE}
# ===== 筛选 =====
${PYTHON} src/prepare_image_screening.py prepare --date ${DATE}
${PYTHON} -c "
from pathlib import Path
d = Path('dates/${DATE}')
lines = [l for l in (d/'screening_candidates.txt').read_text().splitlines() if l.strip() and not l.startswith('#')]
sel = [l.split('\t')[1] for l in lines[:30]]
(d/'screened_candidates.txt').write_text('\n'.join(sel)+'\n')
print(f'Selected {len(sel)}')
"
${PYTHON} src/prepare_image_screening.py apply --date ${DATE}
# ===== 审核 =====
${PYTHON} src/baidu_moderate.py --date ${DATE}
# ===== 排序 =====
${PYTHON} src/prepare_image_order.py --date ${DATE}
# ===== 封面标题 =====
# 注意:选择第一张图片作为封面,标题需每次不同
${PYTHON} src/save_cover_title.py --date ${DATE} \
--cover "dates/${DATE}/images/$(ls dates/${DATE}/images/ | head -1)" \
--title "你的新标题"
# ===== 幻灯片 =====
${PYTHON} src/create_slideshow.py --date ${DATE}
# ===== 投稿 =====
${PYTHON} src/browser_bilibili_upload.py --date ${DATE} --account account-a --publish
# ===== 验证 + 刷新 cookie + 关闭 =====
AB open "https://member.bilibili.com/platform/upload-manager/article"
AB open "https://www.bilibili.com"
AB open "about:blank"
AB close --all
pkill -f chromium
pkill -f Xvfb常见问题
创作声明弹窗 / 定时发布弹窗
根因不是定时发布,而是创作声明未正确选择。B 站前端 checkSubmitParams() 要求 creationStatementId 不为 null。脚本已通过 Vue 组件 setter 直接设置,不再依赖 DOM 点击。
Chrome 进程退出
Chrome 需要 Xvfb 提供虚拟显示。先启动 Xvfb 再启动 Chrome。如果 Xvfb 未运行,Chrome 报 Missing X server 并退出。
Telegram 下载失败
部分图片下载失败产生 0 字节文件,导致 prepare 报错 cannot identify image file。删除损坏文件重试。
稿件被退回
B 站审核退回通常是因为图片违规。按上方"违规图片处理"章节操作,删除违规图片后重新生成投稿。
Chrome profile 未登录
如果浏览器打开后显示 B 站未登录,需要手动扫码登录:
AB open "https://www.bilibili.com"
# 在浏览器中手动扫码登录,cookie 自动保存到 ${BILI_PROFILE}百度 AK/SK 过期
登录 百度智能云控制台 -> 内容审核平台 -> 获取新的 AK/SK,更新 .env 文件。
背景音乐
将 bg_music.flac 放入 output/ 目录。格式需为 FLAC,其他格式可用 ffmpeg 转换:
ffmpeg -i input.mp3 output/bg_music.flac