Skip to content

feat: quality badges in player controls (4K, Dolby Vision, Atmos, IMAX…)#410

Merged
ProdigyV21 merged 8 commits into
ProdigyV21:mainfrom
test01203:feat/player-quality-badges
Jun 27, 2026
Merged

feat: quality badges in player controls (4K, Dolby Vision, Atmos, IMAX…)#410
ProdigyV21 merged 8 commits into
ProdigyV21:mainfrom
test01203:feat/player-quality-badges

Conversation

@test01203

Copy link
Copy Markdown
Contributor

What this adds

Small white quality-logo badges appear above the seekbar whenever the player controls overlay is visible — so you always know exactly what you're watching without opening the source picker.

Badges shown (up to 3–4 icons)

Category Examples
Resolution 4K · 1080p · 720p
Video format Dolby Vision · HDR10+ · HDR10 · HDR · IMAX
Audio format Dolby Atmos · TrueHD · DTS:X · DTS-HD MA · DTS-HD · DTS · DD+ · DD

Each badge uses the same white-on-transparent PNG assets already loaded by the source picker, so no new network dependencies are added. Text-only fallback (e.g. "480p") is used when no image asset exists.

Position

┌────────────────────────────────────────────────┐
│                                                │
│  (video)                                       │
│                                                │
│  [▶]  [⏭]  [CC]  [⚙]  [📋]          (icons) │
│                                                │
│  [4K] [DV] [Atmos]              ← NEW badges  │
│  0:42 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1:58:10  │
└────────────────────────────────────────────────┘

Implementation — 2 files, 185 insertions

PlaybackQualityBadges.kt (new, ui/components)

Self-contained module. Re-uses the same regex patterns and image URLs as StreamSelector.kt for consistent labelling across the app.

Symbol Purpose
PlaybackBadge data class — label text + optional image URL
BadgeImages Same white-on-transparent PNG CDN URLs as SourceBadgeImages
BadgeRegex Same regex corpus as StreamRegexes
buildPlaybackBadges(StreamSource) Scans quality, source, description, filename; returns ≤ 1 resolution + ≤ 1 video-format + ≤ 1 audio-format badge
PlaybackQualityBadgeRow @Composable — horizontal Row of AsyncImage (logos) or Text pills

PlayerScreen.kt

Two-line change: import PlaybackQualityBadgeRow, call it above the seekbar inside the existing bottom-controls Column.

🤖 Generated with Claude Code

The-cpu-max and others added 7 commits June 16, 2026 20:21
Vanilla JS + Supabase single-page app served alongside the existing
arvio.tv marketing site. No build step required — just static files.

Features:
- Google OAuth login (via Supabase GoTrue)
- Dashboard with watch stats and recent activity
- Profiles view — shows all ARVIO sub-profiles with active/kids badges
- Addons manager — lists all Stremio + Telegram addons with enabled status
- Watch History — paginated by movie/tv/all, delete individual entries
- Watchlist — view and remove items
- AI Subtitle Translation — toggle on/off, select model (Groq Llama 70B /
  Gemini Flash 2.5), configure auto-select and hearing-impaired removal;
  settings saved directly to cloud sync payload
- Settings — card layout, language, OLED mode, skip profile selection

Data layer: reads/writes the cloud sync payload stored in
profiles.addons.__arvioAccountSyncPayload (same format the TV app uses),
and queries watch_history/watchlist tables directly via Supabase REST.

Co-Authored-By: koby455 <koby455@gmail.com>
Android TV app (CloudSyncRepository.kt):
- Inject PluginDataStore into CloudSyncRepository
- buildCloudPayload: export pluginRepositories, pluginScrapers, pluginsEnabled
  into __arvioAccountSyncPayload so plugins survive device wipes / multi-device
- applyCloudPayload: restore repositories + scrapers from cloud on first launch
  (scraper JS code stays local-only for security; only metadata is synced)

Companion web app (app.js):
- Add IPTV section: shows all M3U playlists per profile with M3U/EPG URLs,
  enabled status, favourite groups and favourite channels
- Add Plugins section: shows all plugin repositories (name, URL, scraper count,
  last updated) and individual scrapers (name, version, supported types,
  content languages, enabled status) with global plugins toggle
- Add both to sidebar navigation

Co-Authored-By: koby455 <koby455@gmail.com>
- All navigation labels, section titles, badges, toasts, and helper
  text translated to English in app.js and index.html
- Auth screen subtitle and Google button label now in English
- timeAgo() helper uses English relative-time strings
- Hebrew remains fully supported as a selectable app language (setting
  stored in cloud sync payload as before)
- Add mock-preview.html: standalone demo page with generic sample data
  for screenshots / PR previews (no Supabase dependency)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…cPayload

- Add escapeHtml() helper and apply it to every cloud value injected into innerHTML:
  user display name/email/avatar initial, profile names, addon name/description/logo,
  IPTV playlist name/URL/EPG/profile label/fav groups+channels, plugin repo name/URL,
  scraper name/description/version/logo/types/languages, history title/poster,
  watchlist tmdb_id, settings user ID
- Add safeUrl() helper (https/http only) and use it for all image src attributes
  that come from cloud data (addon logos, scraper logos, user avatar)
- saveSyncPayload now reads the existing wrapper first and only updates
  __arvioAccountSyncPayload and __arvioAccountSyncUpdatedAt, preserving any other
  fields the TV app may have written

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Normalizes the URL via the browser's URL parser before use and
HTML-escapes it, preventing quote/attribute injection from synced
logo or avatar URLs in innerHTML img src attributes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a horizontal row of small white logo badges above the seekbar,
visible whenever the player controls overlay is shown.

Badges displayed (up to 3-4 icons per stream):
  Resolution  — 4K · 1080p · 720p  (image assets)
  Video fmt   — Dolby Vision · HDR10+ · HDR10 · HDR · IMAX
  Audio fmt   — Dolby Atmos · TrueHD · DTS:X · DTS-HD MA ·
                DTS-HD · DTS · Dolby Digital+ · Dolby Digital

New file: PlaybackQualityBadges.kt (ui/components)
  • PlaybackBadge data class — text label + optional image URL
  • BadgeImages — same white-on-transparent PNG URLs already used in
    the source picker (SourceBadgeImages)
  • BadgeRegex — same regex corpus as StreamRegexes in StreamSelector
  • buildPlaybackBadges(StreamSource): List<PlaybackBadge> — scans
    quality, source, description and filename fields; returns at most
    one resolution + one video-format + one audio-format badge
  • PlaybackQualityBadgeRow composable — Row of AsyncImage (for logo
    badges) or Text pills (for text-only badges like 480p)

PlayerScreen.kt
  • Imports PlaybackQualityBadgeRow
  • Calls it directly above the seekbar Row inside the bottom controls
    Column, so it appears and disappears with the controls overlay
@ProdigyV21

Copy link
Copy Markdown
Owner

Looks good overall and both Play/Sideload Kotlin compiles pass.

One small cleanup: PlaybackQualityBadgeRow builds badges using stream.behaviorHints?.filename, but the remember(...) keys only include quality/source/description. If the user switches to another stream where only the filename contains the HDR/DV/Atmos tags, the badges can stay stale. Please include stream.behaviorHints?.filename in the remember keys, or just remember by stream.

After that I think this is safe to merge. Nice feature, it makes the player more informative without needing to open the source picker.

…hange

The reviewer noted that remember(quality, source, description) would miss
badge-relevant data embedded only in behaviorHints.filename (e.g. a DV or
Atmos tag only present in the filename). Keying on the full StreamSource
object ensures badges are recomputed whenever any stream field changes.
@test01203

Copy link
Copy Markdown
Contributor Author

Good catch — fixed in the latest push.

remember(stream.quality, stream.source, stream.description) has been replaced with remember(stream) so the badges are recomputed whenever any field on the StreamSource changes, including behaviorHints?.filename. A stream whose quality/source/description are identical but whose filename contains the Atmos or DV tag will now correctly show those badges.

@ProdigyV21 ProdigyV21 merged commit 5f31eed into ProdigyV21:main Jun 27, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants