diff --git a/app/src/main/java/org/oxycblt/auxio/image/coil/CoilModule.kt b/app/src/main/java/org/oxycblt/auxio/image/coil/CoilModule.kt index 3766ce5fb..cd5bc8e07 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/coil/CoilModule.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/coil/CoilModule.kt @@ -37,13 +37,13 @@ class CoilModule { fun imageLoader( @ApplicationContext context: Context, keyer: CoverKeyer, - factory: CoverFetcher.Factory + // factory: CoverFetcher.Factory ) = ImageLoader.Builder(context) .components { // Add fetchers for Music components to make them usable with ImageRequest add(keyer) - add(factory) + // add(factory) } // Use our own crossfade with error drawable support .transitionFactory(ErrorCrossfadeTransitionFactory()) diff --git a/app/src/main/java/org/oxycblt/auxio/image/coil/Components.kt b/app/src/main/java/org/oxycblt/auxio/image/coil/Components.kt index fc5ebffaa..5f713b22d 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/coil/Components.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/coil/Components.kt @@ -23,14 +23,11 @@ import android.graphics.Bitmap import android.graphics.BitmapFactory import android.graphics.Canvas import androidx.core.graphics.drawable.toDrawable -import coil3.ImageLoader import coil3.asImage import coil3.decode.DataSource -import coil3.decode.ImageSource import coil3.fetch.FetchResult import coil3.fetch.Fetcher import coil3.fetch.ImageFetchResult -import coil3.fetch.SourceFetchResult import coil3.key.Keyer import coil3.request.Options import coil3.size.Dimension @@ -38,12 +35,6 @@ import coil3.size.Size import coil3.size.pxOrElse import java.io.InputStream import javax.inject.Inject -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import okio.FileSystem -import okio.buffer -import okio.source -import org.oxycblt.auxio.image.stack.CoverRetriever import org.oxycblt.musikr.cover.Cover class CoverKeyer @Inject constructor() : Keyer { @@ -55,46 +46,61 @@ private constructor( private val context: Context, private val cover: Cover, private val size: Size, - private val coverRetriever: CoverRetriever, ) : Fetcher { override suspend fun fetch(): FetchResult? { - val streams = - when (val cover = cover) { - is Cover.Single -> listOfNotNull(coverRetriever.retrieve(cover)) - is Cover.Multi -> - buildList { - for (single in cover.all) { - coverRetriever.retrieve(single)?.let { add(it) } - if (size == 4) { - break - } - } - } - } + return null + // val streams = + // when (val cover = cover) { + // is Cover.Single -> listOfNotNull(coverRetriever.retrieve(cover)) + // is Cover.Multi -> + // buildList { + // for (single in cover.all) { + // coverRetriever.retrieve(single)?.let { add(it) } + // if (size == 4) { + // break + // } + // } + // } + // } // We don't immediately check for mosaic feasibility from album count alone, as that // does not factor in InputStreams failing to load. Instead, only check once we // definitely have image data to use. - if (streams.size == 4) { - // Make sure we free the InputStreams once we've transformed them into a mosaic. - return createMosaic(streams, size).also { - withContext(Dispatchers.IO) { streams.forEach(InputStream::close) } - } - } + // if (streams.size == 4) { + // // Make sure we free the InputStreams once we've transformed them into a + // mosaic. + // return createMosaic(streams, size).also { + // withContext(Dispatchers.IO) { streams.forEach(InputStream::close) } + // } // Not enough covers for a mosaic, take the first one (if that even + // exists) + // val first = streams.firstOrNull() ?: return null + // + // // All but the first stream will be unused, free their resources + // withContext(Dispatchers.IO) { + // for (i in 1 until streams.size) { + // streams[i].close() + // } + // } + // + // return SourceFetchResult( + // source = ImageSource(first.source().buffer(), FileSystem.SYSTEM, null), + // mimeType = null, + // dataSource = DataSource.DISK) + // } - // Not enough covers for a mosaic, take the first one (if that even exists) - val first = streams.firstOrNull() ?: return null - - // All but the first stream will be unused, free their resources - withContext(Dispatchers.IO) { - for (i in 1 until streams.size) { - streams[i].close() - } - } - - return SourceFetchResult( - source = ImageSource(first.source().buffer(), FileSystem.SYSTEM, null), - mimeType = null, - dataSource = DataSource.DISK) + // // Not enough covers for a mosaic, take the first one (if that even exists) + // val first = streams.firstOrNull() ?: return null + // + // // All but the first stream will be unused, free their resources + // withContext(Dispatchers.IO) { + // for (i in 1 until streams.size) { + // streams[i].close() + // } + // } + // + // return SourceFetchResult( + // source = ImageSource(first.source().buffer(), FileSystem.SYSTEM, null), + // mimeType = null, + // dataSource = DataSource.DISK) } /** Derived from phonograph: https://github.com/kabouzeid/Phonograph */ @@ -148,9 +154,9 @@ private constructor( return if (size.mod(2) > 0) size + 1 else size } - class Factory @Inject constructor(private val coverRetriever: CoverRetriever) : - Fetcher.Factory { - override fun create(data: Cover, options: Options, imageLoader: ImageLoader) = - CoverFetcher(options.context, data, options.size, coverRetriever) - } + // class Factory @Inject constructor(private val coverRetriever: CoverRetriever) : + // Fetcher.Factory { + // override fun create(data: Cover, options: Options, imageLoader: ImageLoader) = + // CoverFetcher(options.context, data, options.size, coverRetriever) + // } } diff --git a/app/src/main/java/org/oxycblt/auxio/image/stack/CoverRetriever.kt b/app/src/main/java/org/oxycblt/auxio/image/stack/CoverRetriever.kt deleted file mode 100644 index 4bd761b74..000000000 --- a/app/src/main/java/org/oxycblt/auxio/image/stack/CoverRetriever.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2024 Auxio Project - * CoverRetriever.kt is part of Auxio. - * - * 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.image.stack - -import java.io.InputStream -import javax.inject.Inject -import org.oxycblt.auxio.image.stack.extractor.CoverExtractor -import org.oxycblt.musikr.cover.Cover -import org.oxycblt.musikr.cover.CoverCache -import timber.log.Timber - -interface CoverRetriever { - suspend fun retrieve(cover: Cover.Single): InputStream? -} - -class CoverRetrieverImpl -@Inject -constructor(private val coverCache: CoverCache, private val coverExtractor: CoverExtractor) : - CoverRetriever { - override suspend fun retrieve(cover: Cover.Single) = - try { - coverCache.read(cover) - ?: coverExtractor.extract(cover)?.let { coverCache.write(cover, it) } - } catch (e: Exception) { - Timber.e("Image extraction failed!") - Timber.e(e.stackTraceToString()) - throw e - } -} diff --git a/app/src/main/java/org/oxycblt/auxio/image/stack/StackModule.kt b/app/src/main/java/org/oxycblt/auxio/image/stack/StackModule.kt deleted file mode 100644 index 4fc3c5eb8..000000000 --- a/app/src/main/java/org/oxycblt/auxio/image/stack/StackModule.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2024 Auxio Project - * StackModule.kt is part of Auxio. - * - * 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.image.stack - -import dagger.Binds -import dagger.Module -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent - -@Module -@InstallIn(SingletonComponent::class) -interface StackModule { - @Binds fun coverRetriever(impl: CoverRetrieverImpl): CoverRetriever -} diff --git a/app/src/main/java/org/oxycblt/auxio/image/stack/extractor/AOSPCoverSource.kt b/app/src/main/java/org/oxycblt/auxio/image/stack/extractor/AOSPCoverSource.kt deleted file mode 100644 index c2920008d..000000000 --- a/app/src/main/java/org/oxycblt/auxio/image/stack/extractor/AOSPCoverSource.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2024 Auxio Project - * AOSPCoverSource.kt is part of Auxio. - * - * 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.image.stack.extractor - -import android.content.Context -import android.media.MediaMetadataRetriever -import android.net.Uri -import dagger.hilt.android.qualifiers.ApplicationContext -import javax.inject.Inject -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext - -class AOSPCoverSource @Inject constructor(@ApplicationContext private val context: Context) : - CoverSource { - override suspend fun extract(fileUri: Uri): ByteArray? { - val mediaMetadataRetriever = MediaMetadataRetriever() - return withContext(Dispatchers.IO) { - mediaMetadataRetriever.setDataSource(context, fileUri) - mediaMetadataRetriever.embeddedPicture - } - } -} diff --git a/app/src/main/java/org/oxycblt/auxio/image/stack/extractor/CoverExtractor.kt b/app/src/main/java/org/oxycblt/auxio/image/stack/extractor/CoverExtractor.kt deleted file mode 100644 index 02ee0abf1..000000000 --- a/app/src/main/java/org/oxycblt/auxio/image/stack/extractor/CoverExtractor.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2024 Auxio Project - * CoverExtractor.kt is part of Auxio. - * - * 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.image.stack.extractor - -import android.net.Uri -import javax.inject.Inject -import org.oxycblt.musikr.cover.Cover - -interface CoverExtractor { - suspend fun extract(cover: Cover.Single): ByteArray? -} - -data class CoverSources(val sources: List) - -interface CoverSource { - suspend fun extract(fileUri: Uri): ByteArray? -} - -class CoverExtractorImpl @Inject constructor(private val coverSources: CoverSources) : - CoverExtractor { - override suspend fun extract(cover: Cover.Single): ByteArray? { - return null - for (coverSource in coverSources.sources) { - val stream = coverSource.extract(cover.uri) - if (stream != null) { - return stream - } - } - return null - } -} diff --git a/app/src/main/java/org/oxycblt/auxio/image/stack/extractor/ExoPlayerCoverSource.kt b/app/src/main/java/org/oxycblt/auxio/image/stack/extractor/ExoPlayerCoverSource.kt deleted file mode 100644 index 79875f836..000000000 --- a/app/src/main/java/org/oxycblt/auxio/image/stack/extractor/ExoPlayerCoverSource.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2024 Auxio Project - * ExoPlayerCoverSource.kt is part of Auxio. - * - * 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.image.stack.extractor - -import android.net.Uri -import androidx.media3.common.MediaItem -import androidx.media3.common.MediaMetadata -import androidx.media3.common.Metadata -import androidx.media3.exoplayer.MetadataRetriever -import androidx.media3.exoplayer.source.MediaSource -import androidx.media3.extractor.metadata.flac.PictureFrame -import androidx.media3.extractor.metadata.id3.ApicFrame -import javax.inject.Inject -import kotlinx.coroutines.guava.asDeferred - -class ExoPlayerCoverSource -@Inject -constructor(private val mediaSourceFactory: MediaSource.Factory) : CoverSource { - override suspend fun extract(fileUri: Uri): ByteArray? { - val tracks = - MetadataRetriever.retrieveMetadata(mediaSourceFactory, MediaItem.fromUri(fileUri)) - .asDeferred() - .await() - - // The metadata extraction process of ExoPlayer results in a dump of all metadata - // it found, which must be iterated through. - val metadata = tracks[0].getFormat(0).metadata - - if (metadata == null || metadata.length() == 0) { - // No (parsable) metadata. This is also expected. - return null - } - - return findCoverDataInMetadata(metadata) - } - - private fun findCoverDataInMetadata(metadata: Metadata): ByteArray? { - var fallbackPic: ByteArray? = null - - for (i in 0 until metadata.length()) { - // We can only extract pictures from two tags with this method, ID3v2's APIC or - // Vorbis picture comments. - val pic: ByteArray? - val type: Int - - when (val entry = metadata.get(i)) { - is ApicFrame -> { - pic = entry.pictureData - type = entry.pictureType - } - is PictureFrame -> { - pic = entry.pictureData - type = entry.pictureType - } - else -> continue - } - - if (type == MediaMetadata.PICTURE_TYPE_FRONT_COVER) { - return pic - } else if (fallbackPic == null) { - fallbackPic = pic - } - } - - return fallbackPic - } -} diff --git a/app/src/main/java/org/oxycblt/auxio/image/stack/extractor/ExtractorModule.kt b/app/src/main/java/org/oxycblt/auxio/image/stack/extractor/ExtractorModule.kt deleted file mode 100644 index 326c5df79..000000000 --- a/app/src/main/java/org/oxycblt/auxio/image/stack/extractor/ExtractorModule.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2024 Auxio Project - * ExtractorModule.kt is part of Auxio. - * - * 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.image.stack.extractor - -import dagger.Binds -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent - -@Module -@InstallIn(SingletonComponent::class) -interface ExtractorModule { - @Binds fun coverExtractor(impl: CoverExtractorImpl): CoverExtractor -} - -@Module -@InstallIn(SingletonComponent::class) -class CoverSourcesModule { - @Provides - fun coverSources(exoPlayerCoverSource: ExoPlayerCoverSource, aospCoverSource: AOSPCoverSource) = - CoverSources(listOf(aospCoverSource, exoPlayerCoverSource)) -} diff --git a/app/src/main/java/org/oxycblt/musikr/model/SongImpl.kt b/app/src/main/java/org/oxycblt/musikr/model/SongImpl.kt index f0bde5620..55b2e0773 100644 --- a/app/src/main/java/org/oxycblt/musikr/model/SongImpl.kt +++ b/app/src/main/java/org/oxycblt/musikr/model/SongImpl.kt @@ -56,7 +56,7 @@ class SongImpl(private val handle: SongCore) : Song { override val replayGainAdjustment = preSong.replayGainAdjustment override val lastModified = preSong.lastModified override val dateAdded = preSong.dateAdded - override val cover = Cover.single(this) + override val cover = Cover.single("") override val album: Album get() = handle.resolveAlbum()