diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-10-05 01:16:12 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-10-05 01:16:12 +0200 |
| commit | 243bcf017b4957237b3ddf556bd0a37296eb8798 (patch) | |
| tree | 7d0820796737aad4dcfb89de7bec1e7271759af6 /packages/meshbay-client/src/cast-chromecast.js | |
| parent | ac8ed437659d765120d1b0cc9f83e942549b479f (diff) | |
| download | meshbay-243bcf017b4957237b3ddf556bd0a37296eb8798.tar.gz | |
feat(cast): photos on the TV, and a television chosen once for the session
A cast button in Videos' toolbar, at the top of Photos, in an album's bar and
in the lightbox, in a group and in Search alike. A television chosen there is
kept for the session: a film opened plays on it with the player as its remote
from the start, and a photo opened in the lightbox is shown on it, scaled to
1920x1080, upright, as JPEG. The lightbox gains a slideshow.
The relay serves one photo at /image behind the stream's token, on the desktop
and on Android; the shell, not the page, decides that the receiver loads it as
a picture.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-client/src/cast-chromecast.js')
| -rw-r--r-- | packages/meshbay-client/src/cast-chromecast.js | 18 |
1 files changed, 12 insertions, 6 deletions
diff --git a/packages/meshbay-client/src/cast-chromecast.js b/packages/meshbay-client/src/cast-chromecast.js index 55deb5b..4c8ddf0 100644 --- a/packages/meshbay-client/src/cast-chromecast.js +++ b/packages/meshbay-client/src/cast-chromecast.js @@ -41,12 +41,18 @@ const TEXT_TRACK_STYLE = Object.freeze({ }); /** - * What to hand `player.load()` for a stream, with or without subtitles. + * What to hand `player.load()` for a stream, with or without subtitles, or + * for a photo. * * `streamType: 'LIVE'` because the relay has no beginning to seek back to — * the film's own timeline lives on this side, and a seek restarts the relay. + * A photo is not a stream at all. */ -function mediaFor(mediaUrl, subtitle) { +function mediaFor(mediaUrl, subtitle, contentType) { + if (contentType && contentType.startsWith('image/')) { + return { contentId: mediaUrl, contentType, streamType: 'NONE', + metadata: { metadataType: 4 } }; // PhotoMediaMetadata + } const media = { contentId: mediaUrl, contentType: 'video/mp4', @@ -139,7 +145,7 @@ class CastChromecast { } } - async connect(deviceId, mediaUrl, subtitle) { + async connect(deviceId, mediaUrl, subtitle, contentType) { const device = this._devices.get(deviceId); if (!device) throw new Error(`Unknown device: ${deviceId}`); @@ -179,7 +185,7 @@ class CastChromecast { debug(`[cast-chromecast] loading with ${subtitle?.url ? 'subtitles' : 'no subtitles'}`); const status = await new Promise((resolve, reject) => { - player.load(mediaFor(mediaUrl, subtitle), loadOptionsFor(subtitle), + player.load(mediaFor(mediaUrl, subtitle, contentType), loadOptionsFor(subtitle), (err, s) => { if (err) return reject(err); resolve(s); @@ -191,12 +197,12 @@ class CastChromecast { return { deviceName: device.name, playerState: status.playerState }; } - async reload(mediaUrl, subtitle) { + async reload(mediaUrl, subtitle, contentType) { if (!this._player) throw new Error('Not connected'); debug(`[cast-chromecast] reloading stream on "${this._connectedDevice?.name}"` + ` with ${subtitle?.url ? 'subtitles' : 'no subtitles'}`); const status = await new Promise((resolve, reject) => { - this._player.load(mediaFor(mediaUrl, subtitle), loadOptionsFor(subtitle), + this._player.load(mediaFor(mediaUrl, subtitle, contentType), loadOptionsFor(subtitle), (err, s) => { if (err) return reject(err); resolve(s); |