Skip to content

Repository files navigation

denpa

テレビを録って観るためのもの。チューナーエージェント(選局)denpa(番組表・予約・録画・エンコード・配信・ライブ視聴) の2つだけで、 メディアサーバは置きません。

チューナー ── エージェント ── denpa ── 録画(mkv) ─┬─→ ブラウザでそのまま観る
                                                    └─→ Nova (WebDAV) / 落として好きなプレイヤーで

エージェントはチャンネルを掴んで素のTSを流すだけです。番組表を読むのも、 局を選り分けるのも、CMを見つけるのも denpa がやります。

用意するもの

  • チューナー — Linux DVB (PT2/PT3、PX-S1UD など)。ドライバはホスト側に入れておく
  • B-CASカード と PC/SC 対応のリーダー
  • DockerKubernetes

イメージは公開してあるので、リポジトリを持ってくる必要はありません。

立てる

mkdir denpa && cd denpa
curl -Lo compose.yml https://raw.githubusercontent.com/danything/denpa/main/compose.prod.yml
docker compose up -d

# 入るためのパスワード。初回の起動で作られ、ここに1度だけ出ます
# (まだ出ていなければ、起動を待ってもう一度)
docker compose logs denpa | grep ベーシック認証
  1. 開くhttp://localhost:3000。ユーザー名は denpa、パスワードは上のログ
  2. チューナーを確かめる — 「チューナー」に、見つかったものが並んでいます。 本数と種別 (地上波 / 衛星) が合っていれば、そのまま次へ。 違っていたら 同じ画面で直します (LNB や「1本だけ止める」もここ)
  3. スキャンする — 同じ画面から。チャンネルは空で出荷しているので、これをやるまで 番組表も空です。地上波の総当たりで十数分
  4. 待つ — 終われば自分で番組表を集めに行きます。空いているチューナーの数だけ 並べて回るので数分
  5. 予約する — 番組表から選ぶか、「ルール」にキーワードを登録して自動で

設定ファイルを書く必要はありません。 チューナーはエージェントが /dev/dvb/* を 開いて、地上波か衛星かまで自分で判別します。直すところがあっても「チューナー」から 書けます。

うまくいかないときも「チューナー」を見てください。 エージェントとカードリーダーの 状態、スキャンの1チャンネルごとの結果、番組表がどこまで集まったかが出ます。 カードリーダーが NG のまま録ると、成功したように見えて中身が全部スクランブル されたままになります。

指しているのは latest で、これはリリースを作ったときだけ動きます。 main へ 入ったぶんは develop に積み上がるので、作業中のものが勝手に降ってくることは ありません。版を固定したいなら 0.1.0 のように書けます (0.1 と書くと その系列の最新に付いてきます) — docs/architecture.md

Kubernetes なら

curl -L https://github.com/danything/denpa/archive/refs/heads/main.tar.gz | tar xz --strip=1 denpa-main/k3s
kubectl apply -f k3s/

k3s/ は自分のクラスタ向けの例です。そのままでは使えないので、 namespace・StorageClass・Ingress のホスト名を書き換えてから当ててください。 必要なものは docs/architecture.md

いま流れているものを観る

「ライブ」を開くと、放送中のものがそのまま観られます。 左に映像、右にチャンネル (番組表と同じ並び)。前回見ていた局から開くので、テレビを点けたときと同じです。

  • 遅延は 0.5〜0.7 秒(焼くのに 0.24〜0.49 秒、貯めに 0.2 秒〜)。宅外から見て 止まるようなら、自分で貯めを伸ばして戻します
  • 止めた所から見られます。 止めている間も受け取り続けるので、電話に出て 戻ってきても追いつけます (5分ぶん)。追いかけるときは速さを選べて (最大2倍)、 追いついたら自分でライブに戻ります
  • 音声を選べます。 二カ国語の主音声/副音声も、解説放送のような音声1/音声2 も
  • 焼き方を見ながら選べます。 H.264 はどの端末でも出るほう、AV1 は軽いほう (宅外向け)。AV1 は放送の今から1秒ぶん離れます。出せない端末では H.264 に戻して、 戻した理由を出します
  • 字幕を出せます。 放送どおりの絵で出るので、録画で見る字幕と同じです (外字も崩れません)。字幕を持っている番組でだけボタンが出ます
  • データ放送を出せます (d ボタン)。テレビと同じ BML がそのまま動くので、 ニュース・気象情報・番組連動のページが出ます。指で押せるリモコン (十字・決定・色・数字) が右に並びます。天気や地域のニュースを地元のものに するには、設定に郵便番号を入れてください (docs/stream.md)
  • Hybridcast は、載っている番組で行き先だけ出します。 別のタブで開くだけで、 denpa は動かしません — 受信機の API をアプリの中に用意できず、放送局の サーバも認証された受信機を期待するためです (docs/stream.md)

録画を観る

録画一覧の行を押すと、その場で再生が始まります。 別のアプリは要りません。 番組の中身は左に並んで出ます (狭い画面では映像の下)。

  • スマホ・タブレットは開いた時点で全画面、PC は左に番組の中身・右に映像
  • どこを押しても再生と一時停止 (指のときは YouTube と同じで、押すと操作が出ます)
  • 左右の端を素早く2回で 10秒 戻す/送る。続けて押せばそのぶん重なります
  • CM 飛ばし。 CM はチャプターとして入っているので、送りのボタンで飛ばせます
  • 観終わったその場で消せます。 末尾はたいてい CM なので、流したまま押せます

焼き上がるまでは観られません。 放送そのままの TS は MPEG-2 で、ブラウザに 復号器が無いためです。その間と、エンコードに失敗した録画は、詳細から落として お手元のプレイヤーで観てください。

  • 字幕が出ます。 放送どおりの絵で出るので、テレビで見る字幕と同じです (ルビも外字も崩れません)。持っている録画でだけボタンが出ます
  • 倍速で観られます (1〜2倍)。選んだ速さは覚えています
  • 切り抜けます。 いまの場面を字幕ごとクリップボードへ
  • 続きから始まります。 途中で止めたところを覚えていて、別の端末で開いても続きます

Nova Video Player から観るときは /dav を WebDAV サーバーとして追加します (Android TV・Fire TV も同じ)。字幕はそのまま出ます — 入れ物の中に PGS で 入っています (docs/library.md)。

誰を通すか

何も設定しなくても、掛かった状態で上がります。 初回の起動で、ベーシック認証が 無ければその場で作ります。以前は設定するまで録画も WebDAV も誰でも取れる状態で、 しかも掛け忘れに気付く手立てがありませんでした。

ユーザー名は denpa で固定。パスワードは24文字を自動で作り、起動のログに 1度だけ出します。

[boot] ベーシック認証を作りました: denpa / abYHnrdeniq7npvdZNkakKQV
       設定画面から見直せます。プレイヤー (Nova) にも同じものを入れてください

以降は設定画面のベーシック認証の欄にそのまま出ています (目のボタンで表示、隣でコピー)。 Nova にも同じものを入れます。

パスワードが分からなくなったら

遠くのサーバに入れて、起動のログを流してしまったときです。画面を開くにも そのパスワードが要るので、DBから直に読みます (像に bun が入っています)。

docker compose exec denpa \
  bun -e 'import {Database} from "bun:sqlite"; const db = new Database(process.env.DENPA_DB ?? "/app/data/denpa.db", {readonly: true}); console.log(db.query("SELECT value FROM settings WHERE key = ?").get("basicAuthPassword")?.value)'
kubectl -n denpa exec deploy/denpa -- \
  bun -e 'import {Database} from "bun:sqlite"; const db = new Database(process.env.DENPA_DB ?? "/app/data/denpa.db", {readonly: true}); console.log(db.query("SELECT value FROM settings WHERE key = ?").get("basicAuthPassword")?.value)'

作り直すのは最後の手段です — 登録済みのプレイヤーが全部つながらなくなります。

LAN からは何も聞かせない

家の中の端末に毎回パスワードを入れさせたくないときは、通す網を書けます

TRUSTED_NETWORKS=10.10.0.0/16
ADDRESS_HEADER=x-forwarded-for   # 前段にリバースプロキシを置いているとき

ここから来た相手にはベーシック認証も OIDC も掛かりません。プレイヤー (Nova) に資格情報を入れずに使わせるためのものです。CIDR の カンマ区切りで、いくつでも並べられます。

ADDRESS_HEADER を忘れると誰も当たりません。 プロキシ越しだと、接続元として プロキシの住所が見えるためです。逆に、denpa へ直に届く経路が残っていると ヘッダを詐称できます — 前段を通してしか触れないことが前提です。

外から使うなら OIDC を

ベーシック認証だけでインターネットに晒さないでください。 資格情報が1つきりで、 誰が入ったのか分からず、切りたいときはパスワードごと替えるしかありません (=登録済みのプレイヤーが全部つながらなくなります)。

3つ渡すと、画面のほうは OIDC でのログインに替わります。

OIDC_ISSUER=https://login.microsoftonline.com/<tenant>/v2.0
OIDC_CLIENT_ID=...
OIDC_CLIENT_SECRET=...
OIDC_GROUP=...   # このグループに居る人だけ通す (省くと入れた人は全員)

ファイルを取りに来る口 (/api/recordings/<id>/file/dav) はベーシック認証の ままです。 プレイヤーがログイン画面へのリダイレクトを扱えないためで、 だから「画面は OIDC・プレイヤーはベーシック認証」の2本立てになります。 入れ方は docs/auth.md に。

もっと詳しく

  • docs/architecture.mdなぜこの形なのか (決めたこと・踏んだ落とし穴)
  • docs/app.mdどこに何があるか (ファイル・環境変数・画面・状態遷移)
  • docs/data.md — エージェントに都度聞くもの / denpa が持つもの
  • docs/development.md手を入れるとき (開発環境・テスト)
  • docs/player.md — ホーム画面に置く、LAN でも https で開く
  • docs/agent.md — チューナーを掴むところ (エージェント・取り合い・B-CAS)
  • docs/encode.md — CM とエンコード (字幕・AV1・CM検出)
  • docs/auth.md誰を通すか (OIDC でのログイン・ベーシック認証)
  • docs/migrate.mdEPGStation からの引き継ぎ
  • docs/roadmap.md — これから入れるもの
  • docs/stream.mdライブ視聴 (放送中のものを観る)

ライセンス

AGPL-3.0-or-later (LICENSE)。

denpa は自分の家に置いて、外から使うものです。ネットワーク越しに使わせる形で 配るなら、そのときの中身も同じ条件で渡せるようにしてほしい、という選び方です。

抱えているものは出どころのままです:

src/lib/vendor/web-bml MIT (LICENSE)。データ放送を描くところ
patches/ ffmpeg に当てている直し。上流に投げるつもりのものだけ (LGPL/GPL)
像に入れるもの ffmpeg (GPL)・libaribcaption (MIT)・join_logo_scp 一式・rounded-mplus-1m-arib (SIL OFL)。焼き方は Dockerfile

About

No description, website, or topics provided.

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages