Skip to content

feat(library): add Audio tab with MediaStore scanning and queue playback - #167

Merged
Aryan447 merged 3 commits into
mainfrom
feat/audio-library
Nov 9, 2026
Merged

Aryan447 merged 3 commits into
mainfrom
feat/audio-library

Conversation

@Aryan447

@Aryan447 Aryan447 commented Nov 7, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Dedicated Audio tab (MainTab.AUDIO at canonical index 6) with MediaStore audio scanning across albums, artists, and tracks.
  • Isolates audio file extensions (FileTypeUtils.AUDIO_EXTENSIONS) to prevent polluting existing video folders or tabs.
  • Model LocalAlbum generates composite IDs from album + artist (never title alone).
  • Automatically hides the Audio tab when the device contains no audio files, while keeping it toggleable in Settings → Appearance.
  • Full browsing support for Albums (grid/list toggle via layout_audio), All tracks, and Artists, with Album detail screen.
  • Album queue playback with next/previous track navigation, per-track resume, and dedicated AudioPlayerSurface with album artwork and video gestures disabled.
  • Persistent background playback via MediaPlaybackService with notification queue controls and graceful handling of denied POST_NOTIFICATIONS permission.

Before / After

Feature Before After
Audio scanning & browsing Video-only scanning; no audio library UI Full MediaStore audio scanning & Albums/Tracks/Artists browsing
Audio player surface Blank black video view Dedicated audio surface with album artwork, seekbar & queue sheet
Album queue No album queue Album playback queue with skip next/previous controls
Background playback controls Notification next/prev triggered relative seek Notification next/prev advances through album queue

How measured

Static verification with ViewModelInitOrderTest logic (0 violations across all ViewModels). Diff checks clean with git diff --check.

Verification

  • git diff --check clean (0 errors)
  • Unit tests added: AudioModelsTest, MainTabsTest, BrowserPreferencesLayoutTest
  • CHANGELOG.md updated under Unreleased -> Added
  • New user-visible text added to res/values/strings.xml

Changelog

  • Audio library tab (MainTab.AUDIO at canonical index 6): dedicated library for local audio with MediaStore scanning across albums, artists, and tracks, plus album artwork support without polluting video folders or tabs. Automatically hides when no audio exists on device while staying toggleable in Settings → Appearance.
  • Audio browsing & layouts: browse by Albums (grid or list view, persisted independently via layout_audio), All tracks, and Artists, with album detail view and queue playback.
  • Audio player surface: dedicated audio-mode player interface featuring album artwork cover, title, artist, seekbar, queue sheet, and playback controls with video gestures disabled.
  • Audio background playback: persistent background playback with media notification and lock screen controls via MediaPlaybackService, with graceful handling when POST_NOTIFICATIONS permission is denied.

Risks

None identified; video scanning, existing video tabs, and video folder logic remain completely untouched.

Summary by Sourcery

Add a complete local audio library and queue-based playback experience without affecting existing video browsing or playback.

New Features:

  • Add a dedicated Audio library tab with MediaStore-based album, artist, and track browsing, artwork, search, and configurable album layouts.
  • Provide album and track queue playback with a dedicated audio player surface, artwork, seeking, playback controls, and background notification controls.

Bug Fixes:

  • Prevent audio files from being included in video scanning, folders, or video tabs.
  • Handle denied notification permissions without interrupting audio playback.

Enhancements:

  • Automatically hide the Audio tab when no audio is available while retaining its Appearance setting and canonical navigation position.
  • Use stable album identifiers based on album and artist metadata and add audio-specific models, preferences, and tests.

Documentation:

  • Document the new audio library, browsing, player, and background playback capabilities in the unreleased changelog.

Tests:

  • Add coverage for audio model identifiers, file-type separation, tab visibility and ordering, and audio layout preferences.

@sourcery-ai

sourcery-ai Bot commented Nov 7, 2026

Copy link
Copy Markdown

Sorry @Aryan447, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 1 day and 23 hours by commenting @sourcery-ai review. Upgrade to get a review now.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 7, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-07T07:13:06.551351Z a562f6a PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Nov 7, 2026 •

Copy link
Copy Markdown

Deploying mpvium with  Cloudflare Pages  Cloudflare Pages

Latest commit: 106a26d
Status: ✅  Deploy successful!
Preview URL: https://890e9fb0.mpvium.pages.dev
Branch Preview URL: https://feat-audio-library.mpvium.pages.dev

View logs

@sourcery-ai

sourcery-ai Bot commented Nov 7, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

Data structures

Define the audio track, album, and artist models and their composite identifiers, which underpin scanning, browsing, and playback.

  • app/src/main/java/app/aryan447/mpvium/domain/media/model/LocalAlbum.kt L1-30
  • app/src/main/java/app/aryan447/mpvium/domain/media/model/LocalAudioArtist.kt L1-18
  • app/src/main/java/app/aryan447/mpvium/domain/media/model/LocalAudioTrack.kt L1-28

API

Expose the audio library repository and scanning results as observable state, with refresh and presence-check operations for consumers.

  • app/src/main/java/app/aryan447/mpvium/domain/audio/AudioRepository.kt L1-41

Add audio-mode metadata and playback-action hooks that connect the player and media service to queue navigation.

  • app/src/main/java/app/aryan447/mpvium/ui/player/MediaPlaybackService.kt L38-42, L215-224, L229-238 (+1 small edits)
  • app/src/main/java/app/aryan447/mpvium/ui/player/PlayerViewModel.kt L192-221

Provide album and track launchers that pass audio queue URIs, the selected index, and display metadata into PlayerActivity.

  • app/src/main/java/app/aryan447/mpvium/ui/audio/AudioPlayerLauncher.kt L1-53

Uses of the API

Connect the Audio tab to the repository’s presence state and route canonical tab index 6 to the new screen.

  • app/src/main/java/app/aryan447/mpvium/ui/browser/MainScreen.kt L57-61, L208-214, L460

Register Audio as canonical tab 6, default it on, and filter it from visible tabs when no audio is present.

  • app/src/main/java/app/aryan447/mpvium/ui/browser/MainTabs.kt L5-78 (7 small edits)

Implementation

Scan MediaStore audio rows, build track records, and group them into sorted albums and artists with artwork URIs.

  • app/src/main/java/app/aryan447/mpvium/domain/audio/AudioScanUtils.kt L1-212

Add audio extension and MIME helpers while keeping audio classification separate from video-file detection.

  • app/src/main/java/app/aryan447/mpvium/utils/storage/VideoScanUtils.kt L285, L300, L350-387

Initialize audio-mode metadata in PlayerActivity, preserve audio playback across pauses, and wire service notification actions to queue navigation.

  • app/src/main/java/app/aryan447/mpvium/ui/player/PlayerActivity.kt L431-439, L3019-3038, L3315-3329 (+3 small edits)

Keep standard video controls out of audio mode and render the dedicated audio player surface instead.

  • app/src/main/java/app/aryan447/mpvium/ui/player/controls/PlayerControls.kt L189-198

UI

Add the Audio browsing screen with album layouts, track and artist views, search, refresh, and navigation into album details.

  • app/src/main/java/app/aryan447/mpvium/ui/audio/AudioScreen.kt L1-335

Add album detail browsing with play-all, shuffle, and track selection actions.

  • app/src/main/java/app/aryan447/mpvium/ui/audio/AlbumDetailScreen.kt L1-248

Render reusable album art, album and track cards, and artist rows for audio browsing and playback.

  • app/src/main/java/app/aryan447/mpvium/ui/audio/components/AlbumArtImage.kt L1-151
  • app/src/main/java/app/aryan447/mpvium/ui/audio/components/AudioCards.kt L1-334

Add the audio playback surface with artwork, seek and transport controls, repeat and shuffle, and a queue sheet.

  • app/src/main/java/app/aryan447/mpvium/ui/player/audio/AudioPlayerSurface.kt L1-520

Add user-facing strings for Audio browsing, playback, queue, empty states, and transport controls.

  • app/src/main/res/values/strings.xml L749-774

Configuration

Request Android access to MediaStore audio and register the repository in dependency injection.

  • app/src/main/AndroidManifest.xml L11
  • app/src/main/java/app/aryan447/mpvium/di/DomainModule.kt L4, L37

