mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 23:51:21 +02:00
Fix issue where theme songs played when the app is backgrounded (#34)
Previously if the app is playing a show's theme song and the app is backgrounded, such as by pressing Home, the music would continue. This PR fixes that.
This commit is contained in:
parent
5bb46bf34b
commit
93f7abfa3b
3 changed files with 82 additions and 39 deletions
|
|
@ -37,6 +37,7 @@ import com.github.damontecres.wholphin.ui.nav.NavigationManager
|
||||||
import com.github.damontecres.wholphin.ui.theme.WholphinTheme
|
import com.github.damontecres.wholphin.ui.theme.WholphinTheme
|
||||||
import com.github.damontecres.wholphin.util.AppUpgradeHandler
|
import com.github.damontecres.wholphin.util.AppUpgradeHandler
|
||||||
import com.github.damontecres.wholphin.util.ExceptionHandler
|
import com.github.damontecres.wholphin.util.ExceptionHandler
|
||||||
|
import com.github.damontecres.wholphin.util.ThemeSongPlayer
|
||||||
import com.github.damontecres.wholphin.util.UpdateChecker
|
import com.github.damontecres.wholphin.util.UpdateChecker
|
||||||
import com.github.damontecres.wholphin.util.profile.createDeviceProfile
|
import com.github.damontecres.wholphin.util.profile.createDeviceProfile
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
@ -68,6 +69,9 @@ class MainActivity : AppCompatActivity() {
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var appUpgradeHandler: AppUpgradeHandler
|
lateinit var appUpgradeHandler: AppUpgradeHandler
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var themeSongPlayer: ThemeSongPlayer
|
||||||
|
|
||||||
@OptIn(ExperimentalTvMaterial3Api::class)
|
@OptIn(ExperimentalTvMaterial3Api::class)
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
@ -164,4 +168,9 @@ class MainActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
super.onStop()
|
||||||
|
themeSongPlayer.stop()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,18 +5,12 @@ import android.widget.Toast
|
||||||
import androidx.annotation.OptIn
|
import androidx.annotation.OptIn
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.media3.common.MediaItem
|
|
||||||
import androidx.media3.common.Player
|
|
||||||
import androidx.media3.common.util.UnstableApi
|
import androidx.media3.common.util.UnstableApi
|
||||||
import androidx.media3.datasource.okhttp.OkHttpDataSource
|
|
||||||
import androidx.media3.exoplayer.ExoPlayer
|
|
||||||
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
|
|
||||||
import com.github.damontecres.wholphin.data.ChosenStreams
|
import com.github.damontecres.wholphin.data.ChosenStreams
|
||||||
import com.github.damontecres.wholphin.data.ItemPlaybackRepository
|
import com.github.damontecres.wholphin.data.ItemPlaybackRepository
|
||||||
import com.github.damontecres.wholphin.data.model.BaseItem
|
import com.github.damontecres.wholphin.data.model.BaseItem
|
||||||
import com.github.damontecres.wholphin.data.model.ItemPlayback
|
import com.github.damontecres.wholphin.data.model.ItemPlayback
|
||||||
import com.github.damontecres.wholphin.data.model.Person
|
import com.github.damontecres.wholphin.data.model.Person
|
||||||
import com.github.damontecres.wholphin.hilt.AuthOkHttpClient
|
|
||||||
import com.github.damontecres.wholphin.preferences.ThemeSongVolume
|
import com.github.damontecres.wholphin.preferences.ThemeSongVolume
|
||||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||||
import com.github.damontecres.wholphin.ui.launchIO
|
import com.github.damontecres.wholphin.ui.launchIO
|
||||||
|
|
@ -30,6 +24,7 @@ import com.github.damontecres.wholphin.util.GetEpisodesRequestHandler
|
||||||
import com.github.damontecres.wholphin.util.GetItemsRequestHandler
|
import com.github.damontecres.wholphin.util.GetItemsRequestHandler
|
||||||
import com.github.damontecres.wholphin.util.LoadingExceptionHandler
|
import com.github.damontecres.wholphin.util.LoadingExceptionHandler
|
||||||
import com.github.damontecres.wholphin.util.LoadingState
|
import com.github.damontecres.wholphin.util.LoadingState
|
||||||
|
import com.github.damontecres.wholphin.util.ThemeSongPlayer
|
||||||
import com.github.damontecres.wholphin.util.profile.Codec
|
import com.github.damontecres.wholphin.util.profile.Codec
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
|
@ -38,7 +33,6 @@ import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import org.jellyfin.sdk.api.client.ApiClient
|
import org.jellyfin.sdk.api.client.ApiClient
|
||||||
import org.jellyfin.sdk.api.client.extensions.libraryApi
|
import org.jellyfin.sdk.api.client.extensions.libraryApi
|
||||||
import org.jellyfin.sdk.api.client.extensions.playStateApi
|
import org.jellyfin.sdk.api.client.extensions.playStateApi
|
||||||
|
|
@ -62,11 +56,10 @@ class SeriesViewModel
|
||||||
constructor(
|
constructor(
|
||||||
api: ApiClient,
|
api: ApiClient,
|
||||||
@param:ApplicationContext val context: Context,
|
@param:ApplicationContext val context: Context,
|
||||||
@param:AuthOkHttpClient private val okHttpClient: OkHttpClient,
|
|
||||||
private val navigationManager: NavigationManager,
|
private val navigationManager: NavigationManager,
|
||||||
private val itemPlaybackRepository: ItemPlaybackRepository,
|
private val itemPlaybackRepository: ItemPlaybackRepository,
|
||||||
|
private val themeSongPlayer: ThemeSongPlayer,
|
||||||
) : ItemViewModel(api) {
|
) : ItemViewModel(api) {
|
||||||
private var player: Player? = null
|
|
||||||
private lateinit var seriesId: UUID
|
private lateinit var seriesId: UUID
|
||||||
private lateinit var prefs: UserPreferences
|
private lateinit var prefs: UserPreferences
|
||||||
val loading = MutableLiveData<LoadingState>(LoadingState.Loading)
|
val loading = MutableLiveData<LoadingState>(LoadingState.Loading)
|
||||||
|
|
@ -117,18 +110,6 @@ class SeriesViewModel
|
||||||
*/
|
*/
|
||||||
@OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
private fun maybePlayThemeSong(playThemeSongs: ThemeSongVolume) {
|
private fun maybePlayThemeSong(playThemeSongs: ThemeSongVolume) {
|
||||||
val volume =
|
|
||||||
when (playThemeSongs) {
|
|
||||||
ThemeSongVolume.UNRECOGNIZED,
|
|
||||||
ThemeSongVolume.DISABLED,
|
|
||||||
-> return
|
|
||||||
|
|
||||||
ThemeSongVolume.LOWEST -> .05f
|
|
||||||
ThemeSongVolume.LOW -> .1f
|
|
||||||
ThemeSongVolume.MEDIUM -> .25f
|
|
||||||
ThemeSongVolume.HIGH -> .5f
|
|
||||||
ThemeSongVolume.HIGHEST -> 75f
|
|
||||||
}
|
|
||||||
viewModelScope.launch(ExceptionHandler()) {
|
viewModelScope.launch(ExceptionHandler()) {
|
||||||
val themeSongs = api.libraryApi.getThemeSongs(seriesId).content
|
val themeSongs = api.libraryApi.getThemeSongs(seriesId).content
|
||||||
themeSongs.items.firstOrNull()?.let { theme ->
|
themeSongs.items.firstOrNull()?.let { theme ->
|
||||||
|
|
@ -146,24 +127,10 @@ class SeriesViewModel
|
||||||
)
|
)
|
||||||
Timber.Forest.v("Found theme song for series $seriesId")
|
Timber.Forest.v("Found theme song for series $seriesId")
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
val player =
|
themeSongPlayer.play(playThemeSongs, url)
|
||||||
ExoPlayer
|
|
||||||
.Builder(context)
|
|
||||||
.setMediaSourceFactory(
|
|
||||||
DefaultMediaSourceFactory(
|
|
||||||
OkHttpDataSource.Factory(okHttpClient),
|
|
||||||
),
|
|
||||||
).build()
|
|
||||||
.apply {
|
|
||||||
this.volume = volume
|
|
||||||
playWhenReady = true
|
|
||||||
this@SeriesViewModel.player = this
|
|
||||||
}
|
|
||||||
addCloseable {
|
addCloseable {
|
||||||
player.release()
|
themeSongPlayer.stop()
|
||||||
}
|
}
|
||||||
player.setMediaItem(MediaItem.fromUri(url))
|
|
||||||
player.prepare()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -171,8 +138,7 @@ class SeriesViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
fun release() {
|
fun release() {
|
||||||
player?.release()
|
themeSongPlayer.stop()
|
||||||
player = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getSeasons(item: BaseItem): ItemListAndMapping {
|
private suspend fun getSeasons(item: BaseItem): ItemListAndMapping {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
package com.github.damontecres.wholphin.util
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.annotation.OptIn
|
||||||
|
import androidx.media3.common.MediaItem
|
||||||
|
import androidx.media3.common.Player
|
||||||
|
import androidx.media3.common.util.UnstableApi
|
||||||
|
import androidx.media3.datasource.okhttp.OkHttpDataSource
|
||||||
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
|
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
|
||||||
|
import com.github.damontecres.wholphin.hilt.AuthOkHttpClient
|
||||||
|
import com.github.damontecres.wholphin.preferences.ThemeSongVolume
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple service to play theme song music
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
class ThemeSongPlayer
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
@param:ApplicationContext val context: Context,
|
||||||
|
@param:AuthOkHttpClient val okHttpClient: OkHttpClient,
|
||||||
|
) {
|
||||||
|
private var player: Player? = null
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
|
fun play(
|
||||||
|
volume: ThemeSongVolume,
|
||||||
|
url: String,
|
||||||
|
) {
|
||||||
|
val volumeLevel =
|
||||||
|
when (volume) {
|
||||||
|
ThemeSongVolume.UNRECOGNIZED,
|
||||||
|
ThemeSongVolume.DISABLED,
|
||||||
|
-> return
|
||||||
|
|
||||||
|
ThemeSongVolume.LOWEST -> .05f
|
||||||
|
ThemeSongVolume.LOW -> .1f
|
||||||
|
ThemeSongVolume.MEDIUM -> .25f
|
||||||
|
ThemeSongVolume.HIGH -> .5f
|
||||||
|
ThemeSongVolume.HIGHEST -> 75f
|
||||||
|
}
|
||||||
|
val player =
|
||||||
|
ExoPlayer
|
||||||
|
.Builder(context)
|
||||||
|
.setMediaSourceFactory(
|
||||||
|
DefaultMediaSourceFactory(
|
||||||
|
OkHttpDataSource.Factory(okHttpClient),
|
||||||
|
),
|
||||||
|
).build()
|
||||||
|
.apply {
|
||||||
|
this.volume = volumeLevel
|
||||||
|
playWhenReady = true
|
||||||
|
}
|
||||||
|
player.setMediaItem(MediaItem.fromUri(url))
|
||||||
|
player.prepare()
|
||||||
|
this.player = player
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stop() {
|
||||||
|
player?.stop()
|
||||||
|
player?.release()
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue