all: temp fix build issues

This commit is contained in:
Alexander Capehart 2024-12-11 13:18:22 -07:00
parent 530d8cc2b5
commit b53b7a0c6a
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
9 changed files with 57 additions and 333 deletions

View file

@ -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())

View file

@ -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<Cover> {
@ -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<Cover> {
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<Cover> {
// override fun create(data: Cover, options: Options, imageLoader: ImageLoader) =
// CoverFetcher(options.context, data, options.size, coverRetriever)
// }
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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
}
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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
}
}
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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<CoverSource>)
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
}
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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
}
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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))
}

View file

@ -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()