mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-29 08:20:32 +05:30
Fix thumbnail quality in notification and use proper metadata
This commit is contained in:
parent
03d712d834
commit
024d55dd16
@ -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()
|
||||||
|
)
|
||||||
|
}
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user