nianzhibai
66adf444ba
fix: detect Docker image version for update checks
2026-05-31 09:55:15 +08:00
nianzhibai
8f8037b838
Update README with service restart instruction
...
Add note about restarting service on first access.
2026-05-30 20:26:29 +08:00
nianzhibai
215d9596fd
Update README.md
2026-05-30 20:17:18 +08:00
nianzhibai
e57058db79
feat: prepare v0.0.4 storage release
2026-05-30 20:02:02 +08:00
nianzhibai
6ec61833f2
feat: probe video duration during thumbnail generation
2026-05-30 18:30:22 +08:00
nianzhibai
6e87f88d53
feat: support spider91 uploads to OneDrive
2026-05-30 18:04:15 +08:00
nianzhibai
e78fa9d978
feat: improve media generation pipeline status
2026-05-30 17:37:31 +08:00
nianzhibai
afbff9eb55
Add Docker Compose deployment support
2026-05-30 11:09:04 +08:00
nianzhibai
039ec2a988
Improve fingerprint dedupe maintenance
2026-05-29 23:58:36 +08:00
nianzhibai
da0683344e
Add sampled fingerprint deduplication
2026-05-29 23:19:52 +08:00
nianzhibai
1a1282382e
Simplify OneDrive setup and redirect playback
2026-05-29 22:35:02 +08:00
nianzhibai
34b6fa8ea9
Release v0.0.3 improvements
2026-05-29 18:34:38 +08:00
nianzhibai
08e38bc4ca
Recreate releases with assets
2026-05-29 16:46:02 +08:00
nianzhibai
c93d193efe
Fetch annotated tag notes for releases
2026-05-29 16:39:12 +08:00
nianzhibai
08568c3951
Use tag notes for release body
2026-05-29 16:34:29 +08:00
nianzhibai
7e394e2971
Prioritize ready thumbnails on home
2026-05-29 16:23:13 +08:00
nianzhibai
d16e3168f9
Update README with upgrade instructions and cleanup
...
Added upgrade instructions for old version users and removed redundant access troubleshooting note.
2026-05-29 15:39:51 +08:00
nianzhibai
81f348b246
Document legacy update recovery
2026-05-29 15:37:40 +08:00
nianzhibai
1e71c1fb72
Wait for service readiness after install
2026-05-29 15:34:48 +08:00
nianzhibai
d5122d289e
Harden installer update flow
2026-05-29 15:23:42 +08:00
nianzhibai
c146ad50ed
Fix PikPak captcha recovery
2026-05-29 14:49:47 +08:00
nianzhibai
f5c20f9594
Fix spider91 upload target and thumbnails
2026-05-29 06:28:18 +00:00
nianzhibai
62e69d4c06
Update mobile section images in README
2026-05-29 11:54:56 +08:00
nianzhibai
51725ba82f
更新 README.md
2026-05-29 11:28:02 +08:00
nianzhibai
c06db836dd
Update LinuxDo community link in README
2026-05-28 21:30:38 +08:00
nianzhibai
b8717da4fd
Include restart command for access issues
...
Add troubleshooting tip for project access issues.
2026-05-28 21:26:49 +08:00
nianzhibai
2d57545e87
Revise README content for clarity and updates
...
Updated the README to enhance the description and clarify features.
2026-05-28 21:23:29 +08:00
nianzhibai
6518d772c0
docs: polish README layout
2026-05-28 21:15:40 +08:00
nianzhibai
f2c0e7f854
Enhance README with new features and preview images
...
Added preview images for desktop and mobile, included theme options and short video mode.
2026-05-28 21:11:13 +08:00
nianzhibai
3c7219ecd6
fix: reduce mobile admin content gap
2026-05-28 20:50:46 +08:00
nianzhibai
94669fd35e
Revise README for project overview and setup
...
Updated project description and installation instructions in README.md.
2026-05-28 20:41:40 +08:00
nianzhibai
d0159435c0
fix: compact mobile admin navigation
2026-05-28 20:00:38 +08:00
nianzhibai
137cfbcf82
feat: add prebuilt installer workflow
2026-05-28 19:13:41 +08:00
nianzhibai
bb8818a55a
feat: improve admin setup and drive management
2026-05-28 18:41:40 +08:00
nianzhibai
54ed98f04f
style: optimize admin layouts, brand rename to 91 and fix drag-scroll interactions
2026-05-28 17:51:16 +08:00
nianzhibai
d2d4db8062
fix: harden spider91 source matching
2026-05-28 16:10:20 +08:00
nianzhibai
7540371838
feat: restore tag classification and drive controls
...
Restore the previous fixed-tag classification flow, including startup backfill for existing videos and the 91porn spider tag.
Also commit the current drive scanning, preview scheduling, and admin drive-control updates present in the workspace.
2026-05-28 12:18:17 +08:00
nianzhibai
e6e5907b38
docs(readme): 用 "视频播放路径" 章节澄清各 drive 走法
...
之前 README 里 115 段落的 "经过进程内本地代理转发 Range 请求" 句容易被
误读成 "用户播放也走代理",但实际上:
- 用户播放 /p/stream/<driveID>/<fileID>: 115 / PikPak 走 302 直连 CDN
(shouldRedirect() in proxy.go 按 kind 判定)
- ffmpeg 抽 teaser: 才走进程内本地代理(startLocalFFmpegProxy)
新增 ## 视频播放路径 主章节,包含一个三列对比表(用户播放 / ffmpeg 取流)
覆盖所有 kind,并解释三个核心概念:
- 302 直连意味着什么(带宽、IP 暴露、过期)
- backend 反代意味着什么(出站流量、Cookie 鉴权)
- ffmpeg 本地代理为什么需要(避免签名 URL 暴露 + 防多段并发风控)
重写 ### 115 说明,把 "用户播放" 和 "ffmpeg 取 teaser" 两条路径分清楚,
每条以加粗前缀(**用户播放**、**取流优先**、**生成 teaser**、**ffmpeg 访问**)
明确作用域。
2026-05-27 18:48:42 +08:00
nianzhibai
39ef2defcc
feat(spider91): 流式爬取 + 完成后统一入队 teaser + 封面失败标 failed
...
三件相关改动,主题都是 spider91 爬虫流程。
1. 流式爬取协议(取代旧的 "Python 凑齐 15 个再交 Go" 模型)
Python 端 (spider_91porn.py):
- 新增 --stream-output flag。开启后每解析出一个 video 直链就把
entry 作为一行 JSON 写到 stdout 并 flush。
- log() 在 stream 模式下走 stderr,避免污染 stdout JSONL 协议。
- --output FILE 仍生效,作离线归档用。
Go 端 (crawler.go):
- 新 startSpiderTargetNew() 异步启动 cmd,返回 stdout pipe。
- RunOnce 用 bufio.Scanner 按行读 stdout,每行解析后立即 processOne
(下载视频 + 封面 + UpsertVideo)。删掉旧 readSpiderOutput / 全 JSON
文件解析路径。
- Python stderr 转发到 backend log,前缀 [spider91:py]。
收益:Python 翻页找下一个 viewkey 与 Go 下载当前视频在时间上重叠,
最大化每条签名链接 e= 时间窗。今天观察到 Python 77 秒就找完 15 个
viewkey 全部 emit;如果还像旧模型那样要等 Go 串行下完才开始下一个,
后面几个的签名很容易过期(之前 8/15 全 EOF 的根因之一)。
2. teaser 在 crawler 完成后统一入队(取代每条入库立即 enqueue)
- main.go attachSpider91Crawler 不再注入 OnNewVideo callback。
- main.go runSpider91Crawl 在 Crawler.RunOnce 完成后调一次
enqueueDriveGeneration(driveID),让所有新视频统一进 teaser worker。
- 与 nightly Phase 2 的 "等 teaser 队列 idle" 语义自然对齐。
- 下载阶段不和 ffmpeg 抢 CPU/IO。
3. 网站封面下载失败时显式标 thumbnail_status='failed'
spider91 drive 的 thumb worker 按设计不处理 spider91 视频(封面应是
网站原图直接保存)。当网站封面下载失败时,url='' + status='pending'
会让 enqueueDriveGeneration 的 waitForThumbnailsBeforePreview 因为
CountVideosNeedingThumbnail > 0 把 teaser 卡死等待循环。
修复:crawler.go processOne 中 thumb 失败分支显式标 status='failed'
(CountVideosNeedingThumbnail 条件 status != 'failed' 会排除)。
今天观察到的现象:187 MB 视频 c2c04fc8602c5396d469 卡在
'[preview] waiting for 1 thumbnails before teaser generation'
循环 35 分钟。
测试:
- crawler_test.go 重构为 buildFakeSpiderScript helper,
生成支持 --stream-output 的伪 python(其实是 sh),逐行 echo JSON。
- TestCrawlerRunOnceFullFlow / TestCrawlerThumbDownloadFailureMarksStatusFailed
通过新 helper 验证流式协议 + thumb fail 闸门。
go test ./... 全绿;线上手动触发 spider91 抓取验证流式行为正确。
2026-05-27 18:48:30 +08:00
nianzhibai
a886b4b490
fix(catalog): thumbnail_status 写入路径同步 + 一次性修历史脏数据
...
症状:直接 SQL 查到 "thumbnail_status='pending'" 有 4032 行,但 worker 入队
统计、admin API 都显示 0 待生成。
根因:thumbnail_status 是 ALTER TABLE 后加的列(DEFAULT 'pending'),列加入
时所有已有视频的 thumbnail_url 已写好,但 status 全部填了 'pending'。worker
入队按 url 判断(不看 status 字段),所以行为正确,但状态字段长期与 url 不一致。
写入路径修复(避免新写入再产生同类脏数据):
- UpsertVideo INSERT 列表加入 thumbnail_status,
值 = CASE WHEN url != '' THEN 'ready' ELSE 'pending' END
- UpsertVideo ON CONFLICT 按 excluded.thumbnail_url 同步 status
(url 空时保留原 status,不误改 'failed' 状态)
- UpdateVideoMeta 当 patch 设了 url 但未传 status 时自动推断 'ready';
显式传 status 仍然尊重
- clearVolatileOneDriveThumbnails 清 url 时同步把 status 重置为 'pending',
让 worker 重新入队
历史数据修复:
- 新增 reconcileThumbnailStatusOnce(ctx) 一次性 migration
- 用 marker setting 'videos.thumbnail_status.url_present_to_ready_migrated'
防重复执行
- 仅修 url 非空 + status NOT IN ('ready', 'failed') 的行
- 已在生产 catalog 上跑过,修正 4030 行 (115 drive thumb_pending: 4032→4)
测试覆盖(catalog/tags_test.go +5 个新测试):
- TestReconcileThumbnailStatusOnce
- TestUpsertVideoSyncsThumbnailStatusFromURL
- TestUpsertVideoOnConflictSyncsStatusOnURLChange
- TestUpdateVideoMetaInfersReadyWhenURLPresent
- TestClearVolatileOneDriveThumbnailsResetsStatus
2026-05-27 13:18:00 +08:00
nianzhibai
1eeebbf305
refactor(scheduling): 统一三套定时调度为 NightlyJob 流水线
...
替代 scanLoop / crawlerLoop / Migrator.Run 三个并行的周期循环为单一 nightly.Runner,
每天 cron_hour(默认 01:00)串行跑一条流水线:
Phase 1 扫所有非 spider91 / 非 localupload 网盘
→ 检测新增视频 + 检测被删视频(清理 catalog 行 + 本地封面/teaser)
→ 入队封面 + teaser(per-drive teaser_enabled 决定 teaser 是否入队)
→ 等所有 thumb / teaser worker 队列 idle
Phase 2 仅当存在 spider91 drive:跑 91 爬虫,新视频入队 teaser
→ 等 teaser 队列 idle
Phase 3 spider91 → 云盘迁移(PikPak/115 一次性 sweep)
关键属性:
- 6h 软超时(nightly.max_duration);到点 phase 跑完,后续 phase 不启动
- 当天去重:last_run_date 持久化到 settings 表,进程崩溃重启不重复跑
- sync.Mutex.TryLock 保证手动触发与自然 cron 触发互斥
- 每 phase 边界检查 ctx.Err,不强 kill 进行中的 ffmpeg / 上传
- 单 drive '重扫' 和 spider91 '立即抓取' 按钮保留
- 顶栏新增 '立即跑全流程' 按钮 (POST /admin/api/jobs/nightly/run)
附带优化:
- preview.Worker / ThumbWorker 增加 WaitIdle(ctx) error,nightly 用作同步屏障
- scanner 增加 30s 心跳进度日志,避免长扫盘内部黑盒
格式: [scanner] drive=X progress: scanned=N added=K errors=E dirs=M elapsed=Ts at=<dir>
- cleanupMissingDriveVideos 从 PikPak-only 扩展到所有云盘 kind
(保留 stats.Errors==0 闸门避免 API 抖动误删)
- Migrator 移除周期 ticker / Trigger 通道,改成可单独调用的 RunOnce
(captcha cooldown 状态机仍保留,跨 RunOnce 持久 5 分钟)
废弃 (字段保留以兼容旧 yaml):
- scanner.interval_seconds (替代为 nightly.cron_hour 调度)
- spider91 drive 的 crawl_hour 凭证字段 (last_crawl_at 仅作 admin UI 显示)
测试:go test ./... 全绿 (含 nightly 包 ~320 行单元测试);npm run build 通过。
2026-05-27 13:17:44 +08:00
nianzhibai
ebd6943a10
feat(spider91,drives): 支持上传 115 + 每盘 Teaser 开关
...
* spider91 → 云盘迁移目标从仅 PikPak 扩展到 PikPak ∪ 115:
- 115 driver 新增 UploadAndReportSha1(buffer 到 tmp 文件 + sha1 +
SDK RapidUploadOrByMultipart + 父目录按 sha1 找 fileID)和 Rename
- migrator 引入 uploadTarget 接口 + pikpakAdapter / p115Adapter,
按 drive Kind() 路由;catalog 改写 / 本地清理 / 失败冷却 / backfill
file_name 行为对两种目标盘统一。captcha 冷却仍只对 PikPak 4002/9 生效
- App.Spider91UploadDriveID 校验放宽到 pikpak ∪ p115,自动选取在两类
候选并存时拒绝(要求显式选定)
- admin DrivesPage 在 spider91 表单里加"上传目标"下拉,文案按系统中
实际挂载的盘 kind 自适应(只挂 PikPak 不会显示 115 字样,反之亦然)
* 全局 teaser 开关下沉为每盘 toggle 按钮:
- drives 表加 teaser_enabled INTEGER NOT NULL DEFAULT 1
- 删除 App.PreviewEnabled / SetPreviewEnabled / loadPreviewEnabled
和 settings.previewEnabled 字段;前端删除 PreviewToggle 组件
- 新增 catalog.SetDriveTeaserEnabled + POST /admin/api/drives/{id}/teaser-enabled
接口;AdminServer 加 OnTeaserEnabledChanged hook,从关到开时立刻
enqueueDriveGeneration 补扫 pending teaser
- 网盘列表"操作"列加 Power / PowerOff toggle 按钮,乐观更新 + 失败回滚
- 一次性迁移 resetDriveTeaserEnabledToDefaultOnce:把现存 drive 强制
重置为开启,marker setting 记号防止重复(兼容短暂存在过的、把全局
preview.enabled=0 同步成 per-drive=0 的中间版本)
- 封面 worker 仍始终入队,开关只控制 teaser,避免越权
测试:go test ./... 全绿;npx tsc --noEmit / npm run build 通过。
2026-05-27 12:07:41 +08:00
nianzhibai
95bf67667a
fix(spider91): cool down PikPak captcha migration failures
2026-05-27 10:59:12 +08:00
nianzhibai
f05df174ac
docs(readme): document systemd-based deployment as primary launch mode
...
- Promote systemd to the primary 运行 method (production / long-running)
- Provide complete unit files for backend (compiled binary) and frontend (vite preview)
- Add daily ops cheatsheet: status / restart / journalctl / rebuild flows
- Keep start.sh as a local-dev / fallback path (方式 B)
- Warn against mixing start.sh with systemd to avoid port/process contention
2026-05-25 18:24:09 +08:00
nianzhibai
bd3f27d5b3
fix(pikpak): auto-recover from error_code=4002 captcha_token expired
...
When PikPak's cached captcha_token expires, Init() and runtime API
calls used to fail permanently with error_code=4002, leaving the drive
un-attached and blocking spider91 -> PikPak migration.
- refreshCaptchaToken: on 4002, clear cached token and retry once with
empty captcha_token so the server issues a fresh one. Covers the
driver-attach path during server startup.
- requestOnce: extend captcha-refresh-and-retry path from case 9 to also
cover case 4002, clearing cache before refresh to avoid sending the
same expired token again. Covers per-API-call recovery at runtime.
- Add captcha_recovery_test.go covering: recovery on 4002, no-loop
guard when token already empty, request-level recovery, and
single-retry boundary.
OpenList's upstream PikPak driver does not currently handle 4002 either,
so this is a strict improvement.
2026-05-25 16:33:41 +08:00
nianzhibai
84ba7c8422
style: redesign web page tab favicon
2026-05-25 13:41:06 +08:00
nianzhibai
d920943b58
fix(security): replace reflect-Origin CORS with allowlist (C-1)
...
Previously corsMiddleware reflected any Origin back into
Access-Control-Allow-Origin while emitting Allow-Credentials: true.
Combined with no CSRF token, this let any third-party site read or
write authenticated APIs cross-origin (full session takeover via
chained requests to /admin/api/drives etc).
Changes:
- config.Server.AllowedOrigins []string (default empty = same-origin only)
- corsMiddleware now only emits CORS headers for whitelisted Origins;
unknown origins receive no Allow-Origin and 403 on preflight
- '*' entries are silently dropped to prevent regression
- Always set Vary: Origin to keep caches honest
- Drop the originOr() helper, no longer needed
- Add cors_test.go covering allow / reject / preflight / wildcard cases
Same-origin deployments (nginx fronting / and /api on the same domain)
keep working with no config change. Cross-origin deployments must add
their frontend Origin to server.allowed_origins.
2026-05-25 13:28:06 +08:00
nianzhibai
e49d5978ee
style(shorts): optimize UI and user interaction experience on mobile and desktop
2026-05-23 12:16:07 +08:00
nianzhibai
cfeba94d16
feat(scanner): published_at 统一用入库时刻,不再取网盘 mtime
...
- scanner.go 把 PublishedAt 从 orDefault(e.ModTime, now) 改成 now
- 删除已废弃的 orDefault 工具函数
- README 把'发布时间'语义点透为'即视频入库时刻'
- plan 追加 14.2.10 记录这次决策
历史数据不回填;新扫的视频起按新规则。
2026-05-23 11:29:47 +08:00
nianzhibai
ada69fec87
feat(pikpak): 302 重定向播放 + 自动迁移 spider91 视频
...
- PikPak 视频播放从反代切到 302 直连 PikPak CDN(与 OpenList 一致),
浏览器直接拿签名链接,backend 不再消耗带宽转发字节。
proxy.shouldRedirect 改成 switch,pikpak 与 p115 同等处理。
- 实现 PikPak Driver.Upload:参考 OpenList 协议,先算 GCID
(SHA1-of-SHA1-blocks 自定义 hash,OpenList 同款)申请上传会话;
命中秒传直接返回 file id,否则用 vendored 的 aliyun-oss-go-sdk
PutObject 走 S3 兼容上传。单次 PutObject 上限 5GiB-1。
另加 PikPak.Rename(PATCH /drive/v1/files/<id>)。
- 新建 internal/spider91migrate 包:周期把 spider91 爬的视频上传到
指定的 PikPak drive,事务性改写 catalog 行(drive_id / file_id /
file_name / content_hash),删本地 mp4+thumb。视频 ID 保持
spider91-<driveID>-<viewkey> 不变,video_tags / views / likes /
91porn 标签全部保留。catalog 加 MigrateVideoToDrive +
ListVideosByDriveID + ListSpider91Viewkeys。
- 上传策略:本地保留最新 KeepLatestN=15 个文件,超出部分(更旧的)
才上传到 PikPak。第一次爬完 15 个全留本地不上传;第二次爬完 30 个
时把最旧 15 个迁走。稳态本地 ≤15 个最新视频,PikPak 累积所有历史。
- 文件名方案 B:上传到 PikPak 时用 <sanitized title>-<viewkey后8>.<ext>,
catalog file_name 同步更新;启动时 backfillFileNames 幂等地把已迁
视频的旧名(viewkey.ext)改成新格式。
- crawler 完成后立即 ping migrator,不必等 60s 周期。
- 修一个迁移破坏去重的 bug:crawler 写 seen viewkey 时按 drive_id 查,
但视频迁到 PikPak 后 drive_id 不再是 spider91。改用 ListSpider91Viewkeys
按 id 前缀 'spider91-<driveID>-' 查,迁移后仍能识别。
- 加全局设置 spider91_upload_drive_id(settings 表)+ admin GET/PUT API;
未显式设置时自动选取唯一的 PikPak drive。
- 顺手清理已废弃的 RemoteDir / preview 回写网盘相关代码(teaser+封面
早就只走本地,但残留了 Config 字段、yaml 示例、NewWorker 多余参数、
catalog UpdatePreview 多余参数)。
测试:
- 新增 ~40 个单测覆盖 GCID 算法、PikPak Upload/Rename schema、
migrator 各种场景(保留窗口内/外、上传失败、未配 target、批次限流、
孤儿清理、文件名 backfill 幂等)、文件名 sanitize、PikPak 302 重定向。
- 全包 go test -count=1 通过。
联调:在生产实例上验证:spider91 17 条已迁视频 6 秒内全部秒传到 PikPak、
catalog 改写正确、本地清空、PikPak 视频回放走 302 直连
dl-z01a-0043.mypikpak.net;触发新爬 15 条本地保留不上传;
backfill 把旧 viewkey.mp4 命名改成 <title>-<viewkey后8>.mp4。
2026-05-23 02:01:36 +08:00