Musicoo/app/src/main/java/relax/offline/music/util/Utils.kt
2024-05-27 17:32:26 +08:00

117 lines
3.9 KiB
Kotlin

package relax.offline.music.util
import android.net.Uri
import android.os.Build
import android.text.format.DateUtils
import androidx.annotation.OptIn
import androidx.core.net.toUri
import androidx.core.os.bundleOf
import androidx.media3.common.MediaItem
import androidx.media3.common.MediaMetadata
import androidx.media3.common.util.UnstableApi
import relax.offline.music.bean.FavoriteBean
import relax.offline.music.bean.OfflineBean
import relax.offline.music.innertube.Innertube
import relax.offline.music.innertube.models.bodies.ContinuationBody
import relax.offline.music.innertube.requests.playlistPage
import relax.offline.music.innertube.utils.plus
val OfflineBean.asMediaItem: MediaItem
@OptIn(UnstableApi::class)
get() = MediaItem.Builder()
.setMediaId(videoId)
.setUri(videoId)
.setCustomCacheKey(videoId)
.setMediaMetadata(
MediaMetadata.Builder()
.setTitle(title)
.setArtist(name)
.setArtworkUri(thumbnail?.toUri())
.build()
)
.build()
val FavoriteBean.asMediaItem: MediaItem
@OptIn(UnstableApi::class)
get() = MediaItem.Builder()
.setMediaId(videoId)
.setUri(videoId)
.setCustomCacheKey(videoId)
.setMediaMetadata(
MediaMetadata.Builder()
.setTitle(title)
.setArtist(name)
.setArtworkUri(thumbnail?.toUri())
.build()
)
.build()
val Innertube.SongItem.asMediaItem: MediaItem
@OptIn(UnstableApi::class)
get() = MediaItem.Builder()
.setMediaId(key)
.setUri(key)
.setCustomCacheKey(key)
.setMediaMetadata(
MediaMetadata.Builder()
.setTitle(info?.name)
.setArtist(authors?.joinToString("") { it.name ?: "" })
.setAlbumTitle(album?.name)
.setArtworkUri(bigThumbnail?.url?.toUri())
.setExtras(
bundleOf(
"albumId" to album?.endpoint?.browseId,
"durationText" to durationText,
"artistNames" to authors?.filter { it.endpoint != null }
?.mapNotNull { it.name },
"artistIds" to authors?.mapNotNull { it.endpoint?.browseId },
)
)
.build()
)
.build()
fun String?.thumbnail(size: Int): String? {
return when {
this?.startsWith("https://lh3.googleusercontent.com") == true -> "$this-w$size-h$size"
this?.startsWith("https://yt3.ggpht.com") == true -> "$this-w$size-h$size-s$size"
else -> this
}
}
fun Uri?.thumbnail(size: Int): Uri? {
return toString().thumbnail(size)?.toUri()
}
fun formatAsDuration(millis: Long) = DateUtils.formatElapsedTime(millis / 1000).removePrefix("0")
suspend fun Result<Innertube.PlaylistOrAlbumPage>.completed(): Result<Innertube.PlaylistOrAlbumPage>? {
var playlistPage = getOrNull() ?: return null
while (playlistPage.songsPage?.continuation != null) {
val continuation = playlistPage.songsPage?.continuation!!
val otherPlaylistPageResult =
Innertube.playlistPage(ContinuationBody(continuation = continuation)) ?: break
if (otherPlaylistPageResult.isFailure) break
otherPlaylistPageResult.getOrNull()?.let { otherSongsPage ->
playlistPage = playlistPage.copy(songsPage = playlistPage.songsPage + otherSongsPage)
}
}
return Result.success(playlistPage)
}
inline val isAtLeastAndroid6
get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
inline val isAtLeastAndroid8
get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
inline val isAtLeastAndroid12
get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
inline val isAtLeastAndroid13
get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU