Skip to content

Inbox の YouTube 由来の件を再判定する - #37

Merged
AkashiSN merged 19 commits into
mainfrom
inbox-rejudge
Oct 18, 2026
Merged

AkashiSN merged 19 commits into
mainfrom
inbox-rejudge

Conversation

@AkashiSN

Copy link
Copy Markdown
Owner

背景

YouTube から取り込んだ Inbox の件は、取り込み時のプラグインの判定がそのまま残る。プラグインのルールを直しても(全角 # や Official Audio など)、既に Inbox にある曲には反映する経路が無かった。未判定の曲だけでなく、判定はされたが誤っていた曲も救えるよう、Inbox の YouTube 由来の件に「再判定」を足す。あわせて、どの版のプラグインで判定したかを表示する。プラグインはホストからファイル単位でマウントしているので、バイナリを cp で置き換えて再判定を押せば新しい版で判定される。

変更

  • 新しいジョブ inbox_rejudge(migration 0005 で jobs の CHECK に追加、同時実行 1、重複は件ごとに抑止)。件内の全曲についてプラグインを呼び直し、タグ・ファイル名・サイドカーを書き直す
  • 再判定の対象はその 1 件のみ。ok だった件の albumartist / album は変えない。_unmatched の曲が ok になったら youtube/<albumartist>/<album>/ の件へ移す(購読由来の曲は移さない)。保存済みの下書きは確認のうえ捨てる
  • POST /api/inbox/:id/rejudge → 202 {job_id}。件が無ければ 404、pending でなければ 409、既に投入済みなら 409、YouTube 機能が無効なら 503
  • 再判定の待ち・実行中は、その件の承認・却下・再開を 409 rejudging で断る(YouTube 機能が無効なら断らない)
  • サイドカーに判定の材料・プラグインの版・判定時刻・失敗理由を残す。ytdl と再判定のサイドカー読み書きは同じロックで直列化
  • プラグインの応答の任意フィールド plugin {name, version} を読む(AkashiSN/spindle-ytmusic-meta#5)。古いプラグインなら「版不明」
  • Inbox 画面: 再判定ボタン、件の見出しに 判定: <name> <version>、詳細に版と判定時刻。実行中は他の操作を止め、移動したら移動先の件を開いて通知する。再判定できなかった曲があれば提案に警告
  • GET /api/inbox に ytmusic_enabled
  • 途中で落ちても再実行で収束する(移動後に残った元の項の掃除、走査の投入、作った親ディレクトリの fsync)
  • docs: SPEC §7.7 / §7.8 / §12.6 と API 一覧、DECISIONS D-114、TASKS

確認

  • cargo test(2273 件)/ cargo clippy -- -D warnings / cargo fmt --check
  • npx vitest run(536 件)/ npm run lint / npm run build
  • 実機: 未判定の件で再判定を押し、youtube/花譜/花譜のお歌/ へ移動、見出しに 判定: spindle-ytmusic-meta v0.1.0-rc.1-3-g6d7b14e が出ることを確認

resolve が判定と一緒にプラグインの name / version を返す。
plugin 欄が無い、または形が違うときは None とし、応答全体は不正にしない。
downloader は判定だけを使う(版の記録は別タスク)。
ダウンローダの初回判定で、プラグインへ渡した Item・プラグインの版・判定時刻・
プラグインが書いた追加タグのキーをサイドカーの項に残す。再判定の材料になる。
download_one からプラグイン問い合わせと購読の上書きを judge に、ファイル名と
タグの組み立てを inbox_file_name_for / tag_changes_for に切り出した。
再判定(D-114)。jobs は CHECK の列挙に inbox_rejudge を足すため
0005 で作り直す(FOREIGN_KEYS_OFF に 5)。並列度は 1、表示用の対象は
payload の item_id。0004 / 0001 からの更新試験は適用する版の範囲を
合わせた。
偽の yt-dlp と Lib・set_tags・lib!・subscribe を tests/common/ytmusic.rs
へ移す。プラグインの本文は Lib::new の引数で渡す(再判定のテストは
応答を切り替えるプラグインを使う)。
rejudge_item は pending の件の下書きを消し、サイドカーに source =
youtube の項がある曲ごとにプラグインへ問い合わせ直して、タグ・ファイル
名・置き場所・サイドカーを初回の取り込みと同じ形に書き直す。曲ごとに
独立に失敗させ、理由は項の rejudge_error に残す。

- Item が項に無い既存の曲は、初回の手順 1 と同じ引数の dump で取り直す
  (dump_video に切り出した)
- 判定が ok と未判定の間で変わったときだけ初回の宛先へ移す。移動先の件が
  pending でなければ移さず、今の件の中で直す
- 新しい名前の同名は SOURCE_URL が同じときだけ前回の途中として置き換え、
  項の名前のファイルが無ければ SOURCE_URL で新しい名前のファイルを拾う
移すかどうかをサイドカーの前回の判定でなく、今のディレクトリが受け皿
(youtube/_unmatched/)かどうかで決める。移せなかった曲が次の再判定で
移らなくなる・skip の後の ok で件のディレクトリから移ってしまう、を直す。
inbox_rejudge ジョブのハンドラ(rejudge_item を進捗つきで走らせ、結果を
note に残す)と new_inbox_rejudge_job(dedup は件ごと、再試行なし)を足し、
main.rs では ytmusic が有効なときに Ytdl と同じ環境で登録する。
POST /api/inbox/:id/rejudge は、pending で YouTube 由来の曲を持つ件に
inbox_rejudge ジョブを投入して 202 を返す。ytmusic が無効・件が無いときは
404、pending でない・YouTube 由来が無いときは 409 state、同じ件の
ジョブが待ち・実行中なら 409 duplicate。
承認前の件に「再判定」ボタンを足し、進みと移動先の件を画面に出す。
見出しにプラグインの版、判定列の詳細に版と判定時刻を出し、再判定に
失敗した曲は赤で理由を読めるようにする。サーバは再判定できなかった曲数を
警告に足す。
Inbox の YouTube 取り込みの再判定(inbox_rejudge ジョブ、POST /api/inbox/:id/rejudge)と
判定したプラグインの版の記録を、SPEC §7.7 / §7.8 / API 一覧 / ジョブ一覧、DECISIONS D-114、
TASKS に書く。
ytdl と inbox_rejudge は別のジョブ枠で並んで走り、どちらも
spindle-inbox.json を読んで直して書くので、後に書いた方が先の項を
消すことがあった。DownloaderEnv にプロセス内の鍵(sidecar_lock)を
持たせ、main.rs では 1 つの環境を clone して両方のハンドラに渡す
(鍵を共有する)。finish_staging の upsert と再判定の update_sidecar
は読んでから書くまで鍵を持つ。ファイルのロックではない(不変条件 5)。
キャンセルや件が pending でなくなって止まったとき、それまでに書き
換えた曲があれば inbox の走査を投入する(行はキャッシュなので、
書いた結果を一覧に見せる)。何も書かずに止まったら投入しない。

移動で create_dir_all が新しく作ったディレクトリは、その項を持つ
親(root を含む)も仕上げで fsync する。
一覧に ytmusic_enabled([ytmusic].enabled)を足し、useInbox が
ytmusicEnabled として持つ。無効なら再判定の API は 404 なので、画面が
ボタンを出さないための材料。旧サーバ・取得前は false。
ジョブの終わりは走査(一覧の作り直し)より先に来るので、終わった
時点の一覧で移動先を探すと外れていた。押した時点の曲の形(名前と
判定の記録)を控え、終わった後に取り直した一覧で押した件が消えるか
形が変わったところで着地する(rejudgeSettle / rejudgeOutcome)。
終わってから 30 秒変わらなければ「再判定した」とだけ知らせる。
進みの取得には番号を振り、投入より前に出した取得と追い越された
古い取得の結果は捨てる(投入した件が載っていない一覧で終わったと
しない)。onDone は終わった件の id を受け、控えた件のときだけ着地を
待ち始める。

再判定の間は「承認して配置」「却下」「下書きに戻す」を無効にし、
YouTube 機能が無効なら再判定のボタンを出さない。SPEC §7.8 / §12.6
と GET /api/inbox の一覧を合わせる。
移動で宛先の項を書いて元を消した後、元の項を消す前に落ちると、元の
サイドカーにファイルの無い項が残り続けた。次の再判定で、ファイルも
SOURCE_URL の拾い直しも見つからない項は鍵の中で消し、走査に見せる
(失敗には数えない)。

曲の前だけでなく、yt-dlp・プラグインの応答を待った後、ファイルを書く
前にも件が pending かを確かめる。待つ間に承認された件を書き換えると、
走査が承認を pending に戻してしまう。

判定の category が無くなったら件の category も消す。タグを触らない
判定(skip 等)では category も触らない。
件の inbox_rejudge ジョブが queued / running の間、approve / reject /
reopen を 409 rejudging(理由の message 付き)にする。検査は状態の
遷移と同じトランザクションで行うので、再判定の投入と競合しない。
YouTube 機能が無効なら待ちのジョブは走らないので見ない(件を塞ぎ
続けない)。

SPEC §7.8 / §12.6 / API の一覧と D-114 に、409 rejudging、判定後の
確認、残った項の掃除、category の消去、画面の二度押し止めを足す。
押してから投入が受理されて最初の取得が届くまでを「投入の途中」とし、
再判定・承認・却下・下書きに戻すを無効にする(rejudgeStarting* /
rejudgeBusy)。判断は ref の最新の値で行うので、同じ描画の中の
二度押しも止まる。

着地の控えを件ごとの Map にし(rejudgeWatch*)、別の件を押しても前の
件の着地を失わない。後から失敗した投入(409 duplicate 等)は、自分が
置いた控えだけを元に戻し、受理済みの控えを消さない。
@AkashiSN
AkashiSN merged commit 04cce71 into main Oct 18, 2026
5 checks passed
@AkashiSN
AkashiSN deleted the inbox-rejudge branch October 18, 2026 09:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant