コンテンツにスキップ

観る

ライブ・追っかけ・録画をブラウザで観るときの使い方です。録画の観る画面 (/watch/<id>) とテレビのアプリは library.md、画面の作りは player.md にあります。

放送中のものもブラウザで観られます (/live)。WebSocket + MSE で放送に追いつき続けます (作りは stream.md)。 局は右の一覧から切り替えます。止めれば追っかけ再生になり (速さを選べ、追いついたら自分でライブに戻る)、 二カ国語・解説放送の音声も選べます (⚙ の「音声」)。

触らないでいると 2.5 秒で引っ込み、マウスを動かすか指で押せば戻ります (止めていても同じ)。 キーボードでは 空白・k で再生、← → で 10秒、c で字幕、s で切り抜き、f で全画面、< > で速さ、m で消音です (観る画面と追っかけ)。

端末ごとに決めておくものは操作バーの ⚙ (再生の設定) にまとめてあります: CMスキップ・アンビエントモード・ バックグラウンド再生・互換モード・字幕 (オフと言語)・音声 (二カ国語・解説放送)・コーデック。

サーバを入れ替えると(デプロイ)、観ている最中に配信が切れます。 コンテナごと作り直すので 数十秒戻りませんが、戻ることは分かっているので、すぐには諦めません。

切れたあと
ライブ WebSocket を張り直して同じ局を選び直す(1秒→2秒→…10秒で頭打ち)。回数の上限は無い
観る画面 同じファイルを読み直して切れた瞬間の位置へ戻す(15秒おきの続きではなく)。待ちは同じく倍々で10秒が頭打ち。続けて8回(約1分)で諦めて、観られる先 (Chrome・Edge かテレビのアプリ) を案内する。その場で流しているもの (remux-player.ts) と互換モードで canvas に描いているもの (canvas-player.ts) は、観ていた位置からリクエストし直す (数は同じ)

どちらも待っている間は「繋ぎ直しています」と出します。読めない形式や壊れたファイルは 読み直しません。 何度やっても同じなので、すぐ観られる先を案内します。

バックグラウンド再生は既定でオフです。 ホームへ戻る・別のアプリやタブへ移ると止め、戻ってきたら 続きから再開します(ライブで放送の今に張り付いていたなら、放送の今へ戻る)。オン/オフは再生画面の ⚙ の「バックグラウンド再生」で、端末ごとに覚えます(速さ・CM スキップと同じ localStorage)。

オフ(既定) オン
裏に回したとき 止める 止めない
OS・ブラウザが自分で小窓にする(全画面からホームへ戻った iPhone など) させない(disablePictureInPicture) 任せる
放送のままの MPEG-2 の音(Safari) Audio Session は auto のまま playback(裏でも鳴らす)
放送のままの MPEG-2 の音(Safari 以外) ページ(Web Audio)から直に鳴らす <audio> を通して鳴らす(メディアの再生として扱わせる)

押して開いた小窓(pip.svelte.ts)はオフでも使えます。 出している間は裏に回しても止めず、 MPEG-2 の音もオンと同じ鳴らし方にします。閉じた時点でまだ裏なら、そこで止めます。

MPEG-2 の音を <audio> に通すのは、Web Audio の音を効果音と同じに扱って裏で止めるブラウザが あるからです(テスラの車載ブラウザ)。<audio> を通すと「メディアの再生」になり、ロック画面・車の操作・ ブラウザの再生中の通知にも出て、そこで押した止める・再開は操作バーに反映します(RawEngine の remote)。 Media Session のタイトルはまだ出していません(ページのタイトルが出る)。

全画面にする方法は端末で変えます

Section titled “全画面にする方法は端末で変えます”

全画面にするのは枠ごとです(映像だけでなく字幕・データ放送・操作列も一緒に大きくする)。 ボタンのアイコン(広げる/縮める)はどの方法でも今の状態を映します。

端末 全画面にする 戻す
PC・Android・iPadOS 16.4 以降 requestFullscreen() ボタン・f・Esc・端末の戻る(UA が持つ)
それより前の iPadOS webkitRequestFullscreen() 同上
iPhone の Safari 枠を画面いっぱいに広げる(position: fixed。後ろのページは止めて黒く) ボタン・f・Esc・戻る(広げたときに履歴を1段積む。もう一度戻ると前の画面へ)

iPhone は要素の全画面を持たず、あるのは <video> だけの webkitEnterFullscreen です。 あれは映像だけを OS の再生画面に渡すので字幕・データ放送・操作列が置いていかれ、使いません。 広げたときの向きは固定できません(iPhone の Safari は screen.orientation.lock を持たない)。 横に持てば横いっぱいになります。別の画面へ移ると畳みます。

denpa は PWA なので、ブラウザの「ホーム画面に追加」でアプリのように開けます (アドレス欄もタブも出ません)。

名前が2つあると、置いたアイコンが見分けられません (どちらも「denpa」でアイコンも同じ)。 そこで、どの名前で来たかで表示名を変えられます (PWA_NAMES)。

PWA_NAMES='tv.example.com=denpa,tv.lan.example.com=denpa 宅内'

書き方は ホスト名=表示名 のカンマ区切りで、載っていない名前で来たら denpa。 name と short_name に同じものが入ります(アイコンの下に出るのは short_name で、 端末によっては十数文字で切られる)。

同じ端末に2つ置けます。 名前が違えば別のサイトで、マニフェストの id も名前ごとに 分けてある(/?host=<名前>)ので、片方がもう片方の入れ直しと見なされません。

マニフェストは static/ ではなく /manifest.webmanifest のエンドポイントで組み立てます (src/lib/server/manifest.ts)。認証は掛けていません。 ブラウザが資格情報を付けずに 取りに来るためで(auth.md)、出しているのは名前・色・アイコンの場所だけです。

ホーム画面から開いたアプリは、閉じても捨てられません。 端末が凍らせて残し、次に 開くとそのまま見せるので、前に閉じたときの一覧がリロードするまで出ていました。 見えるようになったところで1回読み直します(+layout.svelte)。通知(SSE)は 凍っている間に切られて自分では戻らず、繋ぎ直しても間に起きたことは流れてこない (溜めていない)ので、それだけでは足りません。繋ぎも同じところで張り直します(live-updates.svelte.ts)。

端末に保存して観る (オフライン)

Section titled “端末に保存して観る (オフライン)”

端末に保存したものは denpa の中だけで観ます。 ブラウザの保存領域 (IndexedDB) に置き、 ファイルとして外へは出しません (持ち出すダウンロードが無い理由は library.md)。 作りは offline.md。

電波の無いときは /offline で観ます。 /watch/<id> はサーバが組む画面なので開けず、 ナビゲーションが繋がらないとサービスワーカーが /offline へ落とします。 /offline はナビに並べません。保存・進み具合 (行の3段目に割合、下端にバー)・視聴は ふだんの一覧と観る画面でできます (オンラインの /watch は端末のコピーがあればそちらを使う)。 「サーバからも消す」予約 (outbox) を積むのは /offline の削除だけです。一覧の行の削除は その場でサーバから消し (端末のコピーも片付ける)、詳細の「端末から消す」はサーバに触りません。