Skip to content

Add "Use folder cover images" setting - #123

Open
bxkr wants to merge 3 commits into
PixelPlayerHQ:mainfrom
bxkr:main
Open

Add "Use folder cover images" setting#123
bxkr wants to merge 3 commits into
PixelPlayerHQ:mainfrom
bxkr:main

Conversation

@bxkr

@bxkr bxkr commented Sep 8, 2026

Copy link
Copy Markdown

What

Adds an opt-in "Use folder cover images" setting (Settings → Library → Sync & Scanning). When enabled, a cover image sitting next to the audio file - cover.jpg, folder.jpg, albumart.png, front.jpg and the other names already listed in AlbumArtUtils.commonArtworkFileNames - is used as album art.

Why

Album art currently shows only when it is embedded in the audio file's tags. Users who keep one cover.jpg per album folder - the storage-efficient layout, and the same convention the app already follows for sibling .lrc lyrics files - get no artwork at all.

Folder scanning used to happen automatically and was removed on purpose, because it picked up unrelated images (Gallery, DCIM, Downloads) for music stored in mixed directories. findExternalAlbumArtFile and shouldTrustDirectoryArtwork survived that removal, documented as being "for explicit, controlled callers only". This PR adds that explicit caller - a setting that is off by default, so nothing changes for existing users and the original problem cannot come back unasked.

How it works

  • New readExternalAlbumArtBytes in AlbumArtUtils is wired into ensureAlbumArtCachedFile and hasLocalAlbumArt. Every local artwork consumer - lists, full player, media notification, Android Auto, widgets, palette extraction - resolves through those two, so no changes were needed in SyncWorker, the Room entities, or any UI component.
  • Folder art takes precedence over embedded art when the setting is on: a cover.jpg is usually the full-resolution original, while embedded art is often a downscaled copy.
  • The directory exclusion list is unchanged, so Music/, Download/, DCIM/, Pictures/ and friends are still ignored even when the setting is on. Only dedicated album folders qualify.
  • Folder art is copied into the existing per-song cache rather than referenced in place, so it reuses boundArtworkForCache (1536 px / JPEG q90) and stays under AlbumArtCacheManager's LRU accounting. Covers larger than 20 MB are skipped rather than read into memory.
  • The app records the effective state each cached cover was built under - the opt-in and the image permission - and reconciles it on launch, on returning to the foreground, and whenever the preference changes. That state is persisted because the cache is: covers live in filesDir and outlive the process, and a permission granted back in system settings changes what should be cached without the preference ever changing.
  • Toggling the setting either way clears the album-art cache, the "no art" markers and Coil's caches, then triggers a rescan - every cached entry was resolved under the old precedence. ImageCacheManager.clearAllCoverArtCaches() is new for this; the existing per-URI invalidation can only guess at Coil's size-suffixed keys, which is not good enough for a library-wide change.

Permission

Reading a non-audio file next to a track needs READ_MEDIA_IMAGES on API 33+ - READ_MEDIA_AUDIO does not cover image files, so without it cover.jpg is simply invisible and the feature would silently do nothing on every modern device. The permission is now declared and requested only when the user turns the setting on. Below API 33 nothing extra is requested, since READ_EXTERNAL_STORAGE is already granted during setup.

A partial "Select photos" grant on Android 14+ is deliberately treated as not granted: it gives no access to arbitrary music folders. In that case the setting stays off and an explanatory toast is shown. This is what the new SelectedPhotoAccess lint warning refers to - see the note below.

Settings search

Registered in SettingsRegistry as NAVIGABLE_CARD rather than SWITCH. A SWITCH spec flips the preference straight from the search results, which would bypass the permission prompt and persist the setting with no image access - silently doing nothing. As a navigable card, search jumps to the Library screen and highlights the real, permission-gated toggle.

Translations

Four new strings, added to values/ and all 11 locale folders (ar, de, es, fr, in, it, ko, nb, ru, tr, zh-rCN), so this adds no new MissingTranslation findings.

Local checks

Run with JDK 21 (JAVA_HOME=/opt/homebrew/opt/openjdk@21, OpenJDK 21.0.12.1) after ./gradlew clean:

Check Result
:app:compileDebugKotlin BUILD SUCCESSFUL - no new warnings
:app:testDebugUnitTest BUILD SUCCESSFUL - 590 tests, 0 failures, 0 errors (112 classes)
:app:lintDebug BUILD FAILED - 94 errors, unchanged from the base commit

lintDebug already fails on the base commit db8cd3b, which I linted separately for comparison:

Base db8cd3b This branch
Errors 94 94
Warnings 477 478
Hints 36 36

