BlueSky & more on desktop
lazurite.stormlightlabs.org/
tauri
rust
typescript
bluesky
appview
atproto
solid
Media Viewer & Downloads#
In-app media viewing and downloading for images and videos embedded in posts.
Video Player#
BlueSky videos are HLS streams. The app.bsky.embed.video#view embed provides a playlist URL (m3u8 manifest) and an optional thumbnail.
Playback#
- Use the native
<video>element with HLS.js for manifest parsing (Safari handles HLS natively; HLS.js covers Chromium/WebKit in Tauri). - Inline player replaces the current thumbnail-as-external-link treatment in
EmbedContent. - Controls: play/pause, progress scrubber, volume, fullscreen. Use browser-native controls (
controlsattribute) initially — custom controls are a future polish item. - Muted autoplay is off by default. Player shows thumbnail with a centered play button overlay; playback starts on click.
- Respect
aspectRatiofrom the embed to size the player container and prevent layout shift. alttext from the embed is rendered below the player as a caption when present.
Fullscreen#
- Clicking a "fullscreen" control (or double-click on the player) enters native fullscreen via the Fullscreen API.
Escapeexits fullscreen (browser default).
Image Gallery#
Clicking any image in an ImageEmbed opens a full-window overlay gallery.
Overlay#
- Glass overlay:
surface_container_highestat 70% opacity +backdrop-blur: 20px. - The selected image is displayed at its natural resolution (
fullsizeURL), constrained to viewport withobject-contain. Presencefade-in on open, fade-out on close.
Navigation#
- Left/right arrows (keyboard and on-screen chevron buttons) cycle through images in the post.
- Indicators (dots or
1/4counter) show position in the set. - Single-image posts show no navigation controls.
Caption#
Below the image, display:
- Alt text from the image embed (primary caption,
body-md). - Post text (secondary,
label-sm,on_surface_variant, truncated to 2 lines with "show more" expansion). - Author handle linking to their profile.
Keyboard#
| Key | Action |
|---|---|
Escape |
Close gallery |
ArrowLeft |
Previous image |
ArrowRight |
Next image |
Gestures (future)#
Pinch-to-zoom and swipe navigation are deferred to a future milestone.
Downloads#
Users can download images and videos to their local filesystem.
Download Directory#
- Default:
~/Downloads. - Configurable via a new
download_directorysetting inapp_settings. - Settings UI: a path input with a "Browse" button that opens Tauri's directory picker dialog (
dialog.openwithdirectory: true). - The backend validates that the chosen path exists and is writable before persisting.
Setting#
| Key | Type | Default | Description |
|---|---|---|---|
download_directory |
string | ~/Downloads |
Target directory for saves |
Triggering Downloads#
- Images: a download button (icon:
i-ri-download-2-line) appears in the gallery overlay toolbar. Downloads thefullsizeURL. Also available via right-click context menu on inline images. - Videos: a download button in the video player controls area. Downloads the HLS stream — the backend fetches the m3u8 manifest, resolves the highest-quality variant, downloads all segments, and muxes into a single MP4 file.
Backend#
Video download requires server-side work because HLS streams are segmented:
// Download a media file (image or video) to the configured download directory.
// For images: direct HTTP fetch of the source URL.
// For videos: fetch m3u8 manifest, download segments, concatenate into MP4.
download_media(url: String, media_type: MediaType, filename: Option<String>) -> DownloadResult
MediaType:ImageorVideo.DownloadResult:{ path: String, bytes: u64 }.- Filename: derived from URL path if not provided. Collision handling: append
_1,_2, etc. - The command should emit progress events (
download-progress) for large video files so the frontend can show a progress indicator.
Frontend UX#
- Download button shows a brief spinner/progress indicator while active.
- On completion: success toast with the filename and "Open in Finder" action (uses
tauri-plugin-opener). - On failure: error toast with a human-readable message ("Couldn't save — check that the download folder exists").
Tauri Capabilities#
The following permissions are needed beyond what default.json currently grants:
dialog:default— for the directory picker in settings.fs:default— for writing downloaded files to disk (scoped to the user's download directory).
Constraints#
- HLS.js is a runtime dependency (~60 KB gzipped). It should be lazy-loaded only when a video embed is in view.
- Video muxing on the backend uses raw segment concatenation for MPEG-TS streams. If the CDN serves fMP4 segments, a lightweight remux step is needed — evaluate
mp4orffmpeg-sidecarcrates at implementation time. - Downloads are not queued or batched in v1. One download at a time; concurrent downloads are a future enhancement.