From bfcaba4acdabf04f9c884cf0c6efd61422261087 Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Fri, 21 Feb 2025 17:49:44 -0700 Subject: [PATCH 1/9] ui: attempt to fix a15 e2e enforcement bugs Certain devices (mostly Sony for some reason???) have bugged e2e enforcement that actually breaks it on my app. Try to see if we can "fix" this by disabling the enforcement using the optOut flag. --- app/src/main/AndroidManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2d0499edd..d1166adff 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -34,6 +34,7 @@ android:supportsRtl="true" android:theme="@style/Theme.Auxio.App" android:appCategory="audio" + android:windowOptOutEdgeToEdgeEnforcement="true" android:enableOnBackInvokedCallback="true" tools:ignore="UnusedAttribute"> From b306456d46d6fb145835e13beac792568cec725a Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Sat, 22 Feb 2025 21:00:59 -0700 Subject: [PATCH 2/9] musikr: fix hang on metadata extraction When files read all the way to EOF. --- musikr/src/main/cpp/JInputStream.cpp | 29 ++++++++++++------- musikr/src/main/cpp/JInputStream.h | 1 + .../musikr/metadata/NativeInputStream.kt | 7 ++--- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/musikr/src/main/cpp/JInputStream.cpp b/musikr/src/main/cpp/JInputStream.cpp index 8c729a8db..b003b9eda 100644 --- a/musikr/src/main/cpp/JInputStream.cpp +++ b/musikr/src/main/cpp/JInputStream.cpp @@ -34,7 +34,7 @@ JInputStream::JInputStream(JNIEnv *env, jobject jInputStream) : env(env), jInput jmethodID jInputStreamNameMethod = jInputStreamClass.method("name", "()Ljava/lang/String;"); jInputStreamReadBlockMethod = jInputStreamClass.method("readBlock", - "(Ljava/nio/ByteBuffer;)Z"); + "(Ljava/nio/ByteBuffer;)I"); jInputStreamIsOpenMethod = jInputStreamClass.method("isOpen", "()Z"); jInputStreamSeekFromBeginningMethod = jInputStreamClass.method( "seekFromBeginning", "(J)Z"); @@ -58,22 +58,31 @@ TagLib::FileName /* const char * */JInputStream::name() const { return _name.toCString(true); } -TagLib::ByteVector JInputStream::readBlock(size_t length) { - // We have to invert the buffer allocation here siits not a perfect system (vykeen instead of korvax0 but i warped all over the hub and i dont think its possible to find a "perfect" purple system like you would withnce the JVM ByteBuffer allocation system - // uses a bugged caching mechanism that leaks memory if used in multithreaded contexts. - TagLib::ByteVector buf { static_cast(length), 0 }; +jint JInputStream::readBlockImpl(TagLib::ByteVector &buf) { jobject wrappedByteBuffer = env->NewDirectByteBuffer(buf.data(), buf.size()); if (wrappedByteBuffer == nullptr) { throw std::runtime_error("Failed to wrap ByteBuffer"); } - JObjectRef byteBuffer = { env, wrappedByteBuffer }; - jboolean result = env->CallBooleanMethod(jInputStream, - jInputStreamReadBlockMethod, *byteBuffer); - if (!result) { + JObjectRef byteBuffer { env, wrappedByteBuffer }; + jint read = env->CallIntMethod(jInputStream, jInputStreamReadBlockMethod, + *byteBuffer); + return read; +} + +TagLib::ByteVector JInputStream::readBlock(size_t length) { + // We have to invert the buffer allocation here + TagLib::ByteVector buf { static_cast(length), 0 }; + jint read = readBlockImpl(buf); + if (read >= 0) { + buf.resize(read); + return buf; + } else if (read == -1) { + buf.resize(0); + return buf; + } else { throw std::runtime_error("Failed to read block, see logs"); } - return buf; } void JInputStream::writeBlock(const TagLib::ByteVector &data) { diff --git a/musikr/src/main/cpp/JInputStream.h b/musikr/src/main/cpp/JInputStream.h index 026e6c3c3..5245dbe96 100644 --- a/musikr/src/main/cpp/JInputStream.h +++ b/musikr/src/main/cpp/JInputStream.h @@ -124,6 +124,7 @@ private: jmethodID jInputStreamSeekFromEndMethod; jmethodID jInputStreamTellMethod; jmethodID jInputStreamLengthMethod; + jint readBlockImpl(TagLib::ByteVector &buf); }; #endif //AUXIO_JINPUTSTREAM_H diff --git a/musikr/src/main/java/org/oxycblt/musikr/metadata/NativeInputStream.kt b/musikr/src/main/java/org/oxycblt/musikr/metadata/NativeInputStream.kt index b8c22fb24..c7486e220 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/metadata/NativeInputStream.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/metadata/NativeInputStream.kt @@ -28,13 +28,12 @@ internal class NativeInputStream(private val deviceFile: DeviceFile, fis: FileIn fun name() = requireNotNull(deviceFile.path.name) - fun readBlock(buf: ByteBuffer): Boolean { + fun readBlock(buf: ByteBuffer): Int { try { - channel.read(buf) - return true + return channel.read(buf) } catch (e: Exception) { Log.d("NativeInputStream", "Error reading block", e) - return false + return -2 } } From 117678a0666a479575bc71d5802cd6132430e8e2 Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Sat, 22 Feb 2025 22:35:27 -0700 Subject: [PATCH 3/9] musikr: fix metadata drift Largely a temporary compat measure to avoid playlist destruction, will retire UIDs for a new system soon which should give me the ability to rethink the spec. --- .../src/main/java/org/oxycblt/musikr/model/AlbumImpl.kt | 2 +- .../java/org/oxycblt/musikr/tag/interpret/PreMusic.kt | 9 ++++++--- .../org/oxycblt/musikr/tag/interpret/TagInterpreter.kt | 3 ++- .../main/java/org/oxycblt/musikr/tag/parse/TagParser.kt | 4 ++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/musikr/src/main/java/org/oxycblt/musikr/model/AlbumImpl.kt b/musikr/src/main/java/org/oxycblt/musikr/model/AlbumImpl.kt index 99817b6eb..6031569b8 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/model/AlbumImpl.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/model/AlbumImpl.kt @@ -50,7 +50,7 @@ class AlbumImpl internal constructor(private val core: AlbumCore) : Album { // I don't know if there is any situation where an artist will have two albums with // the exact same name, but if there is, I would love to know. update(preAlbum.rawName) - update(preAlbum.preArtists.map { it.rawName }) + update(preAlbum.preArtists.mapNotNull { it.rawName }) } override val name = preAlbum.name override val releaseType = preAlbum.releaseType diff --git a/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/PreMusic.kt b/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/PreMusic.kt index 4d8831acf..1760039b1 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/PreMusic.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/PreMusic.kt @@ -51,7 +51,8 @@ internal data class PreSong( val cover: Cover?, val preAlbum: PreAlbum, val preArtists: List, - val preGenres: List + val preGenres: List, + val compatAlbumArtistNames: List ) { val uid = musicBrainzId?.let { Music.UID.musicBrainz(Music.UID.Item.SONG, it) } @@ -66,8 +67,10 @@ internal data class PreSong( update(track) update(disc?.number) - update(preArtists.map { artist -> artist.rawName }) - update(preAlbum.preArtists.map { artist -> artist.rawName }) + update(preArtists.mapNotNull { artist -> artist.rawName }) + // We have to encode the album artist names as-is w/o the interpreter's actions to + // maintain UID parity + update(compatAlbumArtistNames) } } diff --git a/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/TagInterpreter.kt b/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/TagInterpreter.kt index 1deb269aa..efab3b609 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/TagInterpreter.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/TagInterpreter.kt @@ -83,7 +83,8 @@ private class TagInterpreterImpl(private val interpretation: Interpretation) : T preAlbum = preAlbum, preArtists = rawArtists, preGenres = rawGenres, - cover = song.cover) + cover = song.cover, + compatAlbumArtistNames = song.tags.albumArtistNames) } private fun makePreAlbum( diff --git a/musikr/src/main/java/org/oxycblt/musikr/tag/parse/TagParser.kt b/musikr/src/main/java/org/oxycblt/musikr/tag/parse/TagParser.kt index 42d76af43..e3fe90f0f 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/tag/parse/TagParser.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/tag/parse/TagParser.kt @@ -38,14 +38,14 @@ private data object TagParserImpl : TagParser { replayGainTrackAdjustment = metadata.replayGainTrackAdjustment(), replayGainAlbumAdjustment = metadata.replayGainAlbumAdjustment(), musicBrainzId = metadata.musicBrainzId(), - name = metadata.name() ?: unlikelyToBeNull(file.path.name), + name = metadata.name() ?: unlikelyToBeNull(file.path.name).split('.').first(), sortName = metadata.sortName(), track = metadata.track(), disc = metadata.disc(), subtitle = metadata.subtitle(), date = metadata.date(), albumMusicBrainzId = metadata.albumMusicBrainzId(), - albumName = metadata.albumName(), + albumName = metadata.albumName() ?: file.path.directory.name, albumSortName = metadata.albumSortName(), // Compilation flag implies a compilation release type in the case that // we don't have any other release types From 3834e92192fca45b4c99b7c5fddd0051ed929b57 Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Mon, 24 Feb 2025 06:58:10 -0700 Subject: [PATCH 4/9] musikr: add backwards compat for v4 uids This annoying hack should be temporary once I can build a new UID system and migrate everything over. --- .../org/oxycblt/musikr/cache/CacheDatabase.kt | 4 +- .../org/oxycblt/musikr/graph/MusicGraph.kt | 2 +- .../org/oxycblt/musikr/model/LibraryImpl.kt | 4 +- .../java/org/oxycblt/musikr/model/SongImpl.kt | 5 +- .../oxycblt/musikr/pipeline/ExtractStep.kt | 2 +- .../oxycblt/musikr/tag/interpret/PreMusic.kt | 27 ++------- .../musikr/tag/interpret/TagInterpreter.kt | 56 ++++++++++++++++--- .../oxycblt/musikr/tag/parse/ParsedTags.kt | 2 +- .../org/oxycblt/musikr/tag/parse/TagParser.kt | 10 ++-- 9 files changed, 67 insertions(+), 45 deletions(-) diff --git a/musikr/src/main/java/org/oxycblt/musikr/cache/CacheDatabase.kt b/musikr/src/main/java/org/oxycblt/musikr/cache/CacheDatabase.kt index c4744c29e..d1700777c 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/cache/CacheDatabase.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/cache/CacheDatabase.kt @@ -41,7 +41,7 @@ import org.oxycblt.musikr.tag.parse.ParsedTags import org.oxycblt.musikr.util.correctWhitespace import org.oxycblt.musikr.util.splitEscaped -@Database(entities = [CachedSong::class], version = 58, exportSchema = false) +@Database(entities = [CachedSong::class], version = 60, exportSchema = false) internal abstract class CacheDatabase : RoomDatabase() { abstract fun visibleDao(): VisibleCacheDao @@ -97,7 +97,7 @@ internal data class CachedSong( val bitrateHz: Int, val sampleRateHz: Int, val musicBrainzId: String?, - val name: String, + val name: String?, val sortName: String?, val track: Int?, val disc: Int?, diff --git a/musikr/src/main/java/org/oxycblt/musikr/graph/MusicGraph.kt b/musikr/src/main/java/org/oxycblt/musikr/graph/MusicGraph.kt index 0d0e6104f..3bce98c69 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/graph/MusicGraph.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/graph/MusicGraph.kt @@ -55,7 +55,7 @@ private class MusicGraphBuilderImpl : MusicGraph.Builder { private val playlistVertices = mutableSetOf() override fun add(preSong: PreSong) { - val uid = preSong.uid + val uid = preSong.v363Uid if (songVertices.containsKey(uid)) { return } diff --git a/musikr/src/main/java/org/oxycblt/musikr/model/LibraryImpl.kt b/musikr/src/main/java/org/oxycblt/musikr/model/LibraryImpl.kt index badcada45..e60d4f662 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/model/LibraryImpl.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/model/LibraryImpl.kt @@ -37,6 +37,7 @@ internal data class LibraryImpl( private val playlistInterpreter: PlaylistInterpreter ) : MutableLibrary { private val songUidMap = songs.associateBy { it.uid } + private val v400SongUidMap = songs.associateBy { it.v400Uid } private val albumUidMap = albums.associateBy { it.uid } private val artistUidMap = artists.associateBy { it.uid } private val genreUidMap = genres.associateBy { it.uid } @@ -44,7 +45,8 @@ internal data class LibraryImpl( override fun empty() = songs.isEmpty() - override fun findSong(uid: Music.UID) = songUidMap[uid] + // Compat hack. See TagInterpreter for why this needs to be done + override fun findSong(uid: Music.UID) = songUidMap[uid] ?: v400SongUidMap[uid] override fun findSongByPath(path: Path) = songs.find { it.path == path } diff --git a/musikr/src/main/java/org/oxycblt/musikr/model/SongImpl.kt b/musikr/src/main/java/org/oxycblt/musikr/model/SongImpl.kt index 6a34168c6..383abf11c 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/model/SongImpl.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/model/SongImpl.kt @@ -42,7 +42,10 @@ internal interface SongCore { internal class SongImpl(private val handle: SongCore) : Song { private val preSong = handle.preSong - override val uid = preSong.uid + override val uid = preSong.v363Uid + + val v400Uid = preSong.v400Uid + override val name = preSong.name override val track = preSong.track override val disc = preSong.disc diff --git a/musikr/src/main/java/org/oxycblt/musikr/pipeline/ExtractStep.kt b/musikr/src/main/java/org/oxycblt/musikr/pipeline/ExtractStep.kt index 858421457..1d204fe5a 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/pipeline/ExtractStep.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/pipeline/ExtractStep.kt @@ -131,7 +131,7 @@ private class ExtractStepImpl( metadata .map { fileWith -> if (fileWith.with != null) { - val tags = tagParser.parse(fileWith.file, fileWith.with) + val tags = tagParser.parse(fileWith.with) val cover = fileWith.with.cover?.let { storedCovers.write(it) } RawSong(fileWith.file, fileWith.with.properties, tags, cover, addingMs) } else { diff --git a/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/PreMusic.kt b/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/PreMusic.kt index 1760039b1..d5722b0a6 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/PreMusic.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/PreMusic.kt @@ -29,9 +29,10 @@ import org.oxycblt.musikr.tag.Disc import org.oxycblt.musikr.tag.Name import org.oxycblt.musikr.tag.ReleaseType import org.oxycblt.musikr.tag.ReplayGainAdjustment -import org.oxycblt.musikr.util.update internal data class PreSong( + val v363Uid: Music.UID, + val v400Uid: Music.UID, val musicBrainzId: UUID?, val name: Name.Known, val rawName: String, @@ -51,28 +52,8 @@ internal data class PreSong( val cover: Cover?, val preAlbum: PreAlbum, val preArtists: List, - val preGenres: List, - val compatAlbumArtistNames: List -) { - val uid = - musicBrainzId?.let { Music.UID.musicBrainz(Music.UID.Item.SONG, it) } - ?: Music.UID.auxio(Music.UID.Item.SONG) { - // Song UIDs are based on the raw data without parsing so that they remain - // consistent across music setting changes. Parents are not held up to the - // same standard since grouping is already inherently linked to settings. - update(rawName) - update(preAlbum.rawName) - update(date) - - update(track) - update(disc?.number) - - update(preArtists.mapNotNull { artist -> artist.rawName }) - // We have to encode the album artist names as-is w/o the interpreter's actions to - // maintain UID parity - update(compatAlbumArtistNames) - } -} + val preGenres: List +) {} internal data class PreAlbum( val musicBrainzId: UUID?, diff --git a/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/TagInterpreter.kt b/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/TagInterpreter.kt index efab3b609..c74db7940 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/TagInterpreter.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/TagInterpreter.kt @@ -19,6 +19,8 @@ package org.oxycblt.musikr.tag.interpret import org.oxycblt.musikr.Interpretation +import org.oxycblt.musikr.Music +import org.oxycblt.musikr.fs.DeviceFile import org.oxycblt.musikr.fs.Format import org.oxycblt.musikr.pipeline.RawSong import org.oxycblt.musikr.tag.Disc @@ -29,6 +31,7 @@ import org.oxycblt.musikr.tag.ReplayGainAdjustment import org.oxycblt.musikr.tag.format.parseId3GenreNames import org.oxycblt.musikr.tag.parse.ParsedTags import org.oxycblt.musikr.util.toUuidOrNull +import org.oxycblt.musikr.util.update internal interface TagInterpreter { fun interpret(song: RawSong): PreSong @@ -53,13 +56,49 @@ private class TagInterpreterImpl(private val interpretation: Interpretation) : T song.tags.albumArtistSortNames, interpretation) val preAlbum = - makePreAlbum(song.tags, individualPreArtists, albumPreArtists, interpretation) + makePreAlbum( + song.tags, song.file, individualPreArtists, albumPreArtists, interpretation) val rawArtists = individualPreArtists.ifEmpty { albumPreArtists }.ifEmpty { listOf(unknownPreArtist()) } val rawGenres = makePreGenres(song.tags, interpretation).ifEmpty { listOf(unknownPreGenre()) } val uri = song.file.uri + + val songNameOrFile = song.tags.name ?: requireNotNull(song.file.path.name) + val songNameOrFileWithoutExt = + song.tags.name ?: requireNotNull(song.file.path.name).split('.').first() + val albumNameOrDir = song.tags.albumName ?: song.file.path.directory.name + val v363uid = + Music.UID.auxio(Music.UID.Item.SONG) { + update(songNameOrFileWithoutExt) + update(albumNameOrDir) + update(song.tags.date) + + update(song.tags.track) + update(song.tags.disc) + + update(song.tags.artistNames) + update(song.tags.albumArtistNames) + } + + // I was an idiot and accidentally changed the UID spec in v4.0.0, so we need to calculate + // the broken UID too and maintain compat for that version. + val v400uid = + Music.UID.auxio(Music.UID.Item.SONG) { + update(songNameOrFile) + update(song.tags.albumName) + update(song.tags.date) + + update(song.tags.track) + update(song.tags.disc) + + update(song.tags.artistNames.ifEmpty { listOf(null) }) + update(song.tags.albumArtistNames.ifEmpty { listOf(null) }) + } + return PreSong( + v363Uid = v363uid, + v400Uid = v400uid, uri = uri, path = song.file.path, size = song.file.size, @@ -67,8 +106,8 @@ private class TagInterpreterImpl(private val interpretation: Interpretation) : T modifiedMs = song.file.modifiedMs, addedMs = song.addedMs, musicBrainzId = song.tags.musicBrainzId?.toUuidOrNull(), - name = interpretation.naming.name(song.tags.name, song.tags.sortName), - rawName = song.tags.name, + name = interpretation.naming.name(songNameOrFileWithoutExt, song.tags.sortName), + rawName = songNameOrFileWithoutExt, track = song.tags.track, disc = song.tags.disc?.let { Disc(it, song.tags.subtitle) }, date = song.tags.date, @@ -83,22 +122,21 @@ private class TagInterpreterImpl(private val interpretation: Interpretation) : T preAlbum = preAlbum, preArtists = rawArtists, preGenres = rawGenres, - cover = song.cover, - compatAlbumArtistNames = song.tags.albumArtistNames) + cover = song.cover) } private fun makePreAlbum( parsedTags: ParsedTags, + deviceFile: DeviceFile, individualPreArtists: List, albumPreArtists: List, interpretation: Interpretation ): PreAlbum { + val name = parsedTags.albumName ?: deviceFile.path.directory.name return PreAlbum( musicBrainzId = parsedTags.albumMusicBrainzId?.toUuidOrNull(), - name = - interpretation.naming.name( - parsedTags.albumName, parsedTags.albumSortName, Placeholder.ALBUM), - rawName = parsedTags.albumName, + name = interpretation.naming.name(name, parsedTags.albumSortName, Placeholder.ALBUM), + rawName = name, releaseType = ReleaseType.parse(interpretation.separators.split(parsedTags.releaseTypes)) ?: ReleaseType.Album(null), diff --git a/musikr/src/main/java/org/oxycblt/musikr/tag/parse/ParsedTags.kt b/musikr/src/main/java/org/oxycblt/musikr/tag/parse/ParsedTags.kt index a7dc4d3c5..1d7198a56 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/tag/parse/ParsedTags.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/tag/parse/ParsedTags.kt @@ -25,7 +25,7 @@ internal data class ParsedTags( val replayGainTrackAdjustment: Float? = null, val replayGainAlbumAdjustment: Float? = null, val musicBrainzId: String? = null, - val name: String, + val name: String? = null, val sortName: String? = null, val track: Int? = null, val disc: Int? = null, diff --git a/musikr/src/main/java/org/oxycblt/musikr/tag/parse/TagParser.kt b/musikr/src/main/java/org/oxycblt/musikr/tag/parse/TagParser.kt index e3fe90f0f..a4dbda470 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/tag/parse/TagParser.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/tag/parse/TagParser.kt @@ -18,12 +18,10 @@ package org.oxycblt.musikr.tag.parse -import org.oxycblt.musikr.fs.DeviceFile import org.oxycblt.musikr.metadata.Metadata -import org.oxycblt.musikr.util.unlikelyToBeNull internal interface TagParser { - fun parse(file: DeviceFile, metadata: Metadata): ParsedTags + fun parse(metadata: Metadata): ParsedTags companion object { fun new(): TagParser = TagParserImpl @@ -31,21 +29,21 @@ internal interface TagParser { } private data object TagParserImpl : TagParser { - override fun parse(file: DeviceFile, metadata: Metadata): ParsedTags { + override fun parse(metadata: Metadata): ParsedTags { val compilation = metadata.isCompilation() return ParsedTags( durationMs = metadata.properties.durationMs, replayGainTrackAdjustment = metadata.replayGainTrackAdjustment(), replayGainAlbumAdjustment = metadata.replayGainAlbumAdjustment(), musicBrainzId = metadata.musicBrainzId(), - name = metadata.name() ?: unlikelyToBeNull(file.path.name).split('.').first(), + name = metadata.name(), sortName = metadata.sortName(), track = metadata.track(), disc = metadata.disc(), subtitle = metadata.subtitle(), date = metadata.date(), albumMusicBrainzId = metadata.albumMusicBrainzId(), - albumName = metadata.albumName() ?: file.path.directory.name, + albumName = metadata.albumName(), albumSortName = metadata.albumSortName(), // Compilation flag implies a compilation release type in the case that // we don't have any other release types From 582b0c6eef5c6cdb25079541bfb3fa17363496d7 Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Mon, 24 Feb 2025 07:53:20 -0700 Subject: [PATCH 5/9] musikr: fix uid compat issues --- musikr/src/main/java/org/oxycblt/musikr/graph/MusicGraph.kt | 6 ++++-- .../java/org/oxycblt/musikr/tag/interpret/TagInterpreter.kt | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/musikr/src/main/java/org/oxycblt/musikr/graph/MusicGraph.kt b/musikr/src/main/java/org/oxycblt/musikr/graph/MusicGraph.kt index 3bce98c69..fc9420618 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/graph/MusicGraph.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/graph/MusicGraph.kt @@ -140,8 +140,10 @@ private class MusicGraphBuilderImpl : MusicGraph.Builder { vertex.genreVertices = vertex.genreVertices.distinct().toMutableList() playlistVertices.forEach { - val pointer = SongPointer.UID(entry.key) - it.pointerMap[pointer]?.forEach { index -> it.songVertices[index] = vertex } + val v363Pointer = SongPointer.UID(entry.key) + it.pointerMap[v363Pointer]?.forEach { index -> it.songVertices[index] = vertex } + val v400Pointer = SongPointer.UID(entry.value.preSong.v400Uid) + it.pointerMap[v400Pointer]?.forEach { index -> it.songVertices[index] = vertex } } } diff --git a/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/TagInterpreter.kt b/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/TagInterpreter.kt index c74db7940..e8958071e 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/TagInterpreter.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/TagInterpreter.kt @@ -92,8 +92,10 @@ private class TagInterpreterImpl(private val interpretation: Interpretation) : T update(song.tags.track) update(song.tags.disc) - update(song.tags.artistNames.ifEmpty { listOf(null) }) - update(song.tags.albumArtistNames.ifEmpty { listOf(null) }) + val artistNames = interpretation.separators.split(song.tags.artistNames) + update(artistNames.ifEmpty { listOf(null) }) + val albumArtistNames = interpretation.separators.split(song.tags.albumArtistNames) + update(albumArtistNames.ifEmpty { artistNames }.ifEmpty { listOf(null) }) } return PreSong( From 50e2dde6e24eb23efee982daa76f2812f681a8ef Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Mon, 24 Feb 2025 07:54:12 -0700 Subject: [PATCH 6/9] musikr: remove pipeline logs --- .../org/oxycblt/musikr/pipeline/PipelineException.kt | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/musikr/src/main/java/org/oxycblt/musikr/pipeline/PipelineException.kt b/musikr/src/main/java/org/oxycblt/musikr/pipeline/PipelineException.kt index 292d8d221..1f6efc892 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/pipeline/PipelineException.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/pipeline/PipelineException.kt @@ -18,7 +18,6 @@ package org.oxycblt.musikr.pipeline -import android.util.Log import org.oxycblt.musikr.fs.DeviceFile import org.oxycblt.musikr.playlist.PlaylistFile import org.oxycblt.musikr.playlist.interpret.PrePlaylist @@ -55,45 +54,35 @@ sealed interface WhileProcessing { internal suspend fun wrap(file: DeviceFile, block: suspend (DeviceFile) -> R): R = try { - Log.d("wrap", "Processing DeviceFile ${file.path}") block(file) } catch (e: Exception) { - Log.e("wrap", "Error while processing DeviceFile ${file.path}", e) throw PipelineException(WhileProcessing.AFile(file), e) } internal suspend fun wrap(song: RawSong, block: suspend (RawSong) -> R): R = try { - Log.d("wrap", "Processing RawSong ${song.file.path}") block(song) } catch (e: Exception) { - Log.e("wrap", "Error while processing RawSong ${song.file.path}", e) throw PipelineException(WhileProcessing.ARawSong(song), e) } internal suspend fun wrap(file: PlaylistFile, block: suspend (PlaylistFile) -> R): R = try { - Log.d("wrap", "Processing PlaylistFile ${file.name}") block(file) } catch (e: Exception) { - Log.e("wrap", "Error while processing PlaylistFile ${file.name}", e) throw PipelineException(WhileProcessing.APlaylistFile(file), e) } internal suspend fun wrap(song: PreSong, block: suspend (PreSong) -> R): R = try { - Log.d("wrap", "Processing PreSong ${song.path}") block(song) } catch (e: Exception) { - Log.e("wrap", "Error while processing PreSong ${song.path}", e) throw PipelineException(WhileProcessing.APreSong(song), e) } internal suspend fun wrap(playlist: PrePlaylist, block: suspend (PrePlaylist) -> R): R = try { - Log.d("wrap", "Processing PrePlaylist ${playlist.name}") block(playlist) } catch (e: Exception) { - Log.e("wrap", "Error while processing PrePlaylist ${playlist.name}", e) throw PipelineException(WhileProcessing.APrePlaylist(playlist), e) } From d6c251447375c3c9923c16aa77a7b304dde166b3 Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Mon, 24 Feb 2025 09:09:55 -0700 Subject: [PATCH 7/9] build: bump to v4.0.1 Bump to version 4.0.1 (60). --- CHANGELOG.md | 6 ++++++ README.md | 4 ++-- app/build.gradle | 4 ++-- fastlane/metadata/android/en-US/changelogs/60.txt | 4 ++++ 4 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/60.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e08ae917..4792b87bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 4.0.1 + +#### What's Fixed +- Fixed music loading hanging on files without tags +- Fixed playlists being destroyed in poorly tagged libraries + ## 4.0.0 #### What's New diff --git a/README.md b/README.md index 94a1126cc..07052404a 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@

Auxio

A simple, rational music player for android.

- - Latest Version + + Latest Version Releases diff --git a/app/build.gradle b/app/build.gradle index a5c6bf437..fdc1e0eab 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,8 +18,8 @@ android { defaultConfig { applicationId namespace - versionName "4.0.0" - versionCode 59 + versionName "4.0.1" + versionCode 60 minSdk min_sdk targetSdk target_sdk diff --git a/fastlane/metadata/android/en-US/changelogs/60.txt b/fastlane/metadata/android/en-US/changelogs/60.txt new file mode 100644 index 000000000..b24baaaae --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/60.txt @@ -0,0 +1,4 @@ +Auxio 4.0.0 completely overhauls the user experience, with a refreshed design based on the latest Material Design specs +and a brand new music loader with signifigant improvements to device and tag support. +This issue fixes critical issues with music loading. +For more information, see https://github.com/OxygenCobalt/Auxio/releases/tag/v4.0.1. From 91b8b387327e23c8e69cc6a42dea276079757d0f Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Mon, 24 Feb 2025 09:29:37 -0700 Subject: [PATCH 8/9] Revert "ui: attempt to fix a15 e2e enforcement bugs" This reverts commit bfcaba4acdabf04f9c884cf0c6efd61422261087. --- app/src/main/AndroidManifest.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d1166adff..2d0499edd 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -34,7 +34,6 @@ android:supportsRtl="true" android:theme="@style/Theme.Auxio.App" android:appCategory="audio" - android:windowOptOutEdgeToEdgeEnforcement="true" android:enableOnBackInvokedCallback="true" tools:ignore="UnusedAttribute"> From 98299722bc92c16fafa71a35992fc3bc95ea281e Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Mon, 24 Feb 2025 09:41:49 -0700 Subject: [PATCH 9/9] musikr: add back mbids to backported uids --- .../musikr/tag/interpret/TagInterpreter.kt | 47 ++++++++++--------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/TagInterpreter.kt b/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/TagInterpreter.kt index e8958071e..de6f07a49 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/TagInterpreter.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/TagInterpreter.kt @@ -68,35 +68,40 @@ private class TagInterpreterImpl(private val interpretation: Interpretation) : T val songNameOrFileWithoutExt = song.tags.name ?: requireNotNull(song.file.path.name).split('.').first() val albumNameOrDir = song.tags.albumName ?: song.file.path.directory.name + + val musicBrainzId = song.tags.musicBrainzId?.toUuidOrNull() val v363uid = - Music.UID.auxio(Music.UID.Item.SONG) { - update(songNameOrFileWithoutExt) - update(albumNameOrDir) - update(song.tags.date) + musicBrainzId?.let { Music.UID.musicBrainz(Music.UID.Item.SONG, it) } + ?: Music.UID.auxio(Music.UID.Item.SONG) { + update(songNameOrFileWithoutExt) + update(albumNameOrDir) + update(song.tags.date) - update(song.tags.track) - update(song.tags.disc) + update(song.tags.track) + update(song.tags.disc) - update(song.tags.artistNames) - update(song.tags.albumArtistNames) - } + update(song.tags.artistNames) + update(song.tags.albumArtistNames) + } // I was an idiot and accidentally changed the UID spec in v4.0.0, so we need to calculate // the broken UID too and maintain compat for that version. val v400uid = - Music.UID.auxio(Music.UID.Item.SONG) { - update(songNameOrFile) - update(song.tags.albumName) - update(song.tags.date) + musicBrainzId?.let { Music.UID.musicBrainz(Music.UID.Item.SONG, it) } + ?: Music.UID.auxio(Music.UID.Item.SONG) { + update(songNameOrFile) + update(song.tags.albumName) + update(song.tags.date) - update(song.tags.track) - update(song.tags.disc) + update(song.tags.track) + update(song.tags.disc) - val artistNames = interpretation.separators.split(song.tags.artistNames) - update(artistNames.ifEmpty { listOf(null) }) - val albumArtistNames = interpretation.separators.split(song.tags.albumArtistNames) - update(albumArtistNames.ifEmpty { artistNames }.ifEmpty { listOf(null) }) - } + val artistNames = interpretation.separators.split(song.tags.artistNames) + update(artistNames.ifEmpty { listOf(null) }) + val albumArtistNames = + interpretation.separators.split(song.tags.albumArtistNames) + update(albumArtistNames.ifEmpty { artistNames }.ifEmpty { listOf(null) }) + } return PreSong( v363Uid = v363uid, @@ -107,7 +112,7 @@ private class TagInterpreterImpl(private val interpretation: Interpretation) : T format = Format.infer(song.file.mimeType, song.properties.mimeType), modifiedMs = song.file.modifiedMs, addedMs = song.addedMs, - musicBrainzId = song.tags.musicBrainzId?.toUuidOrNull(), + musicBrainzId = musicBrainzId, name = interpretation.naming.name(songNameOrFileWithoutExt, song.tags.sortName), rawName = songNameOrFileWithoutExt, track = song.tags.track,