@danything/arib 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/eit.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * 空いているだけ並列に回せる**し、録画で開いているチャンネルのぶんはただで
6
6
  * 手に入る ([agent.md](https://github.com/danything/denpa/blob/main/docs/agent.md))。
7
7
  *
8
- * 扱うのは2種類。
8
+ * 扱うのは 2 種類。
9
9
  *
10
10
  * - **EIT[p/f]** (table_id 0x4E) … いま流れている番組と次の番組。**放送に追従する。**
11
11
  * 野球で延びた終了時刻はここに出る
@@ -20,9 +20,9 @@ interface EventAudio {
20
20
  /**
21
21
  * 放送が自分で付けた名前。**「主音声ステレオ」「解説ステレオ」。**
22
22
  *
23
- * 同じ構成の音声が2本ある番組 (解説放送・二重音声) は、種別も言語も同じに
23
+ * 同じ構成の音声が 2 本ある番組 (解説放送・二重音声) は、種別も言語も同じに
24
24
  * なるので**符号からは区別が付かない**。実機の日テレでは、どちらも
25
- * `component_type=3 lang=jpn` で「ステレオ (日本語)」が2つ並んでいた。
25
+ * `component_type=3 lang=jpn` で「ステレオ (日本語)」が 2 つ並んでいた。
26
26
  * 見分けが付くものはここにしか無い
27
27
  */
28
28
  text?: string;
@@ -30,7 +30,7 @@ interface EventAudio {
30
30
  main?: boolean;
31
31
  }
32
32
  /**
33
- * シリーズ (series_descriptor。ARIB STD-B10 第2部)。**載せる局と載せない局がある。**
33
+ * シリーズ (series_descriptor。ARIB STD-B10 第 2 部)。**載せる局と載せない局がある。**
34
34
  *
35
35
  * `seriesId` で決まるのは**その局の中だけ**。番号は局ごとに振るので、別の局の同じ番号は
36
36
  * 別のシリーズ。比べるときは局 (original_network_id + service_id) と組にする
@@ -44,7 +44,7 @@ export interface EitSeries {
44
44
  */
45
45
  repeatLabel: number;
46
46
  /**
47
- * 編成の型 (program_pattern)。0=不定期 1=帯 (毎日・平日のみなど) 2=週1回 3=月1回
47
+ * 編成の型 (program_pattern)。0=不定期 1=帯 (毎日・平日のみなど) 2=週 1 回 3=月 1 回
48
48
  * 4=同じ日に何話か 5=長い番組を分けたもの。6・7 はここでは意味を読まない
49
49
  */
50
50
  programPattern: number;
@@ -65,7 +65,7 @@ export interface EitEvent {
65
65
  transportStreamId: number;
66
66
  originalNetworkId: number;
67
67
  eventId: number;
68
- /** 開始時刻 (epoch ms)。未定 (全ビット1) なら null */
68
+ /** 開始時刻 (epoch ms)。未定 (全ビット 1) なら null */
69
69
  startAt: number | null;
70
70
  /** 尺 (ms)。未定なら null。番組表に入れられるのは決まっているものだけ */
71
71
  duration: number | null;
@@ -107,7 +107,7 @@ export interface EitSection {
107
107
  version: number;
108
108
  sectionNumber: number;
109
109
  lastSectionNumber: number;
110
- /** このセグメント (8セクション単位) で実際に使われている最後のセクション */
110
+ /** このセグメント (8 セクション単位) で実際に使われている最後のセクション */
111
111
  segmentLastSectionNumber: number;
112
112
  /** この局で使われている最後の table_id。番組表がどこまで先を持っているか */
113
113
  lastTableId: number;
@@ -118,22 +118,22 @@ export declare const PID_TIME = 20;
118
118
  /**
119
119
  * TDT / TOT のセクションから**放送の実時刻**を読む。別のテーブルなら null。
120
120
  *
121
- * 頭3バイトのあとに MJD + BCD が5バイト。**TOT も同じ並び**で、後ろに
121
+ * 頭 3 バイトのあとに MJD + BCD が 5 バイト。**TOT も同じ並び**で、後ろに
122
122
  * 時差の記述子が付くだけなので同じに読める。
123
123
  *
124
124
  * データ放送 (`bml.ts` の `onTime`) が読み、BML の時計にします
125
125
  */
126
126
  export declare function parseTimeTable(section: Uint8Array): number | null;
127
127
  /**
128
- * MJD + BCD の5バイトを epoch ms に直す。
128
+ * MJD + BCD の 5 バイトを epoch ms に直す。
129
129
  *
130
- * 全ビットが1なら「未定」。開始時刻が未定の番組は番組表に置けないので null で返す。
130
+ * 全ビットが 1 なら「未定」。開始時刻が未定の番組は番組表に置けないので null で返す。
131
131
  */
132
132
  export declare function parseMjdTime(data: Uint8Array, at: number): number | null;
133
- /** BCD 3バイトの尺 (時分秒) を ms に。全ビット1なら「終了未定」 */
133
+ /** BCD 3 バイトの尺 (時分秒) を ms に。全ビット 1 なら「終了未定」 */
134
134
  export declare function parseBcdDuration(data: Uint8Array, at: number): number | null;
135
135
  /**
136
- * EIT のセクションを1本読む。自局のもの以外は null。
136
+ * EIT のセクションを 1 本読む。自局のもの以外は null。
137
137
  *
138
138
  * 壊れたセクションは `SectionAssembler` が CRC で落としているので、ここに来るのは
139
139
  * 中身が揃っているものだけ。それでも長さの辻褄が合わないことはあるので、
@@ -149,13 +149,13 @@ export declare function parseEit(section: Uint8Array, options?: {
149
149
  * 早く揃った局でも待たされ、遅い局は取りこぼす。EIT は自分がどこまであるかを
150
150
  * セクションの中で言っているので、それを数えれば足りる。
151
151
  *
152
- * セクションは**8本ずつのセグメント**に分かれていて、セグメントの中で実際に
152
+ * セクションは**8 本ずつのセグメント**に分かれていて、セグメントの中で実際に
153
153
  * 使われている最後の番号が `segment_last_section_number`。使われていない番号は
154
154
  * 永久に来ないので、そこまで揃えばそのセグメントは終わり。
155
155
  *
156
- * **過ぎた時間帯のセグメントは流れてこない** (`stale`)。空でも先頭の1本は必ず
156
+ * **過ぎた時間帯のセグメントは流れてこない** (`stale`)。空でも先頭の 1 本は必ず
157
157
  * 来るものとして待っていた頃は、**どのチャンネルも例外なく上限まで
158
- * 開きっぱなし**になっていた (実機14チャンネル、揃って離せたのは0本)。
158
+ * 開きっぱなし**になっていた (実機 14 チャンネル、揃って離せたのは 0 本)。
159
159
  */
160
160
  export declare class ScheduleProgress {
161
161
  private readonly now;
@@ -169,11 +169,11 @@ export declare class ScheduleProgress {
169
169
  /**
170
170
  * `table_id` → バージョン。変わったらその表だけ数え直す。
171
171
  *
172
- * **バージョンは `table_id` ごとに別々に振られる。** 番組表の1つの表 (sub_table) は
172
+ * **バージョンは `table_id` ごとに別々に振られる。** 番組表の 1 つの表 (sub_table) は
173
173
  * `table_id` + 局 + TS で決まり、`version_number` はその単位で動く。
174
- * 局に1つだけ持っていた頃は、**基本 (0x50〜) と詳細 (0x58〜) を行き来する
174
+ * 局に 1 つだけ持っていた頃は、**基本 (0x50〜) と詳細 (0x58〜) を行き来する
175
175
  * たびにバージョンが違って数えたものを全部捨てて**いた。揃ったと分かることが
176
- * 二度と無いので、どのチャンネルも上限の10分 (denpa の `epgChannelTimeout`) まで開きっぱなしになる。
176
+ * 二度と無いので、どのチャンネルも上限の 10 分 (denpa の `epgChannelTimeout`) まで開きっぱなしになる。
177
177
  */
178
178
  private readonly version;
179
179
  /**
@@ -185,13 +185,13 @@ export declare class ScheduleProgress {
185
185
  /**
186
186
  * 使われている table_id を全部揃えられたか。
187
187
  *
188
- * **番号が飛ぶ。** 1つの `table_id` が受け持つのは4日ぶんで、基本は
189
- * `0x50` から、詳細は `0x58` から始まる。日本の放送は8日ぶんなので、
188
+ * **番号が飛ぶ。** 1 つの `table_id` が受け持つのは 4 日ぶんで、基本は
189
+ * `0x50` から、詳細は `0x58` から始まる。日本の放送は 8 日ぶんなので、
190
190
  * 実際に流れてくるのは `0x50` `0x51` と `0x58` `0x59` あたりだけで、
191
191
  * **`0x52`〜`0x57` は永久に来ません**。
192
192
  *
193
193
  * `0x50` から `last_table_id` まで全部を待っていた頃は、詳細を積んでいる局が
194
- * **一度も「揃った」にならず**、どのチャンネルも上限の10分 (denpa の `epgChannelTimeout`) まで開きっぱなしに
194
+ * **一度も「揃った」にならず**、どのチャンネルも上限の 10 分 (denpa の `epgChannelTimeout`) まで開きっぱなしに
195
195
  * なっていました (実機で、詳細の無い BS11 だけが早く閉じていた)。
196
196
  *
197
197
  * 見かけた表と、`last_table_id` が指す表だけを見ます。
@@ -202,9 +202,9 @@ export declare class ScheduleProgress {
202
202
  /**
203
203
  * そのセグメントの時間帯がもう過ぎているか。**過ぎたものは待たない。**
204
204
  *
205
- * セグメントは 0:00 から3時間ずつの枠で、`table_id` と節番号から
206
- * それがいつの枠なのかが決まる — 基本は `0x50` が当日 0:00 から4日ぶん、
207
- * `0x51` がその次の4日ぶん。詳細 (`0x58`〜) も同じ並びをもう一度たどる。
205
+ * セグメントは 0:00 から 3 時間ずつの枠で、`table_id` と節番号から
206
+ * それがいつの枠なのかが決まる。基本は `0x50` が当日 0:00 から 4 日ぶん、
207
+ * `0x51` がその次の 4 日ぶん。詳細 (`0x58`〜) も同じ並びをもう一度たどる。
208
208
  * 終わった枠は放送に乗らない (クラスの説明)。そのぶんの番組は、そこが未来だった数日前に取り込んである。
209
209
  */
210
210
  private stale;
@@ -212,13 +212,13 @@ export declare class ScheduleProgress {
212
212
  * 何が足りないか。**上限まで開いても揃わなかったときに出す。**
213
213
  *
214
214
  * 揃ったかどうかしか分からなかった頃は、上限まで開きっぱなしになっている局を
215
- * 見つけても**その先を追えなかった** — 電波が弱くて欠けているのか、
215
+ * 見つけても**その先を追えなかった。** 電波が弱くて欠けているのか、
216
216
  * こちらが来ない表を待っているのかで、直し方がまるで違う。
217
217
  */
218
218
  report(): string;
219
219
  }
220
220
  /**
221
- * 流れてくる TS を食べて番組を溜める。
221
+ * 流れてくる TS を読んで番組を溜める。
222
222
  *
223
223
  * 局ごとに `ScheduleProgress` を持ち、**その物理チャンネルに入っている局が
224
224
  * 全部揃ったら**読むのをやめられる。同じ番組が何度も来る (カルーセルなので) ので、
@@ -241,7 +241,7 @@ export declare class EpgReader {
241
241
  /**
242
242
  * @param now いまの時刻。局ごとの `ScheduleProgress` にそのまま渡す
243
243
  * @param options.other ほかの TS の局の番組表も読む。ネットワーク全局ぶんを
244
- * 1つの中継から先に入れるときに使う (denpa の `epg-collect.ts` の初回)
244
+ * 1 つの中継から先に入れるときに使う (denpa の `epg-collect.ts` の初回)
245
245
  * @param options.settle `other` のとき、新しい局が出てこなくなってから閉じるまで (ms)
246
246
  * @param options.expect `other` のとき、来るはずの局 (service_id)。全部見えて揃えば
247
247
  * `settle` を待たずに閉じる。受信できない局が混ざっていれば `settle` で閉じる
@@ -251,12 +251,12 @@ export declare class EpgReader {
251
251
  settle?: number;
252
252
  expect?: readonly number[];
253
253
  });
254
- /** 任意の長さのバイト列を食わせる。番組が1つでも増えたら true */
254
+ /** 任意の長さのバイト列を渡す。番組が 1 つでも増えたら true */
255
255
  feed(chunk: Uint8Array): boolean;
256
256
  /**
257
257
  * 溜めてあるものと混ぜる。**別の表で来るものを消し合わせない。**
258
258
  *
259
- * 番組表は2つの表に分かれて流れてくる。同じ event_id が両方に載っていて、
259
+ * 番組表は 2 つの表に分かれて流れてくる。同じ event_id が両方に載っていて、
260
260
  * **それぞれ自分のぶんの記述子しか持っていない**。
261
261
  *
262
262
  * - **基本** (table_id 0x50〜0x57) … タイトルと短い説明 (short_event_descriptor)
@@ -264,7 +264,7 @@ export declare class EpgReader {
264
264
  *
265
265
  * あとから来たもので丸ごと置き換えていた頃は、**詳細のほうが後に届いた番組の
266
266
  * タイトルが空になっていた**。実機では番組 23,000 件のうち 11,000 件が名無しで、
267
- * うち 2,700 件は「タイトルは無いのに番組内容だけある」状態 — 詳細に上書きされた
267
+ * うち 2,700 件は「タイトルは無いのに番組内容だけある」状態で、詳細に上書きされた
268
268
  * 跡そのもの。番組表には「(番組情報なし)」の列が並んでいた。
269
269
  *
270
270
  * **中身のあるほうを残す。** 書き換え (「[新]」が付く、誤字が直る) は
@@ -275,7 +275,7 @@ export declare class EpgReader {
275
275
  * p/f で「いま流れている」と言えるか。
276
276
  *
277
277
  * **`running_status` を当てにしきれない。** 4 (放送中) を入れてくる局も
278
- * あれば、**0 (未定義) しか入れてこない局もある** — 実機の NHK は 74 節
278
+ * あれば、**0 (未定義) しか入れてこない局もある。** 実機の NHK は 74 節
279
279
  * ぜんぶ 0 だった。4 だけを見ていると、そういう局では延長追従が丸ごと
280
280
  * 効かなくなる (denpa の docs/data.md)。
281
281
  *
@@ -294,28 +294,28 @@ export declare class EpgReader {
294
294
  requeue(events: EitEvent[]): void;
295
295
  /** 溜まった番組。開始時刻の順に並べて返す */
296
296
  all(): EitEvent[];
297
- /** 番組表を1つでも見かけた局 */
297
+ /** 番組表を 1 つでも見かけた局 */
298
298
  services(): number[];
299
299
  /**
300
300
  * 見かけた局が**全部**揃ったか。
301
301
  *
302
- * 「1局でも揃えば閉じる」にはしない。1つの物理チャンネルには複数の局が
302
+ * 「1 局でも揃えば閉じる」にはしない。1 つの物理チャンネルには複数の局が
303
303
  * 入っていて (地上波なら MX1 と MX2)、先に揃ったほうで閉じると残りが
304
304
  * 永久に埋まらない。
305
305
  */
306
306
  get complete(): boolean;
307
- /** 来るはずの局を教わっていて、それが全部見えたか */
307
+ /** 来るはずの局 (`expect`) が渡されていて、それが全部見えたか */
308
308
  private sawExpected;
309
309
  /**
310
310
  * 揃っていない局と、その理由。**上限まで開いてしまったときに出す。**
311
311
  *
312
- * 1局でも揃わなければチャンネルごと上限まで開き続けるので、
312
+ * 1 局でも揃わなければチャンネルごと上限まで開き続けるので、
313
313
  * 「どの局のせいか」が分からないと直しようがない。
314
314
  */
315
315
  shortfall(): string[];
316
316
  }
317
317
  /**
318
- * **1局の「いま」と「次」(EIT[p/f]) を追う。** ライブで番組の切り替わりを知るのに使う。
318
+ * **1 局の「いま」と「次」(EIT[p/f]) を追う。** ライブで番組の切り替わりを知るのに使う。
319
319
  *
320
320
  * 番組表 (schedule) は数日先までの予定で、**延長や繰り下げには追いつかない**
321
321
  * (局が送り直してくるのは後になってから)。p/f は放送そのものに追従していて、
@@ -324,7 +324,7 @@ export declare class EpgReader {
324
324
  * section 0 が「いま」、section 1 が「次」と決まっている (`EpgReader.onAir` と同じ)。
325
325
  *
326
326
  * **中身で比べる。** 書き換われば version が上がるはずだが、上げずに中身だけ替える
327
- * 送り手を当てにしないよう、番組の番号・時刻・尺・タイトルで比べる。p/f は1局ぶん数百バイトが
327
+ * 送り手を当てにしないよう、番組の番号・時刻・尺・タイトルで比べる。p/f は 1 局ぶん数百バイトが
328
328
  * 数秒おきに来るだけなので、毎回読んでも軽い
329
329
  */
330
330
  export declare class PresentFollowing {
@@ -341,7 +341,7 @@ export declare class PresentFollowing {
341
341
  /** 次の番組 */
342
342
  get following(): EitEvent | null;
343
343
  /**
344
- * 188 バイトのパケットを1つ。**いまか次のどちらかが変わったら true**。
344
+ * 188 バイトのパケットを 1 つ。**いまか次のどちらかが変わったら true**。
345
345
  * 最初に読めたときも true (知らなかったものが分かった)
346
346
  */
347
347
  feedPacket(packet: Uint8Array): boolean;
package/dist/eit.js CHANGED
@@ -5,7 +5,7 @@
5
5
  * 空いているだけ並列に回せる**し、録画で開いているチャンネルのぶんはただで
6
6
  * 手に入る ([agent.md](https://github.com/danything/denpa/blob/main/docs/agent.md))。
7
7
  *
8
- * 扱うのは2種類。
8
+ * 扱うのは 2 種類。
9
9
  *
10
10
  * - **EIT[p/f]** (table_id 0x4E) … いま流れている番組と次の番組。**放送に追従する。**
11
11
  * 野球で延びた終了時刻はここに出る
@@ -22,9 +22,9 @@ const SCHEDULE_ACTUAL_MIN = 0x50;
22
22
  /** 詳細 (extended) の表はここから。基本と同じ並びがもう一度始まる */
23
23
  const SCHEDULE_ACTUAL_EXTENDED = 0x58;
24
24
  const SCHEDULE_ACTUAL_MAX = 0x5f;
25
- /** セグメント1つが受け持つ時間。0:00 から3時間ずつ、1日8つ */
25
+ /** セグメント 1 つが受け持つ時間。0:00 から 3 時間ずつ、1 日 8 つ */
26
26
  const SEGMENT_SPAN = 3 * 3600_000;
27
- /** 1つの table_id が持つセグメントの数 (= 4日ぶん) */
27
+ /** 1 つの table_id が持つセグメントの数 (= 4 日ぶん) */
28
28
  const SEGMENTS_PER_TABLE = 32;
29
29
  const DESC_SHORT_EVENT = 0x4d;
30
30
  const DESC_EXTENDED_EVENT = 0x4e;
@@ -42,7 +42,7 @@ function isEitActual(tableId) {
42
42
  * 並びは自局のもの (0x50〜0x5F) と同じで、`OTHER_SHIFT` だけずれている。
43
43
  *
44
44
  * BS・CS はどの中継にもネットワーク全局ぶんが流れているが、**詳細はほぼ付かない**
45
- * (実測で BS 45 局のうち2局ぶん。denpa の docs/data.md)。いま/次 (0x4F) は読まない
45
+ * (実測で BS 45 局のうち 2 局ぶん。denpa の docs/data.md)。いま/次 (0x4F) は読まない
46
46
  */
47
47
  const SCHEDULE_OTHER_MIN = 0x60;
48
48
  const SCHEDULE_OTHER_MAX = 0x6f;
@@ -59,7 +59,7 @@ const TABLE_TOT = 0x73;
59
59
  /**
60
60
  * TDT / TOT のセクションから**放送の実時刻**を読む。別のテーブルなら null。
61
61
  *
62
- * 頭3バイトのあとに MJD + BCD が5バイト。**TOT も同じ並び**で、後ろに
62
+ * 頭 3 バイトのあとに MJD + BCD が 5 バイト。**TOT も同じ並び**で、後ろに
63
63
  * 時差の記述子が付くだけなので同じに読める。
64
64
  *
65
65
  * データ放送 (`bml.ts` の `onTime`) が読み、BML の時計にします
@@ -70,9 +70,9 @@ export function parseTimeTable(section) {
70
70
  return parseMjdTime(section, 3);
71
71
  }
72
72
  /**
73
- * MJD + BCD の5バイトを epoch ms に直す。
73
+ * MJD + BCD の 5 バイトを epoch ms に直す。
74
74
  *
75
- * 全ビットが1なら「未定」。開始時刻が未定の番組は番組表に置けないので null で返す。
75
+ * 全ビットが 1 なら「未定」。開始時刻が未定の番組は番組表に置けないので null で返す。
76
76
  */
77
77
  export function parseMjdTime(data, at) {
78
78
  if ([0, 1, 2, 3, 4].every((i) => data[at + i] === 0xff))
@@ -85,7 +85,7 @@ export function parseMjdTime(data, at) {
85
85
  JST_OFFSET;
86
86
  return seconds * 1000;
87
87
  }
88
- /** BCD 3バイトの尺 (時分秒) を ms に。全ビット1なら「終了未定」 */
88
+ /** BCD 3 バイトの尺 (時分秒) を ms に。全ビット 1 なら「終了未定」 */
89
89
  export function parseBcdDuration(data, at) {
90
90
  if (data[at] === 0xff && data[at + 1] === 0xff && data[at + 2] === 0xff)
91
91
  return null;
@@ -115,7 +115,7 @@ const VIDEO_CODEC = {
115
115
  5: "h.264",
116
116
  9: "h.265",
117
117
  };
118
- /** audio_component_descriptor の sampling_rate。3ビットの符号 */
118
+ /** audio_component_descriptor の sampling_rate。3 ビットの符号 */
119
119
  const SAMPLING_RATE = {
120
120
  1: 16000,
121
121
  2: 22050,
@@ -137,13 +137,22 @@ const lang = (data, at) => ascii(data, at, 3).toLowerCase();
137
137
  * 正しくは「音楽制作:ONE MUSIC」)。分割点は
138
138
  *
139
139
  * - **二バイト文字の途中**に来ることがある (片割れだけでは字にならない)
140
- * - **文字集合の状態を持ち越す** — G0〜G3 の指示も GL/GR の呼び出しも、
140
+ * - **文字集合の状態を持ち越す。** G0〜G3 の指示も GL/GR の呼び出しも、
141
141
  * 続きの側には書き直されない。前の状態のまま読む前提で送られてくる
142
142
  *
143
143
  * ので、部分だけを単独でデコードすると、そこから先が崩れます。
144
+ *
145
+ * **ただし見出しのある項目は、同じ見出しでも別の項目として最初の状態から読む。** 見出しが同じ
146
+ * 項目が 2 つ続けて来る局があり (BS日テレの「番組内容」)、2 つ目は最初の状態 (漢字) から読む前提で
147
+ * 送られている。1 つ目が英数字に切り替えたまま (`0e 21 3f` = LS1 のあと「!?」) 終わっていると、
148
+ * バイトのまま繋いだ頃は 2 つ目の漢字が英数字で出ていた (実機の「いずれ「6'MpNa>n」と8Fばれる」。
149
+ * 正しくは「いずれ「凶乱令嬢」と呼ばれる」)。項目ごとにデコードして、文字で繋ぐ
144
150
  */
145
151
  function readDescriptors(event, body) {
146
- /** 見出しごとの生バイト。**全部揃ってからデコードする** (Map なので見出しの出てきた順に並ぶ) */
152
+ /**
153
+ * 見出しごとの項目。項目はバイト列の部分の並びで、**項目の部分が全部揃ってからデコードする**
154
+ * (Map なので見出しの出てきた順に並ぶ)
155
+ */
147
156
  const pending = new Map();
148
157
  let lastHeading = "";
149
158
  for (const [tag, data] of descriptors(body)) {
@@ -166,16 +175,19 @@ function readDescriptors(event, body) {
166
175
  const textLength = data[at];
167
176
  const text = data.subarray(at + 1, at + 1 + textLength);
168
177
  at += 1 + textLength;
169
- // 見出しが空なら前の項目の続き。改行を挟まずそのまま繋ぐ
170
- const key = heading === "" ? lastHeading : heading;
171
- if (key === "")
178
+ // 見出しが空なら前の項目の続き (バイトのまま繋ぐ)。見出しがあれば、同じ見出しでも新しい項目
179
+ if (heading === "") {
180
+ if (lastHeading === "")
181
+ continue;
182
+ pending.get(lastHeading).at(-1).push(text);
172
183
  continue;
173
- const parts = pending.get(key);
174
- if (parts === undefined)
175
- pending.set(key, [text]);
184
+ }
185
+ const items = pending.get(heading);
186
+ if (items === undefined)
187
+ pending.set(heading, [[text]]);
176
188
  else
177
- parts.push(text);
178
- lastHeading = key;
189
+ items.push([text]);
190
+ lastHeading = heading;
179
191
  }
180
192
  break;
181
193
  }
@@ -195,7 +207,7 @@ function readDescriptors(event, body) {
195
207
  break;
196
208
  }
197
209
  /*
198
- * audio_component_descriptor (ARIB STD-B10 第2部)。
210
+ * audio_component_descriptor (ARIB STD-B10 第 2 部)。
199
211
  *
200
212
  * [0] reserved(4) stream_content(4)
201
213
  * [1] component_type … ステレオ・デュアルモノ…
@@ -230,7 +242,7 @@ function readDescriptors(event, body) {
230
242
  break;
231
243
  }
232
244
  /*
233
- * series_descriptor (ARIB STD-B10 第2部)。
245
+ * series_descriptor (ARIB STD-B10 第 2 部)。
234
246
  *
235
247
  * [0..1] series_id
236
248
  * [2] repeat_label(4) program_pattern(3) expire_date_valid_flag(1)
@@ -257,12 +269,14 @@ function readDescriptors(event, body) {
257
269
  break;
258
270
  }
259
271
  }
260
- // 全部揃ってからデコードする (分割点が二バイト文字や文字集合の途中に来るため)
261
- for (const [heading, parts] of pending)
262
- event.extended[heading] = decodeAribText(joinBytes(parts));
272
+ // 項目ごとに、部分が全部揃ってからデコードする (分割点が二バイト文字や文字集合の途中に来るため)
273
+ for (const [heading, items] of pending)
274
+ event.extended[heading] = items
275
+ .map((parts) => decodeAribText(joinBytes(parts)))
276
+ .join("");
263
277
  }
264
278
  /**
265
- * EIT のセクションを1本読む。自局のもの以外は null。
279
+ * EIT のセクションを 1 本読む。自局のもの以外は null。
266
280
  *
267
281
  * 壊れたセクションは `SectionAssembler` が CRC で落としているので、ここに来るのは
268
282
  * 中身が揃っているものだけ。それでも長さの辻褄が合わないことはあるので、
@@ -335,13 +349,13 @@ export function parseEit(section, options = {}) {
335
349
  * 早く揃った局でも待たされ、遅い局は取りこぼす。EIT は自分がどこまであるかを
336
350
  * セクションの中で言っているので、それを数えれば足りる。
337
351
  *
338
- * セクションは**8本ずつのセグメント**に分かれていて、セグメントの中で実際に
352
+ * セクションは**8 本ずつのセグメント**に分かれていて、セグメントの中で実際に
339
353
  * 使われている最後の番号が `segment_last_section_number`。使われていない番号は
340
354
  * 永久に来ないので、そこまで揃えばそのセグメントは終わり。
341
355
  *
342
- * **過ぎた時間帯のセグメントは流れてこない** (`stale`)。空でも先頭の1本は必ず
356
+ * **過ぎた時間帯のセグメントは流れてこない** (`stale`)。空でも先頭の 1 本は必ず
343
357
  * 来るものとして待っていた頃は、**どのチャンネルも例外なく上限まで
344
- * 開きっぱなし**になっていた (実機14チャンネル、揃って離せたのは0本)。
358
+ * 開きっぱなし**になっていた (実機 14 チャンネル、揃って離せたのは 0 本)。
345
359
  */
346
360
  export class ScheduleProgress {
347
361
  now;
@@ -355,11 +369,11 @@ export class ScheduleProgress {
355
369
  /**
356
370
  * `table_id` → バージョン。変わったらその表だけ数え直す。
357
371
  *
358
- * **バージョンは `table_id` ごとに別々に振られる。** 番組表の1つの表 (sub_table) は
372
+ * **バージョンは `table_id` ごとに別々に振られる。** 番組表の 1 つの表 (sub_table) は
359
373
  * `table_id` + 局 + TS で決まり、`version_number` はその単位で動く。
360
- * 局に1つだけ持っていた頃は、**基本 (0x50〜) と詳細 (0x58〜) を行き来する
374
+ * 局に 1 つだけ持っていた頃は、**基本 (0x50〜) と詳細 (0x58〜) を行き来する
361
375
  * たびにバージョンが違って数えたものを全部捨てて**いた。揃ったと分かることが
362
- * 二度と無いので、どのチャンネルも上限の10分 (denpa の `epgChannelTimeout`) まで開きっぱなしになる。
376
+ * 二度と無いので、どのチャンネルも上限の 10 分 (denpa の `epgChannelTimeout`) まで開きっぱなしになる。
363
377
  */
364
378
  version = new Map();
365
379
  /**
@@ -370,7 +384,7 @@ export class ScheduleProgress {
370
384
  this.now = now;
371
385
  }
372
386
  add(section) {
373
- // p/f は番組表の完成度とは関係ない (いつでも2番組しか無い)
387
+ // p/f は番組表の完成度とは関係ない (いつでも 2 番組しか無い)
374
388
  if (section.tableId < SCHEDULE_ACTUAL_MIN)
375
389
  return;
376
390
  if (section.version !== this.version.get(section.tableId)) {
@@ -392,13 +406,13 @@ export class ScheduleProgress {
392
406
  /**
393
407
  * 使われている table_id を全部揃えられたか。
394
408
  *
395
- * **番号が飛ぶ。** 1つの `table_id` が受け持つのは4日ぶんで、基本は
396
- * `0x50` から、詳細は `0x58` から始まる。日本の放送は8日ぶんなので、
409
+ * **番号が飛ぶ。** 1 つの `table_id` が受け持つのは 4 日ぶんで、基本は
410
+ * `0x50` から、詳細は `0x58` から始まる。日本の放送は 8 日ぶんなので、
397
411
  * 実際に流れてくるのは `0x50` `0x51` と `0x58` `0x59` あたりだけで、
398
412
  * **`0x52`〜`0x57` は永久に来ません**。
399
413
  *
400
414
  * `0x50` から `last_table_id` まで全部を待っていた頃は、詳細を積んでいる局が
401
- * **一度も「揃った」にならず**、どのチャンネルも上限の10分 (denpa の `epgChannelTimeout`) まで開きっぱなしに
415
+ * **一度も「揃った」にならず**、どのチャンネルも上限の 10 分 (denpa の `epgChannelTimeout`) まで開きっぱなしに
402
416
  * なっていました (実機で、詳細の無い BS11 だけが早く閉じていた)。
403
417
  *
404
418
  * 見かけた表と、`last_table_id` が指す表だけを見ます。
@@ -438,9 +452,9 @@ export class ScheduleProgress {
438
452
  /**
439
453
  * そのセグメントの時間帯がもう過ぎているか。**過ぎたものは待たない。**
440
454
  *
441
- * セグメントは 0:00 から3時間ずつの枠で、`table_id` と節番号から
442
- * それがいつの枠なのかが決まる — 基本は `0x50` が当日 0:00 から4日ぶん、
443
- * `0x51` がその次の4日ぶん。詳細 (`0x58`〜) も同じ並びをもう一度たどる。
455
+ * セグメントは 0:00 から 3 時間ずつの枠で、`table_id` と節番号から
456
+ * それがいつの枠なのかが決まる。基本は `0x50` が当日 0:00 から 4 日ぶん、
457
+ * `0x51` がその次の 4 日ぶん。詳細 (`0x58`〜) も同じ並びをもう一度たどる。
444
458
  * 終わった枠は放送に乗らない (クラスの説明)。そのぶんの番組は、そこが未来だった数日前に取り込んである。
445
459
  */
446
460
  stale(tableId, start) {
@@ -457,7 +471,7 @@ export class ScheduleProgress {
457
471
  * 何が足りないか。**上限まで開いても揃わなかったときに出す。**
458
472
  *
459
473
  * 揃ったかどうかしか分からなかった頃は、上限まで開きっぱなしになっている局を
460
- * 見つけても**その先を追えなかった** — 電波が弱くて欠けているのか、
474
+ * 見つけても**その先を追えなかった。** 電波が弱くて欠けているのか、
461
475
  * こちらが来ない表を待っているのかで、直し方がまるで違う。
462
476
  */
463
477
  report() {
@@ -482,7 +496,7 @@ export class ScheduleProgress {
482
496
  }
483
497
  const hex = (value) => `0x${value.toString(16)}`;
484
498
  /**
485
- * 流れてくる TS を食べて番組を溜める。
499
+ * 流れてくる TS を読んで番組を溜める。
486
500
  *
487
501
  * 局ごとに `ScheduleProgress` を持ち、**その物理チャンネルに入っている局が
488
502
  * 全部揃ったら**読むのをやめられる。同じ番組が何度も来る (カルーセルなので) ので、
@@ -505,7 +519,7 @@ export class EpgReader {
505
519
  /**
506
520
  * @param now いまの時刻。局ごとの `ScheduleProgress` にそのまま渡す
507
521
  * @param options.other ほかの TS の局の番組表も読む。ネットワーク全局ぶんを
508
- * 1つの中継から先に入れるときに使う (denpa の `epg-collect.ts` の初回)
522
+ * 1 つの中継から先に入れるときに使う (denpa の `epg-collect.ts` の初回)
509
523
  * @param options.settle `other` のとき、新しい局が出てこなくなってから閉じるまで (ms)
510
524
  * @param options.expect `other` のとき、来るはずの局 (service_id)。全部見えて揃えば
511
525
  * `settle` を待たずに閉じる。受信できない局が混ざっていれば `settle` で閉じる
@@ -514,7 +528,7 @@ export class EpgReader {
514
528
  this.now = now;
515
529
  this.options = options;
516
530
  }
517
- /** 任意の長さのバイト列を食わせる。番組が1つでも増えたら true */
531
+ /** 任意の長さのバイト列を渡す。番組が 1 つでも増えたら true */
518
532
  feed(chunk) {
519
533
  let added = false;
520
534
  for (const packet of this.packets.feed(chunk)) {
@@ -547,7 +561,7 @@ export class EpgReader {
547
561
  /**
548
562
  * 溜めてあるものと混ぜる。**別の表で来るものを消し合わせない。**
549
563
  *
550
- * 番組表は2つの表に分かれて流れてくる。同じ event_id が両方に載っていて、
564
+ * 番組表は 2 つの表に分かれて流れてくる。同じ event_id が両方に載っていて、
551
565
  * **それぞれ自分のぶんの記述子しか持っていない**。
552
566
  *
553
567
  * - **基本** (table_id 0x50〜0x57) … タイトルと短い説明 (short_event_descriptor)
@@ -555,7 +569,7 @@ export class EpgReader {
555
569
  *
556
570
  * あとから来たもので丸ごと置き換えていた頃は、**詳細のほうが後に届いた番組の
557
571
  * タイトルが空になっていた**。実機では番組 23,000 件のうち 11,000 件が名無しで、
558
- * うち 2,700 件は「タイトルは無いのに番組内容だけある」状態 — 詳細に上書きされた
572
+ * うち 2,700 件は「タイトルは無いのに番組内容だけある」状態で、詳細に上書きされた
559
573
  * 跡そのもの。番組表には「(番組情報なし)」の列が並んでいた。
560
574
  *
561
575
  * **中身のあるほうを残す。** 書き換え (「[新]」が付く、誤字が直る) は
@@ -589,7 +603,7 @@ export class EpgReader {
589
603
  * p/f で「いま流れている」と言えるか。
590
604
  *
591
605
  * **`running_status` を当てにしきれない。** 4 (放送中) を入れてくる局も
592
- * あれば、**0 (未定義) しか入れてこない局もある** — 実機の NHK は 74 節
606
+ * あれば、**0 (未定義) しか入れてこない局もある。** 実機の NHK は 74 節
593
607
  * ぜんぶ 0 だった。4 だけを見ていると、そういう局では延長追従が丸ごと
594
608
  * 効かなくなる (denpa の docs/data.md)。
595
609
  *
@@ -621,14 +635,14 @@ export class EpgReader {
621
635
  all() {
622
636
  return [...this.events.values()].sort((a, b) => (a.startAt ?? 0) - (b.startAt ?? 0));
623
637
  }
624
- /** 番組表を1つでも見かけた局 */
638
+ /** 番組表を 1 つでも見かけた局 */
625
639
  services() {
626
640
  return [...this.progress.keys()];
627
641
  }
628
642
  /**
629
643
  * 見かけた局が**全部**揃ったか。
630
644
  *
631
- * 「1局でも揃えば閉じる」にはしない。1つの物理チャンネルには複数の局が
645
+ * 「1 局でも揃えば閉じる」にはしない。1 つの物理チャンネルには複数の局が
632
646
  * 入っていて (地上波なら MX1 と MX2)、先に揃ったほうで閉じると残りが
633
647
  * 永久に埋まらない。
634
648
  */
@@ -638,7 +652,7 @@ export class EpgReader {
638
652
  /*
639
653
  * ほかの TS の局まで読むときは、**来るはずの局が全部見えるか、しばらく新しい局が
640
654
  * 出てこないことも待つ。** 局ごとに流れてくる順はばらばらで、見かけた局が
641
- * 揃っただけではまだ1度も来ていない局を置いていく。来るはずの局を知っていれば
655
+ * 揃っただけではまだ 1 度も来ていない局を置いていく。来るはずの局を知っていれば
642
656
  * すぐ閉じられる (WebTS.app・Mirakurun と同じ)
643
657
  */
644
658
  if (this.options.other === true &&
@@ -652,7 +666,7 @@ export class EpgReader {
652
666
  }
653
667
  return true;
654
668
  }
655
- /** 来るはずの局を教わっていて、それが全部見えたか */
669
+ /** 来るはずの局 (`expect`) が渡されていて、それが全部見えたか */
656
670
  sawExpected() {
657
671
  const expect = this.options.expect ?? [];
658
672
  return (expect.length > 0 &&
@@ -661,7 +675,7 @@ export class EpgReader {
661
675
  /**
662
676
  * 揃っていない局と、その理由。**上限まで開いてしまったときに出す。**
663
677
  *
664
- * 1局でも揃わなければチャンネルごと上限まで開き続けるので、
678
+ * 1 局でも揃わなければチャンネルごと上限まで開き続けるので、
665
679
  * 「どの局のせいか」が分からないと直しようがない。
666
680
  */
667
681
  shortfall() {
@@ -674,7 +688,7 @@ export class EpgReader {
674
688
  }
675
689
  }
676
690
  /**
677
- * **1局の「いま」と「次」(EIT[p/f]) を追う。** ライブで番組の切り替わりを知るのに使う。
691
+ * **1 局の「いま」と「次」(EIT[p/f]) を追う。** ライブで番組の切り替わりを知るのに使う。
678
692
  *
679
693
  * 番組表 (schedule) は数日先までの予定で、**延長や繰り下げには追いつかない**
680
694
  * (局が送り直してくるのは後になってから)。p/f は放送そのものに追従していて、
@@ -683,7 +697,7 @@ export class EpgReader {
683
697
  * section 0 が「いま」、section 1 が「次」と決まっている (`EpgReader.onAir` と同じ)。
684
698
  *
685
699
  * **中身で比べる。** 書き換われば version が上がるはずだが、上げずに中身だけ替える
686
- * 送り手を当てにしないよう、番組の番号・時刻・尺・タイトルで比べる。p/f は1局ぶん数百バイトが
700
+ * 送り手を当てにしないよう、番組の番号・時刻・尺・タイトルで比べる。p/f は 1 局ぶん数百バイトが
687
701
  * 数秒おきに来るだけなので、毎回読んでも軽い
688
702
  */
689
703
  export class PresentFollowing {
@@ -706,7 +720,7 @@ export class PresentFollowing {
706
720
  return this.held[1];
707
721
  }
708
722
  /**
709
- * 188 バイトのパケットを1つ。**いまか次のどちらかが変わったら true**。
723
+ * 188 バイトのパケットを 1 つ。**いまか次のどちらかが変わったら true**。
710
724
  * 最初に読めたときも true (知らなかったものが分かった)
711
725
  */
712
726
  feedPacket(packet) {
@@ -732,7 +746,7 @@ export class PresentFollowing {
732
746
  return changed;
733
747
  }
734
748
  }
735
- /** 変わったかどうかを見る中身。**番号・時刻・尺・タイトルだけ** — 番組表に写して画面に出るもの */
749
+ /** 変わったかどうかを見る中身。**番号・時刻・尺・タイトルだけ** (番組表に写して画面に出るもの) */
736
750
  function markOf(event) {
737
751
  return `${event.eventId}:${event.startAt}:${event.duration}:${event.name}`;
738
752
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * ISO 639-2 のうち日本の放送で出てくるもの。
3
3
  *
4
- * **音声も字幕も同じ表を使う** — 字幕と音声で別に持っていた頃は
5
- * 4つ足りず、同じ放送の音声が「イタリア語」、字幕が「ita」と出る形になっていた
4
+ * **音声も字幕も同じ表を使う。** 字幕と音声で別に持っていた頃は
5
+ * 4 つ足りず、同じ放送の音声が「イタリア語」、字幕が「ita」と出る形になっていた
6
6
  */
7
7
  export declare const LANGUAGE: Record<string, string>;
package/dist/language.js CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * ISO 639-2 のうち日本の放送で出てくるもの。
3
3
  *
4
- * **音声も字幕も同じ表を使う** — 字幕と音声で別に持っていた頃は
5
- * 4つ足りず、同じ放送の音声が「イタリア語」、字幕が「ita」と出る形になっていた
4
+ * **音声も字幕も同じ表を使う。** 字幕と音声で別に持っていた頃は
5
+ * 4 つ足りず、同じ放送の音声が「イタリア語」、字幕が「ita」と出る形になっていた
6
6
  */
7
7
  export const LANGUAGE = {
8
8
  jpn: "日本語",