From b69d9ed69fef01a4d8294c8878a715429bd886e6 Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Thu, 9 Oct 2025 23:53:07 +0800 Subject: [PATCH] tts: improve media session control compatibility across more Android systems (#2185) --- .../android/app/src/main/AndroidManifest.xml | 19 +- .../android/build.gradle.kts | 5 +- .../android/src/main/assets/silence.mp3 | Bin 0 -> 40162 bytes .../src/main/java/MediaPlaybackService.kt | 232 ++++++++++++++ .../android/src/main/java/NativeTTSPlugin.kt | 283 ++---------------- .../main/res/drawable/notification_icon.png | Bin 0 -> 42487 bytes .../app/reader/components/tts/TTSControl.tsx | 9 + apps/readest-app/src/libs/mediaSession.ts | 4 +- apps/readest-app/src/styles/themes.ts | 1 - 9 files changed, 293 insertions(+), 260 deletions(-) create mode 100644 apps/readest-app/src-tauri/plugins/tauri-plugin-native-tts/android/src/main/assets/silence.mp3 create mode 100644 apps/readest-app/src-tauri/plugins/tauri-plugin-native-tts/android/src/main/java/MediaPlaybackService.kt create mode 100644 apps/readest-app/src-tauri/plugins/tauri-plugin-native-tts/android/src/main/res/drawable/notification_icon.png diff --git a/apps/readest-app/src-tauri/gen/android/app/src/main/AndroidManifest.xml b/apps/readest-app/src-tauri/gen/android/app/src/main/AndroidManifest.xml index a8423bc9..3b96dd68 100644 --- a/apps/readest-app/src-tauri/gen/android/app/src/main/AndroidManifest.xml +++ b/apps/readest-app/src-tauri/gen/android/app/src/main/AndroidManifest.xml @@ -115,11 +115,22 @@ + + + + + + + android:name="com.readest.native_tts.MediaPlaybackService" + android:foregroundServiceType="mediaPlayback" + android:exported="true"> + + + + o;!p+`4_I_wM}%4<9{w`s~HaSFhi^efR#u$4{TXeC_*IJGuH9w^l!6 zOIs~|z9v`34_tQjTxS~eyVTB^ zdi0NThVt&e{&&zh9e>`>ukBE-2Ay-LPWN-EPWSV;PWSV?PWR(E(c?boxzqZIO5PProvD+aKxcoOogFt;D|%F zmWZw4IFXk7E@uU8#v<7EvCXy zH*mzETTF$aZs3SRx0nh;-M|rtZZQ>xx`87O-C`;XbpuBny2Vr&>IRNDbc?Al)D0YQ z=oV99s2e!q&@HCIP&aVIp<7Iap>E)aL${a;L*2j;hi)+yhPr_x4&7oZ40QuX9J<9+ z80rR&ICP7tFw_kkap)FPVW=B8;?OOo!caGG#GzYEg`sZXh(ouS3Pat%5r=Lu6^6Qj zBM#kSDhzc4M;yAvR2b?8jyQCSsW8+H9C7FtQ(>qZIO5PProvD+aKxcoOogFt;D|%F zmWZw4IFXk7E@uU8#v<7EvCXy zH*mzETTF$aZs3SRx0nh;-M|rtZZQ>xx`87O-C`;XbpuBny2Vr&>IRNDbc?Al)D0YQ z=oV99s2e!q&@HCIP&aVIp<7Iap>E)aL${a;L*2j;hi)+yhPr_x4&7oZ40QuX9J<9+ z80rR&ICP7tFw_kkap)FPVW=B8;`ra(aO3@bqwhVh^p=M1Qc6=Pt(~PbV)1XnbN + Log.i("MediaPlaybackService", "Audio focus changed: $focusChange, $player.isPlaying") + when (focusChange) { + AudioManager.AUDIOFOCUS_GAIN -> { + player.volume = 1.0f + if (!player.isPlaying) player.play() + } + AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { + player.volume = 0.3f + } + AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { + if (player.isPlaying) player.pause() + } + } + } + + companion object { + private const val CHANNEL_ID = "media2_playback_channel" + private const val NOTIFICATION_ID = 1002 + private const val MEDIA_ROOT_ID = "media_root_id" + + var pluginEventTrigger: ((String, JSObject) -> Unit)? = null + + var currentTitle: String = "Read Aloud" + var currentArtist: String = "Reading your content" + var currentArtwork: Bitmap? = null + } + + override fun onCreate() { + super.onCreate() + + audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager + val result = audioManager.requestAudioFocus( + afChangeListener, + AudioManager.STREAM_MUSIC, + AudioManager.AUDIOFOCUS_GAIN + ) + if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { + Log.d("MediaPlaybackService", "Audio focus granted") + } else { + Log.w("MediaPlaybackService", "Failed to gain audio focus") + } + + player = ExoPlayer.Builder(this).build() + + mediaSession = MediaSessionCompat(baseContext, "ReadestMediaSession").apply { + stateBuilder = PlaybackStateCompat.Builder().setActions( + PlaybackStateCompat.ACTION_PLAY or + PlaybackStateCompat.ACTION_PLAY_PAUSE or + PlaybackStateCompat.ACTION_PAUSE or + PlaybackStateCompat.ACTION_STOP or + PlaybackStateCompat.ACTION_SKIP_TO_NEXT or + PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS + ) + setPlaybackState(stateBuilder.build()) + setCallback(SessionCallback()) + setSessionToken(sessionToken) + isActive = true + } + + player.addListener(object : Player.Listener { + override fun onIsPlayingChanged(isPlaying: Boolean) { + updatePlaybackState() + } + override fun onPlaybackStateChanged(playbackState: Int) { + updatePlaybackState() + } + }) + + val mediaItem = MediaItem.fromUri("asset:///silence.mp3") + player.setMediaItem(mediaItem) + player.repeatMode = Player.REPEAT_MODE_ONE + player.prepare() + player.playWhenReady = true + + showNotification(PlaybackStateCompat.STATE_PLAYING) + } + + private inner class SessionCallback : MediaSessionCompat.Callback() { + override fun onPlay() { + player.play() + pluginEventTrigger?.invoke("media-session-play", JSObject()) + updatePlaybackState() + } + + override fun onPause() { + player.pause() + pluginEventTrigger?.invoke("media-session-pause", JSObject()) + updatePlaybackState() + } + + override fun onSkipToNext() { + player.seekTo(0) + pluginEventTrigger?.invoke("media-session-next", JSObject()) + } + + override fun onSkipToPrevious() { + player.seekTo(0) + pluginEventTrigger?.invoke("media-session-previous", JSObject()) + } + } + + private fun updatePlaybackState() { + val state = if (player.isPlaying) PlaybackStateCompat.STATE_PLAYING else PlaybackStateCompat.STATE_PAUSED + mediaSession?.setPlaybackState( + stateBuilder.setState(state, player.currentPosition, 1f).build() + ) + showNotification(state) + } + + private fun showNotification(playbackState: Int) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val channel = NotificationChannel(CHANNEL_ID, "Media Controls", NotificationManager.IMPORTANCE_LOW) + getSystemService(NotificationManager::class.java).createNotificationChannel(channel) + } + startForeground(NOTIFICATION_ID, buildNotification(playbackState)) + } + + private fun buildNotification(playbackState: Int): Notification { + val builder = NotificationCompat.Builder(this, CHANNEL_ID).apply { + setContentTitle(currentTitle) + setContentText(currentArtist) + setLargeIcon(currentArtwork) + setContentIntent(mediaSession!!.controller.sessionActivity) + setDeleteIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(this@MediaPlaybackService, PlaybackStateCompat.ACTION_STOP)) + setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + setSmallIcon(R.drawable.notification_icon) + + setStyle( + androidx.media.app.NotificationCompat.MediaStyle() + .setMediaSession(mediaSession?.sessionToken) + .setShowActionsInCompactView(0) + ) + } + return builder.build() + } + + override fun onGetRoot(clientPackageName: String, clientUid: Int, rootHints: Bundle?): BrowserRoot? { + return BrowserRoot(MEDIA_ROOT_ID, null) + } + + override fun onLoadChildren(parentId: String, result: Result>) { + result.sendResult(null) + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + MediaButtonReceiver.handleIntent(mediaSession, intent) + + if (intent?.action == "UPDATE_METADATA") { + currentTitle = intent.getStringExtra("title") ?: currentTitle + currentArtist = intent.getStringExtra("artist") ?: currentArtist + val newArtwork = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + intent.getParcelableExtra("artwork", Bitmap::class.java) + } else { + @Suppress("DEPRECATION") + intent.getParcelableExtra("artwork") + } + if (newArtwork != null) { + currentArtwork = newArtwork + } + + val metadataBuilder = MediaMetadataCompat.Builder() + .putString(MediaMetadataCompat.METADATA_KEY_TITLE, currentTitle) + .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, currentArtist) + .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, currentArtwork) + + mediaSession?.setMetadata(metadataBuilder.build()) + + showNotification(if (player.isPlaying) PlaybackStateCompat.STATE_PLAYING else PlaybackStateCompat.STATE_PAUSED) + } else if (intent?.action == "UPDATE_PLAYBACK_STATE") { + val isPlaying = intent.getBooleanExtra("playing", false) + val position = intent.getLongExtra("position", 0L) // in milliseconds + val duration = intent.getLongExtra("duration", 0L) // in milliseconds + + if (isPlaying && !player.isPlaying) { + player.play() + } else if (!isPlaying && player.isPlaying) { + player.pause() + } + player.seekTo(position) + + val state = if (isPlaying) PlaybackStateCompat.STATE_PLAYING else PlaybackStateCompat.STATE_PAUSED + mediaSession?.setPlaybackState( + stateBuilder.setState(state, position, 1f).build() + ) + showNotification(state) + } + + return super.onStartCommand(intent, flags, startId) + } + + override fun onDestroy() { + super.onDestroy() + player.release() + mediaSession?.release() + } +} \ No newline at end of file diff --git a/apps/readest-app/src-tauri/plugins/tauri-plugin-native-tts/android/src/main/java/NativeTTSPlugin.kt b/apps/readest-app/src-tauri/plugins/tauri-plugin-native-tts/android/src/main/java/NativeTTSPlugin.kt index 20de26e8..dd0a8172 100644 --- a/apps/readest-app/src-tauri/plugins/tauri-plugin-native-tts/android/src/main/java/NativeTTSPlugin.kt +++ b/apps/readest-app/src-tauri/plugins/tauri-plugin-native-tts/android/src/main/java/NativeTTSPlugin.kt @@ -11,13 +11,7 @@ import android.speech.tts.Voice import android.util.Log import android.graphics.Bitmap import android.graphics.BitmapFactory -import androidx.media3.common.MediaMetadata -import androidx.media3.common.Player -import androidx.media3.common.MediaItem -import androidx.media3.common.util.UnstableApi -import androidx.media3.common.ForwardingPlayer -import androidx.media3.session.MediaSession -import androidx.media3.exoplayer.ExoPlayer +import androidx.core.content.ContextCompat import app.tauri.annotation.Command import app.tauri.annotation.InvokeArg import app.tauri.annotation.Permission @@ -92,8 +86,8 @@ class UpdateMediaSessionMetadataArgs { @InvokeArg class UpdateMediaSessionStateArgs { var playing: Boolean? = null - var position: Double? = null - var duration: Double? = null + var position: Int? = null // in milliseconds + var duration: Int? = null // in milliseconds } @InvokeArg @@ -106,78 +100,6 @@ class SetMediaSessionActiveArgs { var foregroundServiceText: String? = null } -class MediaForegroundService : Service() { - companion object { - const val NOTIFICATION_ID = 1001 - const val CHANNEL_ID = "tts_media_playback_channel" - const val ACTION_START = "START_FOREGROUND_SERVICE" - const val ACTION_STOP = "STOP_FOREGROUND_SERVICE" - - var pluginInstance: NativeTTSPlugin? = null - } - - override fun onCreate() { - super.onCreate() - createNotificationChannel() - } - - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - when (intent?.action) { - ACTION_START -> { - startForegroundService() - } - ACTION_STOP -> { - stopForegroundService() - } - } - return START_STICKY // Restart if killed - } - - override fun onBind(intent: Intent?): IBinder? = null - - private fun createNotificationChannel() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val channel = NotificationChannel( - CHANNEL_ID, - NativeTTSPlugin.NOTIFICATION_TITLE, - NotificationManager.IMPORTANCE_MIN - ).apply { - description = NativeTTSPlugin.NOTIFICATION_TEXT - setShowBadge(false) - setSound(null, null) - } - val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - manager.createNotificationChannel(channel) - } - } - - private fun startForegroundService() { - val notification = NotificationCompat.Builder(this, CHANNEL_ID) - .setContentTitle(NativeTTSPlugin.FOREGROUND_SERVICE_TITLE) - .setContentText(NativeTTSPlugin.FOREGROUND_SERVICE_TEXT) - .setSmallIcon(android.R.drawable.ic_media_play) - .setOngoing(true) - .setSilent(true) - .setPriority(NotificationCompat.PRIORITY_MIN) - .setCategory(NotificationCompat.CATEGORY_SERVICE) - .build() - - startForeground(NOTIFICATION_ID, notification) - Log.d("MediaForegroundService", "Foreground service started") - } - - private fun stopForegroundService() { - stopForeground(STOP_FOREGROUND_REMOVE) - stopSelf() - Log.d("MediaForegroundService", "Foreground service stopped") - } - - override fun onDestroy() { - super.onDestroy() - Log.d("MediaForegroundService", "Service destroyed") - } -} - @TauriPlugin( permissions = [ Permission(strings = [Manifest.permission.POST_NOTIFICATIONS], alias = "postNotification") @@ -203,18 +125,8 @@ class NativeTTSPlugin(private val activity: Activity) : Plugin(activity) { private val eventChannels = ConcurrentHashMap>() private val speakingJobs = ConcurrentHashMap() - - private var player: Player? = null - private var mediaSession: MediaSession? = null - private var isMediaSessionActive = false - private var isForegroundServiceRunning = false - private val coroutineScope = CoroutineScope(Dispatchers.Main + SupervisorJob()) - init { - MediaForegroundService.pluginInstance = this - } - @Command fun init(invoke: Invoke) { coroutineScope.launch { @@ -509,95 +421,6 @@ class NativeTTSPlugin(private val activity: Activity) : Plugin(activity) { } } - @UnstableApi - private class WebViewPlayer(player: Player) : ForwardingPlayer(player) { - var eventTrigger: ((String, JSObject) -> Unit)? = null - - override fun play() { - eventTrigger?.invoke("media-session-play", JSObject()) - if (!this.playWhenReady) { - this.playWhenReady = true - } else { - this.playWhenReady = false - } - } - override fun pause() { - eventTrigger?.invoke("media-session-pause", JSObject()) - if (!this.playWhenReady) { - this.playWhenReady = true - } else { - this.playWhenReady = false - } - } - override fun seekToNext() { - eventTrigger?.invoke("media-session-next", JSObject()) - } - override fun seekToPrevious() { - eventTrigger?.invoke("media-session-previous", JSObject()) - } - } - - private fun initializeMediaSession() { - var basePlayer = ExoPlayer.Builder(activity).build() - val webViewPlayer = WebViewPlayer(basePlayer) - webViewPlayer.eventTrigger = { event, data -> trigger(event, data) } - player = webViewPlayer - - mediaSession = MediaSession.Builder(activity, player!!) - .setCallback(object : MediaSession.Callback { - override fun onConnect( - session: MediaSession, - controller: MediaSession.ControllerInfo - ): MediaSession.ConnectionResult { - val builder = MediaSession.ConnectionResult.AcceptedResultBuilder(session) - builder.setAvailablePlayerCommands( - Player.Commands.Builder() - .add(Player.COMMAND_PLAY_PAUSE) - .add(Player.COMMAND_SEEK_TO_NEXT) - .add(Player.COMMAND_SEEK_TO_PREVIOUS) - .build() - ) - return builder.build() - } - }) - .build() - } - - private fun deinitializeMediaSession() { - mediaSession?.release() - mediaSession = null - player?.release() - player = null - } - - private fun startForegroundService() { - try { - val intent = Intent(activity, MediaForegroundService::class.java).apply { - action = MediaForegroundService.ACTION_START - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - activity.startForegroundService(intent) - } else { - activity.startService(intent) - } - Log.d(TAG, "Foreground service started") - } catch (e: Exception) { - Log.e(TAG, "Failed to start foreground service", e) - } - } - - private fun stopForegroundService() { - try { - val intent = Intent(activity, MediaForegroundService::class.java).apply { - action = MediaForegroundService.ACTION_STOP - } - activity.stopService(intent) - Log.d(TAG, "Foreground service stopped") - } catch (e: Exception) { - Log.e(TAG, "Failed to stop foreground service", e) - } - } - private suspend fun loadArtworkFromUrl(urlString: String): Bitmap? { return withContext(Dispatchers.IO) { try { @@ -624,50 +447,26 @@ class NativeTTSPlugin(private val activity: Activity) : Plugin(activity) { } } - private var currentArtworkByteArray: ByteArray? = null - @Command fun update_media_session_metadata(invoke: Invoke) { val args = invoke.parseArgs(UpdateMediaSessionMetadataArgs::class.java) val title = args.title ?: "" val artist = args.artist ?: "" val album = args.album ?: "" - val artworkUrl = args.artwork ?: "" - + coroutineScope.launch { try { - val metadataBuilder = MediaMetadata.Builder() - .setTitle(title) - .setArtist(artist) - .setAlbumTitle(album) - .apply { - if (artworkUrl.isNotEmpty()) { - loadArtworkFromUrl(artworkUrl)?.let { bitmap -> - java.io.ByteArrayOutputStream().use { stream -> - bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream) - currentArtworkByteArray = stream.toByteArray() - } - } - } - currentArtworkByteArray?.let { - setArtworkData(it, MediaMetadata.PICTURE_TYPE_FRONT_COVER) - } - } - - val mediaItem: MediaItem = MediaItem.Builder() - .setMediaId("silent_media") - .setUri("data:audio/wav;base64,UklGRigAAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQQAAAAAAA==") - .setMediaMetadata(metadataBuilder.build()) - .build() - - player?.setMediaItems(listOf(mediaItem, mediaItem)) - player?.prepare() - player?.playWhenReady = true - player?.setRepeatMode(Player.REPEAT_MODE_ALL) - + val artworkBitmap = args.artwork?.let { loadArtworkFromUrl(it) } + val intent = Intent(activity, MediaPlaybackService::class.java).apply { + action = "UPDATE_METADATA" + putExtra("title", title) + putExtra("artist", artist) + putExtra("album", album) + putExtra("artwork", artworkBitmap) + } + activity.startService(intent) invoke.resolve() } catch (e: Exception) { - Log.e("NativeBridgePlugin", "Failed to update metadata: ${e.message}") invoke.reject("Failed to update metadata: ${e.message}") } } @@ -677,15 +476,17 @@ class NativeTTSPlugin(private val activity: Activity) : Plugin(activity) { fun update_media_session_state(invoke: Invoke) { var args = invoke.parseArgs(UpdateMediaSessionStateArgs::class.java) val isPlaying = args.playing ?: false - val position = args.position ?: 0.0 - + val position = args.position ?: 0 + val duration = args.duration ?: 0 + try { - player?.let { player -> - if (position > 0) { - player.seekTo((position * 1000).toLong()) - } - player.playWhenReady = isPlaying + val intent = Intent(activity, MediaPlaybackService::class.java).apply { + action = "UPDATE_PLAYBACK_STATE" + putExtra("playing", isPlaying) + putExtra("position", position) + putExtra("duration", duration) } + activity.startService(intent) invoke.resolve() } catch (e: Exception) { invoke.reject("Failed to update playback state: ${e.message}") @@ -696,7 +497,6 @@ class NativeTTSPlugin(private val activity: Activity) : Plugin(activity) { fun set_media_session_active(invoke: Invoke) { var args = invoke.parseArgs(SetMediaSessionActiveArgs::class.java) val active = args.active ?: true - val keepAppInForeground = args.keepAppInForeground ?: false args.notificationTitle?.let { NOTIFICATION_TITLE = it } args.notificationText?.let { NOTIFICATION_TEXT = it } @@ -704,41 +504,26 @@ class NativeTTSPlugin(private val activity: Activity) : Plugin(activity) { args.foregroundServiceText?.let { FOREGROUND_SERVICE_TEXT = it } try { - if (active && !isMediaSessionActive) { - initializeMediaSession() - if (keepAppInForeground) { - startForegroundService() - isForegroundServiceRunning = true - } - isMediaSessionActive = true - Log.d(TAG, "Media session activated with foreground service") - } else if (!active && isMediaSessionActive) { - deinitializeMediaSession() - if (isForegroundServiceRunning) { - stopForegroundService() - isForegroundServiceRunning = false - } - isMediaSessionActive = false - Log.d(TAG, "Media session deactivated and foreground service stopped") + val intent = Intent(activity, MediaPlaybackService::class.java) + if (active) { + MediaPlaybackService.pluginEventTrigger = { event, data -> trigger(event, data) } + MediaPlaybackService.currentTitle = FOREGROUND_SERVICE_TITLE + MediaPlaybackService.currentArtist = FOREGROUND_SERVICE_TEXT + ContextCompat.startForegroundService(activity, intent) + } else { + activity.stopService(intent) + MediaPlaybackService.pluginEventTrigger = null } invoke.resolve() } catch (e: Exception) { - Log.e(TAG, "Failed to set media session active state: ${e.message}") invoke.reject("Failed to set media session active state: ${e.message}") } } fun destroy() { try { - if (isMediaSessionActive) { - if (isForegroundServiceRunning) { - stopForegroundService() - isForegroundServiceRunning = false - } - isMediaSessionActive = false - } - - deinitializeMediaSession() + val intent = Intent(activity, MediaPlaybackService::class.java) + activity.stopService(intent) coroutineScope.cancel() textToSpeech?.shutdown() @@ -747,8 +532,6 @@ class NativeTTSPlugin(private val activity: Activity) : Plugin(activity) { speakingJobs.values.forEach { it.cancel() } speakingJobs.clear() - MediaForegroundService.pluginInstance = null - Log.d(TAG, "Plugin destroyed successfully") } catch (e: Exception) { Log.e(TAG, "Error during plugin destruction", e) diff --git a/apps/readest-app/src-tauri/plugins/tauri-plugin-native-tts/android/src/main/res/drawable/notification_icon.png b/apps/readest-app/src-tauri/plugins/tauri-plugin-native-tts/android/src/main/res/drawable/notification_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3b7e495a27b1251034e107980e01c176ab63073c GIT binary patch literal 42487 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 = ({ bookKey, gridInsets }) => { await ttsController.start(); } } + + if (mediaSessionRef.current) { + const mediaSession = mediaSessionRef.current; + if (mediaSession instanceof TauriMediaSession) { + await mediaSession.updatePlaybackState({ playing: !isPlaying }); + } else { + mediaSession.playbackState = isPlaying ? 'paused' : 'playing'; + } + } }, [isPlaying, isPaused]); const handleBackward = useCallback(async (byMark = false) => { diff --git a/apps/readest-app/src/libs/mediaSession.ts b/apps/readest-app/src/libs/mediaSession.ts index 0df1860c..f11ff142 100644 --- a/apps/readest-app/src/libs/mediaSession.ts +++ b/apps/readest-app/src/libs/mediaSession.ts @@ -12,8 +12,8 @@ export interface MediaMetadata { export interface PlaybackState { playing: boolean; - position: number; - duration: number; + position?: number; // in milliseconds + duration?: number; // in milliseconds } export interface MediaSessionState { diff --git a/apps/readest-app/src/styles/themes.ts b/apps/readest-app/src/styles/themes.ts index 44df104f..794d38a1 100644 --- a/apps/readest-app/src/styles/themes.ts +++ b/apps/readest-app/src/styles/themes.ts @@ -230,7 +230,6 @@ export const applyCustomTheme = ( const lightThemeName = customTheme ? `${customTheme.name}-light` : `${themeName}-light`; const darkThemeName = customTheme ? `${customTheme.name}-dark` : `${themeName}-dark`; - console.log('themeName', themeName); const lightPalette = customTheme ? generateLightPalette(customTheme.colors.light) : (themes.find((t) => t.name === themeName) || themes[0]!).colors.light;