Fix thumbnail quality in notification and use proper metadata

This commit is contained in:
Bnyro 2023-05-18 16:37:00 +02:00
parent 03d712d834
commit 024d55dd16
4 changed files with 42 additions and 56 deletions

View File

@ -0,0 +1,31 @@
package com.github.libretube.extensions
import android.content.res.Resources
import android.graphics.BitmapFactory
import android.support.v4.media.MediaMetadataCompat
import androidx.core.net.toUri
import androidx.core.os.bundleOf
import androidx.media3.common.MediaItem
import androidx.media3.common.MediaMetadata
import com.github.libretube.R
import com.github.libretube.api.obj.Streams
fun MediaItem.Builder.setMetadata(streams: Streams) = apply {
val appIcon = BitmapFactory.decodeResource(
Resources.getSystem(),
R.drawable.ic_launcher_monochrome,
)
val extras = bundleOf(
MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON to appIcon,
MediaMetadataCompat.METADATA_KEY_TITLE to streams.title,
MediaMetadataCompat.METADATA_KEY_ARTIST to streams.uploader,
)
setMediaMetadata(
MediaMetadata.Builder()
.setTitle(streams.title)
.setArtist(streams.uploader)
.setArtworkUri(streams.thumbnailUrl.toUri())
.setExtras(extras)
.build()
)
}

View File

@ -27,6 +27,7 @@ import com.github.libretube.constants.PLAYER_NOTIFICATION_ID
import com.github.libretube.db.DatabaseHolder.Database import com.github.libretube.db.DatabaseHolder.Database
import com.github.libretube.db.obj.WatchPosition import com.github.libretube.db.obj.WatchPosition
import com.github.libretube.extensions.TAG import com.github.libretube.extensions.TAG
import com.github.libretube.extensions.setMetadata
import com.github.libretube.extensions.toID import com.github.libretube.extensions.toID
import com.github.libretube.helpers.PlayerHelper import com.github.libretube.helpers.PlayerHelper
import com.github.libretube.helpers.PlayerHelper.checkForSegments import com.github.libretube.helpers.PlayerHelper.checkForSegments
@ -294,8 +295,7 @@ class OnlinePlayerService : LifecycleService() {
* Sets the [MediaItem] with the [streams] into the [player] * Sets the [MediaItem] with the [streams] into the [player]
*/ */
private fun setMediaItem() { private fun setMediaItem() {
val streams = streams val streams = streams ?: return
streams ?: return
val uri = if (streams.audioStreams.isNotEmpty()) { val uri = if (streams.audioStreams.isNotEmpty()) {
PlayerHelper.getAudioSource(this, streams.audioStreams) PlayerHelper.getAudioSource(this, streams.audioStreams)
@ -305,6 +305,7 @@ class OnlinePlayerService : LifecycleService() {
val mediaItem = MediaItem.Builder() val mediaItem = MediaItem.Builder()
.setUri(ProxyHelper.rewriteUrl(uri)) .setUri(ProxyHelper.rewriteUrl(uri))
.setMetadata(streams)
.build() .build()
player?.setMediaItem(mediaItem) player?.setMediaItem(mediaItem)
} }

View File

@ -121,6 +121,7 @@ import retrofit2.HttpException
import java.io.IOException import java.io.IOException
import java.util.* import java.util.*
import java.util.concurrent.Executors import java.util.concurrent.Executors
import com.github.libretube.extensions.setMetadata
import kotlin.math.abs import kotlin.math.abs
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) @androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
@ -1246,10 +1247,11 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
} }
private fun setMediaSource(uri: Uri, mimeType: String) { private fun setMediaSource(uri: Uri, mimeType: String) {
val mediaItem: MediaItem = MediaItem.Builder() val mediaItem = MediaItem.Builder()
.setUri(uri) .setUri(uri)
.setMimeType(mimeType) .setMimeType(mimeType)
.setSubtitleConfigurations(subtitles) .setSubtitleConfigurations(subtitles)
.setMetadata(streams)
.build() .build()
exoPlayer.setMediaItem(mediaItem) exoPlayer.setMediaItem(mediaItem)
} }

View File

@ -6,13 +6,9 @@ import android.app.PendingIntent.FLAG_UPDATE_CURRENT
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.support.v4.media.MediaDescriptionCompat
import android.support.v4.media.MediaMetadataCompat
import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.MediaSessionCompat
import android.util.Log
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.PendingIntentCompat import androidx.core.app.PendingIntentCompat
@ -22,7 +18,6 @@ import androidx.core.os.bundleOf
import androidx.media3.common.Player import androidx.media3.common.Player
import androidx.media3.exoplayer.ExoPlayer import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.session.CommandButton import androidx.media3.session.CommandButton
import androidx.media3.session.DefaultMediaNotificationProvider
import androidx.media3.session.MediaSession import androidx.media3.session.MediaSession
import androidx.media3.session.SessionCommand import androidx.media3.session.SessionCommand
import androidx.media3.session.SessionResult import androidx.media3.session.SessionResult
@ -36,7 +31,6 @@ import com.github.libretube.helpers.ImageHelper
import com.github.libretube.helpers.PlayerHelper import com.github.libretube.helpers.PlayerHelper
import com.github.libretube.obj.PlayerNotificationData import com.github.libretube.obj.PlayerNotificationData
import com.github.libretube.ui.activities.MainActivity import com.github.libretube.ui.activities.MainActivity
import com.google.common.collect.ImmutableList
import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.ListenableFuture
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) @androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
@ -102,10 +96,10 @@ class NowPlayingNotification(
player: Player, player: Player,
callback: PlayerNotificationManager.BitmapCallback, callback: PlayerNotificationManager.BitmapCallback,
): Bitmap? { ): Bitmap? {
if (DataSaverMode.isEnabled(context)) return null // On Android 13 and up, the metadata is responsible for the thumbnail
if (DataSaverMode.isEnabled(context) ||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) return null
if (bitmap == null) enqueueThumbnailRequest(callback) if (bitmap == null) enqueueThumbnailRequest(callback)
return bitmap return bitmap
} }
@ -119,7 +113,7 @@ class NowPlayingNotification(
// online image // online image
notificationData?.thumbnailPath?.let { path -> notificationData?.thumbnailPath?.let { path ->
ImageHelper.getDownloadedImage(context, path)?.let { ImageHelper.getDownloadedImage(context, path)?.let {
bitmap = processThumbnailBitmap(it) bitmap = ImageHelper.getSquareBitmap(it)
callback.onBitmap(bitmap!!) callback.onBitmap(bitmap!!)
} }
return return
@ -128,7 +122,7 @@ class NowPlayingNotification(
val request = ImageRequest.Builder(context) val request = ImageRequest.Builder(context)
.data(notificationData?.thumbnailUrl) .data(notificationData?.thumbnailUrl)
.target { .target {
bitmap = processThumbnailBitmap(it.toBitmap()) bitmap = ImageHelper.getSquareBitmap(it.toBitmap())
callback.onBitmap(bitmap!!) callback.onBitmap(bitmap!!)
} }
.build() .build()
@ -159,17 +153,6 @@ class NowPlayingNotification(
} }
} }
/**
* Returns the bitmap on Android 13+, for everything below scaled down to a square
*/
private fun processThumbnailBitmap(bitmap: Bitmap): Bitmap {
return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
ImageHelper.getSquareBitmap(bitmap)
} else {
bitmap
}
}
private fun createNotificationAction( private fun createNotificationAction(
drawableRes: Int, drawableRes: Int,
actionName: String, actionName: String,
@ -260,24 +243,6 @@ class NowPlayingNotification(
createMediaSessionAction(R.drawable.ic_forward_md, FORWARD), createMediaSessionAction(R.drawable.ic_forward_md, FORWARD),
) )
private fun getMediaDescription(): MediaDescriptionCompat {
val appIcon = BitmapFactory.decodeResource(
context.resources,
R.drawable.ic_launcher_monochrome,
)
val extras = bundleOf(
MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON to appIcon,
MediaMetadataCompat.METADATA_KEY_TITLE to notificationData?.title,
MediaMetadataCompat.METADATA_KEY_ARTIST to notificationData?.uploaderName,
)
return MediaDescriptionCompat.Builder()
.setTitle(notificationData?.title)
.setSubtitle(notificationData?.uploaderName)
.setIconBitmap(appIcon)
.setExtras(extras)
.build()
}
private fun handlePlayerAction(action: String) { private fun handlePlayerAction(action: String) {
when (action) { when (action) {
NEXT -> { NEXT -> {
@ -324,19 +289,6 @@ class NowPlayingNotification(
} }
} }
class NotificationProvider(val context: Context) : DefaultMediaNotificationProvider(context) {
override fun getMediaButtons(
session: MediaSession,
playerCommands: Player.Commands,
customLayout: ImmutableList<CommandButton>,
showPauseButton: Boolean,
): ImmutableList<CommandButton> {
val buttons = super.getMediaButtons(session, playerCommands, customLayout, showPauseButton)
buttons.removeFirst()
return buttons
}
}
/** /**
* Initializes the [playerNotification] attached to the [player] and shows it. * Initializes the [playerNotification] attached to the [player] and shows it.
*/ */