The error count is identical - those are MissingTranslation across the existing string catalogue plus media3 UnsafeOptInUsageError, and none of them are in files this PR touches. The one added warning is the SelectedPhotoAccess entry described below.

Eight new unit tests. Four in AlbumArtUtilsTest cover the new seam: bytes returned when enabled, null when disabled (the opt-in gate), null when the cover exceeds the size limit, and null in an excluded directory even when enabled. Four more in FolderAlbumArtUpdateTest cover the cache-state reconciler: first record, unchanged state, a preference change, and a permission re-grant with no preference change. The four existing findExternalAlbumArtFile tests are unchanged.

Notes for reviewers

  • One new lint warning is introduced, at AndroidManifest.xml:17: Your app is currently not handling Selected Photos Access introduced in Android 14+ [SelectedPhotoAccess]. This is expected - handling partial photo access would mean accepting a grant that cannot read arbitrary music folders, which is exactly the case this feature must reject. Happy to add a baseline entry or an explicit suppression if you'd prefer the warning silenced.
  • Verified on a physical device. The permission prompt, the notification artwork path and toggling the setting back off have been exercised on an Android 17.

@greptile-apps

greptile-apps Bot commented Sep 8, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds an opt-in setting that prefers trusted folder cover images over embedded artwork and requests image access when necessary.

  • Resolves folder artwork through the existing per-song cache while preserving directory exclusions and size limits.
  • Adds permission-gated settings UI, search navigation, preferences, translations, and cache invalidation.
  • Reconciles persisted preferences, effective permission state, and artwork caches during startup, restore, and foreground transitions.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
app/src/main/java/com/lostf1sh/pixelplayeross/PixelPlayerApplication.kt Adds application-lifetime preference and permission reconciliation so cache state follows startup, restore, and foreground transitions.
app/src/main/java/com/lostf1sh/pixelplayeross/utils/AlbumArtUtils.kt Adds permission-aware folder-cover resolution, bounded external-image reads, and effective-state comparison logic.
app/src/main/java/com/lostf1sh/pixelplayeross/presentation/viewmodel/SettingsViewModel.kt Persists folder-art changes, clears artwork caches, records effective state, and requests a full sync.
app/src/main/java/com/lostf1sh/pixelplayeross/presentation/screens/SettingsCategoryScreen.kt Adds the permission-gated folder-art toggle and accurately reflects unavailable image access.
app/src/main/java/com/lostf1sh/pixelplayeross/data/preferences/UserPreferencesRepository.kt Adds the user preference and device-local cache-state marker while excluding the marker from backups.
app/src/test/java/com/lostf1sh/pixelplayeross/utils/FolderAlbumArtUpdateTest.kt Covers initial, unchanged, and changed effective cache-state decisions.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Folder-art preference] --> B{Image permission available?}
    B -->|No| C[Use embedded artwork]
    B -->|Yes| D[Search trusted song folder]
    D -->|Cover found and within limit| E[Copy bounded cover into per-song cache]
    D -->|No usable cover| C
    F[Preference or permission transition] --> G[Reconcile effective state]
    G --> H[Clear album-art and Coil caches]
    H --> I[Trigger library rescan]
Loading

Reviews (3): Last reviewed commit: "Record and reconcile the effective cover..." | Re-trigger Greptile

Comment thread app/src/main/java/com/lostf1sh/pixelplayeross/PixelPlayerApplication.kt Outdated
@gabxln

gabxln commented Sep 9, 2026

Copy link
Copy Markdown

Could you please extend this option to include artist images located inside the folder? You could use filenames like artist.jpg, band.jpg (and .png). Unfortunately, many third-party artist images are incorrect or of low quality; this option would fix that issue!

@bxkr

bxkr commented Sep 9, 2026

Copy link
Copy Markdown
Author

Could you please extend this option to include artist images located inside the folder? You could use filenames like artist.jpg or band.jpg (and .png). Unfortunately, many third-party artist images are incorrect or of low quality; this option would fix that issue!

I think this behavior isn't as common as having the cover.jpg file in the same folder as the album (many players scan it). You can change the artist's image using the “Change Photo” button.

@gabxln

gabxln commented Sep 9, 2026

Copy link
Copy Markdown

Could you please extend this option to include artist images located inside the folder? You could use filenames like artist.jpg or band.jpg (and .png). Unfortunately, many third-party artist images are incorrect or of low quality; this option would fix that issue!

I think this behavior isn't as common as having the cover.jpg file in the same folder as the album (many players scan it). You can change the artist's image using the “Change Photo” button.

I didn't express myself very well; I meant in the Artist folder. I suggested this idea because many people have huge libraries, and doing it automatically would be more practical... but anyway, thanks :)

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.

2 participants