Persist the Audio tab’s grid/list layout independently from other library layouts.

  • app/src/main/java/app/aryan447/mpvium/preferences/BrowserPreferences.kt L42

Add the Audio tab to Appearance navigation options and define the audio-specific layout preference.

  • app/src/main/java/app/aryan447/mpvium/ui/preferences/AppearancePreferencesScreen.kt L97, L107

Make notification startup and updates tolerate denied notification permission while preserving playback service behavior.

  • app/src/main/java/app/aryan447/mpvium/ui/player/MediaPlaybackService.kt L159-160, L316-317

Add the persisted audio layout preference and its default to the browser layout preference tests.

  • app/src/test/java/app/aryan447/mpvium/preferences/BrowserPreferencesLayoutTest.kt L171-174, L197, L203-204

Documentation

Document the Audio library, browsing layouts, dedicated player, and background playback in the unreleased changelog.

  • CHANGELOG.md L10-13

Tests

Test audio model identifiers and confirm audio extensions remain separate from video-file classification.

  • app/src/test/java/app/aryan447/mpvium/domain/audio/AudioModelsTest.kt L1-74

Test canonical Audio tab registration, default visibility, and automatic hiding when no audio is present.

  • app/src/test/java/app/aryan447/mpvium/ui/browser/MainTabsTest.kt L42-45, L77-94, L100-104 (+4 small edits)

Other changes

Files not grouped.

  • app/src/main/java/app/aryan447/mpvium/ui/audio/AudioViewModel.kt L1-128

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a562f6a7fa

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +3019 to +3022
MediaPlaybackService.playbackActionListener = object : MediaPlaybackService.PlaybackActionListener {
override fun onSkipToNext() { runOnUiThread { playNext() } }
override fun onSkipToPrevious() { runOnUiThread { playPrevious() } }
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve video notification seek actions

handleFileLoaded() starts this service for every media item, so this listener is also installed during normal video playback. Notification Next/Previous then navigate the video playlist—or do nothing when there is no playlist—instead of preserving the existing ±10-second seek behavior. Restrict queue navigation to audio mode and retain seeking for video.

Useful? React with 👍 / 👎.

Comment on lines +3318 to +3321
title = fileName,
artist = viewModel.audioArtist.value,
album = viewModel.audioAlbum.value,
artUri = viewModel.audioArtUri.value,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Load metadata for the selected queue item

When a queued track is selected after the initial launch, this sets its title to the display filename but copies the previous track's artist, album, and artwork. Queues from All Tracks can span albums, so subsequent tracks show stale artist/artwork and a filename (often including the extension) instead of the track title. Update these fields from the selected queue item's metadata.

Useful? React with 👍 / 👎.

Add dedicated Audio tab with MediaStore scanning, album queues, and background playback.

Scan audio albums, artists, tracks, and album art URIs without polluting video folders or tabs; provide browsing across albums, all tracks, and artists; render an audio-mode player surface without video gestures; and integrate album queue navigation with MediaPlaybackService.

Verified
- git diff --check clean
- InitOrderChecker verified 0 violations in AudioViewModel and PlayerViewModel
- Added unit tests in AudioModelsTest, MainTabsTest, and BrowserPreferencesLayoutTest
…Surface

- PullRefreshBox: pass MutableState<Boolean> isRefreshing instead of Boolean refreshing.
- ExpressiveChoiceRow: resolve string resources outside the non-composable labelOf lambda.
- EmptyState: supply missing icon parameter (Audiotrack for empty library, Search for empty query).
- AudioPlayerSurface: correct RepeatMode package import to app.aryan447.mpvium.ui.player.RepeatMode.
- AudioPlayerSurface: collect paused, pos, and duration from MPVLib property flows.
- AudioPlayerSurface: replace nonexistent togglePause() with viewModel.pauseUnpause().
- AudioPlayerSurface: add missing player transport string resources in strings.xml.
- AudioPlayerSurface: safe-call playerActivity?.getPlaylistItemTitle() and invoke public viewModel.playPlaylistItem().
@Aryan447
Aryan447 merged commit ff25b2e into main Nov 9, 2026
6 of 7 checks passed
@Aryan447
Aryan447 deleted the feat/audio-library branch November 9, 2026 06:11

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sourcery assessment

Approved.

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.

1 participant