diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index edbb85883..8a347a391 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -30,7 +30,7 @@ jobs: - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Test app with Gradle - run: ./gradlew app:test + run: ./gradlew app:testDebug - name: Build debug APK with Gradle run: ./gradlew app:packageDebug - name: Upload debug APK artifact diff --git a/app/src/main/java/org/oxycblt/auxio/music/extractor/MetadataExtractor.kt b/app/src/main/java/org/oxycblt/auxio/music/extractor/MetadataExtractor.kt index d2047fabe..f9399e409 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/extractor/MetadataExtractor.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/extractor/MetadataExtractor.kt @@ -160,9 +160,9 @@ class Task(context: Context, private val raw: Song.Raw) { val metadata = format.metadata if (metadata != null) { - val tags = Tags(metadata) - populateWithId3v2(tags.id3v2) - populateWithVorbis(tags.vorbis) + val textTags = TextTags(metadata) + populateWithId3v2(textTags.id3v2) + populateWithVorbis(textTags.vorbis) } else { logD("No metadata could be extracted for ${raw.name}") } diff --git a/app/src/main/java/org/oxycblt/auxio/music/extractor/Tags.kt b/app/src/main/java/org/oxycblt/auxio/music/extractor/TextTags.kt similarity index 91% rename from app/src/main/java/org/oxycblt/auxio/music/extractor/Tags.kt rename to app/src/main/java/org/oxycblt/auxio/music/extractor/TextTags.kt index 03179a230..493a3421e 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/extractor/Tags.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/extractor/TextTags.kt @@ -24,11 +24,11 @@ import com.google.android.exoplayer2.metadata.vorbis.VorbisComment import org.oxycblt.auxio.music.parsing.correctWhitespace /** - * Processing wrapper for [Metadata] that allows access to more organized music tags. + * Processing wrapper for [Metadata] that allows organized access to text-based audio tags. * @param metadata The [Metadata] to wrap. * @author Alexander Capehart (OxygenCobalt) */ -class Tags(metadata: Metadata) { +class TextTags(metadata: Metadata) { private val _id3v2 = mutableMapOf>() /** The ID3v2 text identification frames found in the file. Can have more than one value. */ val id3v2: Map> @@ -65,6 +65,10 @@ class Tags(metadata: Metadata) { is VorbisComment -> { // Vorbis comment keys can be in any case, make them uppercase for simplicity. val id = tag.key.sanitize().lowercase() + if (id == "metadata_block_picture") { + // Picture, we don't care about these + continue + } val value = tag.value.sanitize().correctWhitespace() if (value != null) { _vorbis.getOrPut(id) { mutableListOf() }.add(value) diff --git a/app/src/main/java/org/oxycblt/auxio/playback/replaygain/ReplayGainAudioProcessor.kt b/app/src/main/java/org/oxycblt/auxio/playback/replaygain/ReplayGainAudioProcessor.kt index ecd8a1eec..6c29f4e0b 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/replaygain/ReplayGainAudioProcessor.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/replaygain/ReplayGainAudioProcessor.kt @@ -30,7 +30,7 @@ import java.nio.ByteBuffer import kotlin.math.pow import org.oxycblt.auxio.R import org.oxycblt.auxio.music.Album -import org.oxycblt.auxio.music.extractor.Tags +import org.oxycblt.auxio.music.extractor.TextTags import org.oxycblt.auxio.playback.state.PlaybackStateManager import org.oxycblt.auxio.settings.Settings import org.oxycblt.auxio.util.logD @@ -166,23 +166,23 @@ class ReplayGainAudioProcessor(private val context: Context) : * @return A [Adjustment] adjustment, or null if there were no valid adjustments. */ private fun parseReplayGain(format: Format): Adjustment? { - val tags = Tags(format.metadata ?: return null) + val textTags = TextTags(format.metadata ?: return null) var trackGain = 0f var albumGain = 0f // Most ReplayGain tags are formatted as a simple decibel adjustment in a custom // replaygain_*_gain tag. if (format.sampleMimeType != MimeTypes.AUDIO_OPUS) { - tags.id3v2["TXXX:$TAG_RG_TRACK_GAIN"] + textTags.id3v2["TXXX:$TAG_RG_TRACK_GAIN"] ?.run { first().parseReplayGainAdjustment() } ?.let { trackGain = it } - tags.id3v2["TXXX:$TAG_RG_ALBUM_GAIN"] + textTags.id3v2["TXXX:$TAG_RG_ALBUM_GAIN"] ?.run { first().parseReplayGainAdjustment() } ?.let { albumGain = it } - tags.vorbis[TAG_RG_ALBUM_GAIN] + textTags.vorbis[TAG_RG_ALBUM_GAIN] ?.run { first().parseReplayGainAdjustment() } ?.let { trackGain = it } - tags.vorbis[TAG_RG_TRACK_GAIN] + textTags.vorbis[TAG_RG_TRACK_GAIN] ?.run { first().parseReplayGainAdjustment() } ?.let { albumGain = it } } else { @@ -191,10 +191,10 @@ class ReplayGainAudioProcessor(private val context: Context) : // intrinsic to the format to create the normalized adjustment. That base adjustment // is already handled by the media framework, so we just need to apply the more // specific adjustments. - tags.vorbis[TAG_R128_TRACK_GAIN] + textTags.vorbis[TAG_R128_TRACK_GAIN] ?.run { first().parseReplayGainAdjustment() } ?.let { trackGain = it / 256f } - tags.vorbis[TAG_R128_ALBUM_GAIN] + textTags.vorbis[TAG_R128_ALBUM_GAIN] ?.run { first().parseReplayGainAdjustment() } ?.let { albumGain = it / 256f } } diff --git a/app/src/test/java/org/oxycblt/auxio/music/extractor/TextTagsTest.kt b/app/src/test/java/org/oxycblt/auxio/music/extractor/TextTagsTest.kt new file mode 100644 index 000000000..fbc6a1707 --- /dev/null +++ b/app/src/test/java/org/oxycblt/auxio/music/extractor/TextTagsTest.kt @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2023 Auxio Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.oxycblt.auxio.music.extractor + +import com.google.android.exoplayer2.metadata.Metadata +import com.google.android.exoplayer2.metadata.flac.PictureFrame +import com.google.android.exoplayer2.metadata.id3.ApicFrame +import com.google.android.exoplayer2.metadata.id3.InternalFrame +import com.google.android.exoplayer2.metadata.id3.TextInformationFrame +import com.google.android.exoplayer2.metadata.vorbis.VorbisComment +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test + +class TextTagsTest { + @Test + fun textTags_vorbis() { + val textTags = TextTags(VORBIS_METADATA) + assertTrue(textTags.id3v2.isEmpty()) + assertEquals(listOf("Wheel"), textTags.vorbis["title"]) + assertEquals(listOf("Paraglow"), textTags.vorbis["album"]) + assertEquals(listOf("Parannoul", "Asian Glow"), textTags.vorbis["artist"]) + assertEquals(listOf("2022"), textTags.vorbis["date"]) + assertEquals(listOf("ep"), textTags.vorbis["releasetype"]) + assertEquals(listOf("+2 dB"), textTags.vorbis["replaygain_track_gain"]) + } + + @Test + fun textTags_id3v2() { + val textTags = TextTags(ID3V2_METADATA) + assertTrue(textTags.vorbis.isEmpty()) + assertEquals(listOf("Wheel"), textTags.id3v2["TIT2"]) + assertEquals(listOf("Paraglow"), textTags.id3v2["TALB"]) + assertEquals(listOf("Parannoul", "Asian Glow"), textTags.id3v2["TPE1"]) + assertEquals(listOf("2022"), textTags.id3v2["TDRC"]) + assertEquals(listOf("ep"), textTags.id3v2["TXXX:musicbrainz album type"]) + assertEquals(listOf("+2 dB"), textTags.id3v2["TXXX:replaygain_track_gain"]) + } + + @Test + fun textTags_combined() { + val textTags = TextTags(VORBIS_METADATA.copyWithAppendedEntriesFrom(ID3V2_METADATA)) + assertEquals(listOf("Wheel"), textTags.vorbis["title"]) + assertEquals(listOf("Paraglow"), textTags.vorbis["album"]) + assertEquals(listOf("Parannoul", "Asian Glow"), textTags.vorbis["artist"]) + assertEquals(listOf("2022"), textTags.vorbis["date"]) + assertEquals(listOf("ep"), textTags.vorbis["releasetype"]) + assertEquals(listOf("+2 dB"), textTags.vorbis["replaygain_track_gain"]) + assertEquals(listOf("Wheel"), textTags.id3v2["TIT2"]) + assertEquals(listOf("Paraglow"), textTags.id3v2["TALB"]) + assertEquals(listOf("Parannoul", "Asian Glow"), textTags.id3v2["TPE1"]) + assertEquals(listOf("2022"), textTags.id3v2["TDRC"]) + assertEquals(listOf("ep"), textTags.id3v2["TXXX:musicbrainz album type"]) + assertEquals(listOf("+2 dB"), textTags.id3v2["TXXX:replaygain_track_gain"]) + } + + companion object { + private val VORBIS_METADATA = + Metadata( + VorbisComment("TITLE", "Wheel"), + VorbisComment("ALBUM", "Paraglow"), + VorbisComment("ARTIST", "Parannoul"), + VorbisComment("ARTIST", "Asian Glow"), + VorbisComment("DATE", "2022"), + VorbisComment("RELEASETYPE", "ep"), + VorbisComment("METADATA_BLOCK_PICTURE", ""), + VorbisComment("REPLAYGAIN_TRACK_GAIN", "+2 dB"), + PictureFrame(0, "", "", 0, 0, 0, 0, byteArrayOf())) + + private val ID3V2_METADATA = + Metadata( + TextInformationFrame("TIT2", null, listOf("Wheel")), + TextInformationFrame("TALB", null, listOf("Paraglow")), + TextInformationFrame("TPE1", null, listOf("Parannoul", "Asian Glow")), + TextInformationFrame("TDRC", null, listOf("2022")), + TextInformationFrame("TXXX", "MusicBrainz Album Type", listOf("ep")), + InternalFrame("com.apple.iTunes", "replaygain_track_gain", "+2 dB"), + ApicFrame("", "", 0, byteArrayOf())) + } +}