エージェントと denpa は同じものを二重に知りうる。持ち主を決めておかないと、 画面と実際が食い違ったときにどちらが正しいか分からない。
分け方は1つだけ。「機材の今」はエージェントに都度聞き、 「電波から読んだもの」と「後から要るもの」は denpa が自分のDBに持つ。
エージェントは中身を読まない (NIT も SDT も EIT も読まない。agent.md)。
読むのは全部こちら側で、足場は src/lib/ts/ にある。
denpa は写さない。聞けなければ、その部分だけ出さない。
| もの | エンドポイント | 使うところ |
|---|---|---|
| チューナーの空きと、いま誰が使っているか | /denpa/tuners |
予約の衝突解決、チューナー画面 |
| 選局できるチャンネル (スキャンの結果) | /denpa/channels |
局の取り込み、番組表集め |
| スキャンの結果を預ける | PUT /denpa/channels |
チャンネルスキャン |
| 繋いである機材を書き換える | PUT /denpa/tuners |
チューナー画面 |
| 放送そのもの | /denpa/stream?type=…&channel=… |
録画、ライブ視聴、番組表集め、ロゴ収集、チャンネルスキャン |
| チューナーを使い始めた・離した・局が入れ替わった、の通知 | /denpa/events (SSE) |
チューナー画面の更新、ロゴ集めでの選局の共有、局の取り込み直し |
| スクランブルを復号させる | /denpa/decode |
エンコードの前の B25 解除 |
| カードリーダーの状態 | /denpa/card |
チューナー画面 |
写さない理由は、写した瞬間に嘘になるから。 チューナーの空きは秒で変わる。 チャンネル定義は「いま何を選局できるか」そのもので、写しを見せるとスキャン直後なのに 古い顔ぶれが出る。
チューナーの使い方は1つしかない。 物理チャンネルを丸ごと開くだけで、サービス単位・番組単位の
開き方は無い。局を選り分けるのも (ts/service-filter.ts)、番組の切れ目を見るのも
(ts/eit.ts) denpa。
DENPA_DB の SQLite。ロゴだけは PNG のままファイル (data/logos/)。
| もの | どこから | なぜ持つか |
|---|---|---|
局 (services) |
エージェントの /denpa/channels (元は SDT) |
局が消えても、その局の録画は残る。行は消さず、直近の取り込みで見かけなかったものは画面に出さない (CURRENT_SERVICES) |
番組表 (programs) |
放送波の EIT を denpa が自分で読む | 下記 |
| 局ロゴ | 放送波の CDT / データカルーセルを denpa が自分で読む | 下記 |
| 予約・録画・ルール・設定 | denpa 自身 | エージェントは何も知らない |
局の内部ID (services.id) は networkId * 100000 + serviceId。番組のIDは
局の内部ID * 100000 + event_id。この作り方は変えられない。 録画も予約も
これを参照していて、変えると過去の録画が辿れなくなる。
電波に出ているのは「いま流れている番組表」だけで、放送が終われば消える。
- 予約は番組表より長生きする。 録画が終わったあとも「何を録ったのか」は残る
- 録画に付ける名前と概要は、録ったときの値で固定したい。 番組表は放送直前まで 書き換わるので、後から引き直すと別の名前になることがある
- ルールの判定と衝突解決は SQL でやる。 数千件の番組に JOIN と索引で一気に当てる
- チューナーが塞がっていても画面は出る。 番組表と予約一覧は読めるべきもの
番組表を持っているのが denpa なので、集め方もこちらで決められる。
| 並列 | チューナーが空いているだけ並べる |
| 順番 | 番組表が薄い局から |
| 打ち切り | EIT 自身が「どこまであるか」を言っているので、揃った時点で離す |
| 録画中 | 同じチャンネルなら選局を共有 (チューナーは増えない) |
終わりの判定は ts/eit.ts の ScheduleProgress。EIT のセクションは8本ずつの
セグメントに分かれ、segment_last_section_number が「このセグメントで実際に使っている
最後の番号」を言う。使っていない番号は永久に来ないので、そこまで揃えば終わり。
「0〜last_section_number が全部」で待つと、いつまでも終わらない。
table_id も同じ。1つの table_id が受け持つのは4日ぶんで、基本は 0x50 から、
詳細は 0x58 から始まる。8日ぶんの放送なら流れてくるのは 0x50 0x51 と
0x58 0x59 だけで、0x52〜0x57 は永久に来ない。last_table_id まで全部を
待っていた頃は、詳細を積んでいる局が一度も「揃った」にならなかった。
版 (version_number) も table_id ごとに別々に振られる。局に1つだけ持っていた
頃は、基本と詳細を行き来するたびに数えたものを全部捨てていた。
もう過ぎた時間帯のセグメントは流れてこない。 セグメントは 0:00 から3時間ずつの枠で、
table_id と節番号から枠の時刻が決まる (0x50 が当日 0:00 から4日ぶん=32枠、0x51 がその次)。
「空でも先頭の1本は来る」として待つと必ず取り残される。実機では14チャンネルが全部上限の
600秒を使い切り、欠けはどの局も 0:00 から今までの枠で、時計が進むと1つ増えた (電波の欠けでは
起きない現れ方)。過ぎた枠の番組は、まだ未来だった数日前に取り込んである。
「見えていない先頭は飛ばす」という時計を使わない直し方は採らない。カルーセルの途中から
拾うと、まだ来ていないだけの先頭まで飛ばして 0x51 を揃ったことにし、4〜7日先が丸ごと落ちる。
「揃った」で閉じるのは denpa だけ (よそは時間で打ち切る。Mirakurun も版は version[table_id])。
判定が間違っていると、開きっぱなしのうえ先の日ほど題名が埋まらない状態 (実機の TBS1 は
3〜5日後が 0) で黙って取りこぼす。
| いつ | 何を |
|---|---|
| 起動直後に1回 | 番組表を集める。薄い局からなので数分で画面に出る |
30分ごと (EPG_COLLECT_INTERVAL) |
集め直すべき局を選び直す |
1分ごと (CHANNEL_SYNC_INTERVAL) |
局だけを取り直す (スキャンの結果はここで届く)。BS/CS の局が無ければ標準の表を入れる (チャンネルスキャンの節) |
| 録画している間ずっと | そのチャンネルの EIT は只で読める。5分ごとに書き出す |
| 誰かがチューナーを開いたら | その選局を共有して局ロゴを取得する。ロゴが無い/1週間より古い/(地上波で) 小さい版しか無い局だけ |
| 録画をエンコードするとき | CM検出用のロゴをその録画から覚える (覚えていれば当てるついでに育てる)。チューナーは使わない (logo.md) |
| スキャンが終わったら | 局を取り込み直して、番組表を集め直す |
| 「番組表をいますぐ集める」を押したら | 全チャンネルを、録画とライブ以外からは取り上げる優先度で (下記) |
「集め直すべき局」は、番組表が3日先まで埋まっていない (EPG_MIN_COVERAGE) か
6時間行っていない (EPG_CHANNEL_INTERVAL) もの。前者は再起動しても分かるので、
Pod が入れ替わっても全チャンネルを回し直さない。
ただし行った直後は行き直さない (EPG_CHANNEL_RETRY、既定2時間)。実機の CS には開いても
EIT が1件も来ないチャンネルが4つ (22局) あり、30分ごとに選ばれては毎回上限
(EPG_CHANNEL_TIMEOUT) まで開きっぱなしだった (いまの CS はネットワークごとに1中継で読み、休ませるのもネットワーク単位。下の「衛星の番組表」)。使えなかった回は数えない。
録画に譲っただけの局まで休ませると番組表が古くなる。
番組表に出てこない局 (データ放送・ワンセグ) は「薄い」と数えない。 数えていた頃は、ほぼ全局が これを積んでいる地上波が毎周回丸ごと対象になっていた。
開くのはチューナー1台につき1人で、種別をまたいで1つの列を引く。種別ごとに台数ぶん並べて いた頃は、BS と CS を同時に集めると衛星の2台を二重に数え、溢れたぶんが 409 で落ちていた。
BS はどの中継にも他の中継ぶんの番組表 (他TS: 0x4F / 0x60-0x6F) が流れている。
普段は自TS ぶん (0x4E / 0x50-0x5F) だけ読み、他TS ぶんは初回だけ読む (ts/eit.ts の
EpgReader の other)。
| 何 | セクション | 番組 | 詳細の記述子 | TS | 局 | 最後に新しいものが来た時刻 |
|---|---|---|---|---|---|---|
0x4E いま/次 (自TS) |
6 | 6 | 18 | 1 | 3 | 3 秒 |
0x4F いま/次 (他TS) |
140 | 135 | 37 | 25 | 45 | 783 秒 |
0x50-57 番組表 基本 (自TS) |
96 | 169 | 0 | 1 | 3 | 355 秒 |
0x58-5F 番組表 詳細 (自TS) |
66 | 165 | 1003 | 1 | 1 | 177 秒 |
0x60-67 番組表 基本 (他TS) |
2592 | 8720 | 0 | 25 | 45 | 360 秒 |
0x68-6F 番組表 詳細 (他TS) |
128 | 195 | 1172 | 2 | 2 | 180 秒 |
- 6分までに全部出そろい、残りの14分は何も増えない。 周期が長くて取りこぼしているのではない (2分で測っていた頃はそう疑っていた)。「最後に新しいものが来た時刻」は版の書き換えも数えて いるので、揃った時刻はこれより早い (WebTS.app は約3分で揃うと言う)
- 詳細は、各局が自分の中継にしか流していない。 他TS ぶんの詳細が来たのは 45 局中2局。
番組表用の別の PID (
0x26/0x27) にも何も来ていない - 一方、中継ごとに開いて取り込んだ実機の番組表では、BS のメイン局は大半の番組に詳細が付いている (BS-TBS 252/268、NHK BS 192/228、WOWOW は全件)。サブチャンネル (BS朝日2・3 など) は0件。 1中継で済ませると BS の詳細がほぼ全部消える
- CS は実機の番組表で詳細がほぼ全局0件 (中継ごとに開いていても)
| 何 | セクション | 番組 | 詳細の記述子 | TS | 局 | 最後に新しいものが来た時刻 |
|---|---|---|---|---|---|---|
0x50-57 番組表 基本 (自TS) |
305 | 716 | 0 | 1 | 5 | 178 秒 |
0x60-67 番組表 基本 (他TS) |
2318 | 7102 | 0 | 8 | 38 | 179 秒 |
0x58-5F / 0x68-6F 詳細 |
0 | — | — | — | — | — |
CS は番組表に詳細を流していない (自TS ぶんにも)。中継ごとに開いても取れるものが変わらないので、
いつもネットワークごとに1中継で全局ぶんを読む (epg-collect.WHOLE_ONLY / networkSweeps)。
約3分でそのネットワークの全局の基本が7日先まで揃う。集め直すかどうかもネットワークで1つの
時刻で決める (中継ごとの時刻だと、開かなかった中継が「行っていない」に見えて毎周回読み直す)。
WebTS.app はネットワークごとに1つの TS しか選局せず、他TS ぶんで全局を埋めている (Mirakurun・EDCB も同じ前提、とコメントにある)。速さを取って詳細を捨てる選び方。
BS は両方取る。 初回 (そのネットワークの局に番組が1件も無いとき) だけ、1中継を列の先頭で
読んで全局の基本を入れ (epg-collect.firstSweeps)、
そのあと同じ周回の続きで中継ごとに回って詳細を足す。画面に番組が出るまでが、中継を
1つずつ回る数十分から約6分になる。
- 全局読みは、来るはずの局 (DB にある局) が全部見えて揃えばすぐ閉じる (WebTS.app・Mirakurun と同じ)。
見かけた局が揃っただけで閉じると、まだ1度も来ていない局を置いていく。受信できない局が
混ざっていて全部は見えないときは、新しい局がしばらく出てこないことを待って閉じる
(
EPG_SWEEP_SETTLE、既定1分) - 受信できない局が残っていても、ほかの局が埋まっていれば走らない。 毎周回1中継を
塞がないため。行った直後は休ませる (
EPG_CHANNEL_RETRY) - 全局を読んだ中継は自TS ぶんの詳細もそこで取れているので、続きでは回らない。 揃わないまま上限で切れたときだけ、列の後ろへ戻して読み直す
- 全局読みに使う中継は、いちばん長く行っていないもの。受信できない中継に当たり続けない
- 続きの途中で再起動すると、残りの中継は「行ったばかり」に見えるので、詳細が足されるのは
次に集め直すとき (
EPG_CHANNEL_INTERVAL、既定6時間) まで延びる - 他TS ぶんの番組名は詳細の無いまま入るので、ルールの「詳細説明まで広げる」はその間 BS で 当たらない。詳細が入れば当たり直す
衛星は BS01_0 のような相対番号で選ぶが、何本乗っているかは中継ごとに違い、
無い番号を指すと復調器は先頭の TS を返す (断らない)。実機のスキャン結果 35 枠のうち
9 枠が既知の TS の写しだった。
| 枠 | 実体 |
|---|---|
BS01_3 |
BS01_0 (16400) |
BS03_3 |
BS03_0 (16432) |
BS05_2 BS05_3 |
BS05_0 (17488) |
BS09_2 BS09_3 |
BS09_0 (16528) |
BS13_3 |
BS13_0 (16592) |
BS21_3 |
BS21_0 (18256) |
BS23_3 |
BS23_0 (18288) |
取りこぼしではない。残った 26 TS は、上の他TS 調査で放送自身が名乗った 26 TS と完全に一致する。
スキャンで落とし (twinOf)、開く側でも落とす (withoutTwins)。 衛星の1周が
35 → 26 回になる。開く側でも要るのは、古いスキャンで書いた控えには写しが残るため
(実機の channels.json がそうだった)。しかも services.channel には最後に取り込んだ枠の
名前が1つしか入らず、残った9枠は永久に「一度も集めていない」ことになって、周回の
たびに開かれていた。だから「最後に集めた時刻」は枠ではなく局から引く。
普段の番組表集めは弱い部類 (EPG = 3) で開き、録画・ライブ・スキャンに譲る (ロゴ (1) には勝つ)。
ただ入れた直後は番組表が空で、そこでスキャンが動いているといつまでも画面に何も出ない。
チューナー画面のこのボタンを押している間だけ優先度 8 で使う。録画 (10) とライブ (9) からは 取り上げず、スキャン (5) からは取り上げる。上の2条件も無視して全チャンネルを 薄いほうから回る (集め終えた直後に押して1本も回らないのでは意味が無い)。 走っている周回があれば、その回を強くする。開くのは1チャンネルずつなので次に開くところから 効き、仕切り直すより早い。
1チャンネル (全局読みなら1中継) を読み終えるまで待たず、30秒ごとに読めたぶんを書く
(epg-collect.collectChannel)。今日・明日の番組は先に流れてくるので、開いて数十秒で
番組表が埋まり始める。揃うまでの時間そのものは変わらない (実機の地上波は1チャンネル約1分)。
予約の組み直し (settle) は周回の終わりにまとめて1回。
スキャンは局情報 (NIT・SDT) が揃うまで数秒〜十数秒選局している。その間に流れてくる番組表
(いま・次と今日ぶんくらい) も読んでおき、局を DB に入れた直後に書く (scan.ts の runScan)。
読む時間は延ばさない (スキャンが遅くなる)。スキャンが終わった時点で番組表が空にならない
だけで、続けて走る番組表集めが埋める。
録画は物理チャンネルを丸ごと開いているので、その EIT も流れてくる。5分ごとに書き出し、 番組表集めがそこへ行く手間を省く。延長への追従も同じ流れから来る (下記)。
取り込みで見かけなかった局は、番組表を消し、まだ始めていない予約を取り消す (一覧から戻せる)。
置いたままにしていた頃は、選局できない局の番組が数万件残って検索に引っかかり続け、予約は
始まるのを待って失敗していた。局の行は残す。消すとその局の録画や過去の予約が
辿れなくなる (画面から外すのは CURRENT_SERVICES)。映像の無い局 (データ放送・ワンセグ) だけは、
何も紐付いていないので行ごと消す。
- 1回見かけなかっただけでは片付けない (
SERVICE_FORGET_AFTER、既定30分)。1回で決めていた 頃は、エージェントから欠けた一覧が返った拍子に現役の局の予約が44件まとめて取り消された - 1局も取れなかった回では何もしない。 起動直後や不調で空が返ることがあり、「全部消えた」と 読むと番組表が丸ごと消える
画面の「チューナー」から実行する。 走査は Mirakurun に合わせてある。
- 地上波 13〜62ch を総当たり、BS は 01〜23 の各4スロット、CS は 02〜24ch
- 1チャンネル最大30秒。NIT と SDT が両方揃って受信できたとみなす (SDT だけでは
どのネットワークのものか分からず、設定に書けない)。局名も SDT から
ts/aribtext.tsで読む - 録るに値するサービス種別だけ残す
- 回すのは denpa。 1チャンネルずつエージェントに選局を依頼し、流れてきた TS を読む。 エージェントに読ませると、ARIB の文字符号から局の選り分けまで2箇所に持つことになる
- チューナーの台数ぶん並べる。録画中でも実行できる。 選局は取り合いに乗るので、 録画中のチューナーが使われないだけ (空きが無ければ待つ。飛ばすとそのチャンネルが設定から消える)
- 途中で中断できる (十数分かかる)。中断したときは設定を書き換えない。途中までの結果で 上書きすると、まだ回っていない局の定義が消える
失敗は「何も来なかった」(配線・デバイス指定を疑う) と「電波は来たが NIT/SDT が揃わなかった」 (受信環境を疑う) に分け、エージェントが返した失敗理由も1行添える。揃わなかった チャンネルだけもう一度回す。 NIT は10秒に1回しか来ないので、選局が落ち着くのが遅れると 1回も入らないことがある。
1チャンネル読み終えたら接続ごと切る。エージェントはそれを合図に選局を畳む (agent.md)。畳みそこねると、以降が全部 「受信できませんでした」になる。
探した種別だけを差し替える (地上波だけのスキャンで全部を置き換えて BS と CS が消え、 BS の予約が録れなくなったことがある)。1件も見つからなければ失敗として、今までの局を消さない。
見つけた顔ぶれは PUT /denpa/channels でエージェントに預ける。読んだのは denpa だが、
控え (channels.json) はエージェントが持つ。アンテナに何が映るかは機材ごとの話で、
エージェントを増やせば顔ぶれも変わるから。局を増やすのはスキャンだけ (BS/CS の局が無いときに標準の表から入れる channel-seed.ts を除く)で、番組表を何回
集め直しても増えない。預かったエージェントは何も再起動せず、channels を知らせるだけ
(使っている録画も切れない)。
BS と CS だけは、スキャンしなくても最初から並ぶ (channel-seed.ts)。全国で同じなので、
その種別 (BS / CS それぞれ) の局が控えに1つも無いとき、受けられる種別の標準の表
(channel-seed.json) を同じ PUT /denpa/channels で預ける。地上波だけスキャンしてある環境にも
入る (「控えが空のときだけ」にしていた頃は、前から地上波を入れていた環境に BS/CS が永久に入らず、
Home Assistant のアドオンが自前で追記していた)。1局でもあれば触らない。スキャンの最中も入れない。
表が古くなったらスキャンで上書きする。
放送波の時刻 (TDT / TOT) と自分の時計を突き合わせる作りのものもあるが、denpa はやらない。 録画の開始と終了は壁の時計で決めていて、ライブの「放送から N秒」も PCR とサーバの時計で出す (TDT は局ごとに固定でずれているため。stream.md)。大事なのはホストの時刻で、そちらは NTP の仕事。
エージェントは起きたことを GET /denpa/events (SSE) で流している。
| イベント | denpa の使い道 |
|---|---|
tuners |
チューナー画面を更新する。開いた選局を共有してロゴを取得する |
channels |
局が入れ替わった。取り込み直して番組表も集め直す |
スキャンの進み具合はここに乗らない (回しているのは denpa 自身なので、自分の画面へ直接流す)。 途切れたら繋ぎ直す。黙って止まることもあるので、定期実行を保険に残してある。
黙っている間もエージェントは 30 秒ごとにコメント行 (: keep-alive) を流し、繋いだ時点で
ヘッダも送る。 これが無かった頃は最初の知らせまで 1 バイトも来ず、Bun の fetch が黙った接続を
5 分で切るので、深夜に選局が 5 分止まると「チューナーに繋がりません」→「繋がりました」が
1 時間おきに鳴っていた。
ルールから作った予約は、足すだけでなく外れたものを消す。 番組表を取り込み直す たびに当て直す (足すだけだった頃は、外れた予約を消す手立てが「取り消し」しか無かった)。
消すのであって「取り消し」にはしない。 取り消しは人が押したことの記録で、ルールはそれを 二度と作り直さない。番組表が動いただけのものを取り消しにすると、条件に戻っても永久に立たない。
取り消しは放送単位で効く (物理チャンネル・題名・開始時刻 ±10 分。rules.ts の
canceledBroadcasts)。番組 id だけで当てていた頃は、枝番違い (23608 / 23609) や別の event_id で
載り直した回が立ち直って録れていた。ルールを消すと取り消しの記録も消す (残していた頃は
「ルール: (削除済み)」が実機で149件並んだ)。
手違いで消すほうが、余分に録るより高くつく。 次のものは引っ込めない。
- 手動の予約と、録り始めたもの
- 番組表からその番組ごと消えているときと、題名が空の番組。「条件から外れた」のか 「まだ読めていない」のか区別が付かない (題名が空は実機で 23,000 件中 11,000 件)
- もうすぐ始まるもの (
RULE_RETRACT_GRACE、既定1時間)。番組表は直前まで書き換わる ([新] が付く、サブタイトルが入る、誤字が直る) ので、その拍子に外れても録っておく。 ただしルールごと消された/止められたぶんは直前でも引っ込める (人が押した結果なので)
ルールを足したときは、そのルールしか見ない。 新しいルールは他の予約を外せないので、 全ルール × 全番組 (実機で 318 × 25,608) を回し直す理由が無い。
局は分割放送のために枝番を持つ (TOKYO MX なら 23608 / 23609。SDT の名前はどちらも
「TOKYO MX1」)。分割していない間は同じ回が両方に載り、実機ではルールが両方に当たって2本録れ、
2つのエンコードが同じ名前のファイルへ同時に書いて中身が壊れた (片方は ENOENT、残ったほうは
復号で145行のエラー。再エンコードすると0行)。
そこで同じ物理チャンネル・同じ時刻・同じ題名なら同じ放送とみなし、枝番の小さいほうだけを
予約する (中身が違えば題名が違うので両方残る)。番組表が空の枝番を隠す airing では足りない。
あちらは番組が1つも無い局を落とすだけで、中身の入った写しは隠せない。
ルールの「同じ回は最初の放送だけ録る」(rules.dedupe、episode.firstAirings)。[新] のような
ゆるい条件では、同じ回が局を替えて何度も流れる (MX → BS11 → 地方局、地上波と BS の同時放送)。
- 同じ回 = シリーズ + 話数 + 副題 (
episode.episodeOf/sameEpisode)。話数は#12第12話のほかChapter 15Episode.2EP108も読む (Season 2Part 2Vol.3は読まない)。第2期第2クールのような期と、「東京リベンジャーズ」三天戦争編の頭の鍵括弧に続く編の名前は、 話数ではなくシリーズの側に入る (parseTitleのarc)。編がどちらにも書いてあって違えば別の回 - 副題を出さない局もある (
東京リベンジャーズ 三天戦争編▼第52話と、同じ回に副題を付ける局)。 片方に副題が無ければシリーズ名が同じものを同じ回とみる。編を書かない局 (東京リベンジャーズ #51) も、 作品名が同じなら同じシリーズ。ただし相手が1つに決まるときだけ束ねる —X #5に副題の違うX #5「A」とX #5「B」の両方が当たるなら、どちらにも寄せない (取り違えて録り逃すより、1本多く録る) - 題名に話数も副題も無ければ、概要 (無ければ詳細) から読む。
#18「月下の花」第十八話「…」Chapter 15「…」の形式。題名は「薬屋のひとりごと FRIDAY ANIME NIGHT」のような飾りだけで、話数は概要にしか 無い局がある。括弧の無い話数は行の頭のものだけ (地の文の「第3話から登場」は読まない)。続きが短く文になって いない1行 (Chapter 15 百足坑道の主) なら副題として読む。「前回」「次回」と同じ文の話数も読まない。 録画済みの回も、録画が持つ題名・概要・詳細から同じに読む - 題名に話数だけあれば、副題は概要から足す (話数が題名と同じときだけ)。話数の後ろの
◆枠の名前▼出演者も副題とは限らないので、概要に副題があればそちらを使う。こうして足した副題・括弧の無い副題・ 印の後ろは確かでない副題で、揃えば同じ回の決め手 (飾りの違う局とも束ねる) にするが、食い違っても 別の回にはしない (足す前と同じく、副題の無いものとして見る) - シリーズ名は局ごとの飾りを許す。頭の「アニメ」、後ろの枠の名前、
<…>【…】は局で違う。 飾りを並べて消すのではなく、片方の芯 (いちばん長い語) がもう片方に入っていれば同じシリーズとみる。 これは副題まで揃うときだけ (芯が3文字以上のとき)。話数だけで緩めると、1期の再放送と「X 2」の同じ話数がくっつく。 BS朝日の頭のアニメA・(とドラマ・) は枠の名前として外して比べる。テレ朝は同じ回に副題を出さず【ヌマニメーション】を付けるので、外さないとシリーズ名も副題も揃わない。「・」で始まる頭はほかにも多い (新・続・ザ・) ので、外すのはこれだけ - 話数と概要 (30文字以上) がぴったり同じなら、題名の飾りや副題の有無が違っても同じ回
(
ロンブー亮の… #42と【釣りの日SP】ロンブー亮の… #42)。シリーズ名は同じか片方がもう片方をそっくり 含むものだけ (曜日ごとの枠… Monday #4/… Tuesday #4は同じ番組紹介を持つ)。確かな副題が食い違うもの、 シリーズ名の数字が違うもの (汚職特捜班 5 #6/6 #6) は別の回。話数の違う回にも出てくる概要は 番組紹介とみて使わない (見比べる放送と録画の中で。数字を除いて比べるので「エピソード6」+ 番組紹介 も弾く) - 話数も副題も無い番組は時刻をまたいで束ねない (毎日の「ニュース」が初回しか録れなくなる)。 同じ時刻に同じ題名が流れる同時放送だけ束ねる。題名が「X 第2期」だけのものもここに入る (概要に話数があればそちらで見る)
- いちばん早い放送を録る。それと重なる放送があれば字幕付き (
[字]/ 🈑) → 衛星 の順で選ぶ - 選んだ放送がチューナー不足で弾かれていたら (予約が
conflict)、次の放送も立てる。 当て直すのは番組表が動いたときなので、拾うのは次の当て直しから - 録ってある回は立てない (直近30日の録画。失敗したものは数えない — 再放送は録り直す好機)。 これが無いと、最初の放送を録り終えて番組表の「これから」から抜けた途端、次の再放送が 「いちばん早い放送」に繰り上がる
- 外した放送にもう予約が立っていれば、条件から外れたときと同じ扱いで引っ込める (同じ猶予)。 最初の放送の取り合いが解消して次の放送が要らなくなったときも同じで、直前 (猶予の内) なら残す
- 見比べるのは入れたルールが拾った放送どうし。予約を受け持つのは先に当たったルールだが、 それが入れていないルールでも比べる相手に入る (そこで録るなら、それが最初の放送)。 外した放送に入れていないルールも当たっていれば、そちらが受け持って録る
- 手動で別の局の同じ回を予約してあっても、 ルールはいちばん早い放送をもう1本立てる (1番組1予約なので、同じ放送が2本になることはない)
- 更新で「同じ回は…」が送られてこなければ今の値のまま (編集画面は必ず送る。入れていない ルールが別の経路からの更新で黙って変わらないように)
列を足す前のルールは 0 (入れない)。黙って振る舞いを変えない。画面で新しく作るルールは 入った状態で始まる。
市販のレコーダーに揃えて、コピー禁止の番組は録りません (Discussion #760)。
見るのはデジタルコピー制御記述子 (0xC1) の先頭2ビット (digital_recording_control_data) で、
11 がコピー禁止 (00 コピー可・01 事業者定義・10 1世代のみ)。1世代のみは今までどおり録ります。
記述子は EIT の番組ごとと PMT に入ります。実機で調べた限り、いまの地上波・BS (WOWOW を含む) に
コピー禁止の番組はありません。
- 番組表に持つ (
programs.copy_never)。EIT の基本の表 (と p/f) から読む。詳細の表には 記述子が載らないので、詳細だけ届いた回で印を外さない (EitEvent.copyNeverがnull= 言っていない) - 予約の時点で止める。 ルールが立てた予約は「録画しない」(
skipped) になり、理由 (「コピー禁止の番組なので録画しません」) を持って予約の一覧に出る。チューナーの割り振りには入れない。 番組表で禁止でなくなればふつうの予約に戻る (scheduler.resolveConflicts)。放送が終わっても 「録画しない」のまま理由ごと残し、録り逃し (missed) にはしない — 意図して録らなかったものを失敗に 見せないため。録り逃しの一覧・件数には入らず、予約の一覧の「完了分も表示」で見られる (2週間で片付く)。手で予約しようとしたもの (番組表・ライブの録画ボタン・アプリの API) は 同じ一文で断る。「同じ回は最初の放送だけ」のルールは、禁止の放送を弾かれたものと同じに扱い、 禁止でない次の放送を録る - 録り始めてからも PMT を見る (番組表が古い・無いときの備え)。禁止のあいだは保存しない。 本編を書く前に禁止なら (開始マージンで前の番組のぶんを書いていても) 録画をやめてチューナーを返し、録画は「コピー禁止の番組なので 録画しませんでした」で失敗になる。本編の途中で禁止に変わったときは止めず、そこまでのぶんを残して 禁止のあいだだけ書かない (戻れば続きを書く)
- 観るのはそのまま。 ライブは保存しないので、禁止の番組もふだんどおり観られる。
ライブを止めたり戻したりできるのはブラウザが持っている数分ぶん (stream.md) で、
これも今は変えていない。コンテント利用記述子 (0xDE) の「一時蓄積」は扱っていない。
録画中の録画を頭から観る追っかけ (
/chase/<id>) は録画のファイルを読むので、禁止の番組には出ない
番組表の時刻は予定で、野球が延びれば後ろもずれる。追従の元は録画中の TS に流れている EIT[p/f] (いまと次の番組) で、EIT[schedule] と違って実際の放送に合わせて書き換わる。 問い合わせる相手が要らないので、同時録画の本数にも響かない。
- 録画は物理チャンネルを丸ごと開き、
ServiceFilterでその局だけを書き出す - 同じ TS の EIT[p/f] で、「放送中」の番組が録画中のもの (event_id 一致) なら終了時刻を見る
- 後ろへ動いていたら予約と録画の終了時刻も動かす (動かさないとスケジューラが元の時刻で止める)。 前へ動いても縮めない。まだ流れているのに切ると取り返しがつかない
EIT[p/f] を流さない局でも、番組表の時刻どおりには録れる。
ライブで観ている局も同じ元で追う (server/live.ts → epg.followOnAir)。開いている TS の
EIT[p/f] (いまと次) が番組表と違えば番組表に写し、programs の通知を出す。ライブの画面と
テレビのアプリはこれで読み直すので、延長・繰り下げ・差し替えでも出ている番組が放送とずれない。
写すのは番組表と食い違ったときだけ (p/f は数秒おきに来るが、ふだんは同じものが繰り返されるだけ)。
観ていない局は放送を読んでいないので、画面は番組表の予定の終わりで読み直す。
残っている穴: 延長で後ろの予約と重なっても、録画中のものは競合計算の対象外なので調停されない。 同じ物理チャンネルなら選局を共有するので実害は無いが、別チャンネルでチューナーが埋まっていると後続が録れない。
DBに残り続けるものには必ず期限を切る。1台のサーバで何年も動かすので、 放っておくと一覧が伸びて探すのが遅くなる。
| もの | いつ消えるか |
|---|---|
番組表 (programs) |
終わってから1日 |
| 終わった予約 | 2週間 (取り消し・録り逃し・録画しないか、もう録り始めたもの) |
| 削除済みの録画の行 | 同上 |
| エンコードの記録 | 同上。ただし録画ごとに最新の1件は残す (一覧の状態表示がそれを見ている) |
局 (services) |
消さない。画面から外す (上記)。映像の無い局だけは行ごと消す |
ログインの控え (sessions)・ペアリングの番号 (device_codes) |
期限が来たら |
アプリに渡したアクセストークン (api_tokens) |
消さない。取り消しても revoked_at を付けて残す (いつ・誰が許したかを設定画面に出すため。端末の数だけしか増えない) |
| ルール・設定・局ロゴ・通知先 | 消さない (ユーザーが入れたもの) |
- チャンネルの顔ぶれだけは両方が知っている。 denpa の
services(前回の取り込み 時点) とエージェントのchannels(いまのスキャン結果) は、取り込むまでの間だけ食い違う。 スキャンが終わったその場で取り込む (scan.ts) ので、チューナー画面は denpa の側だけを出す - 番組表を持っているので、集め直すまでは古い番組が残る。 終わった番組は
pruneOldProgramsが消すので、放っておいても数日で揃う