diff --git a/app/src/main/java/com/maxrave/simpmusic/common/Config.kt b/app/src/main/java/com/maxrave/simpmusic/common/Config.kt index a2595d7e..8923a584 100644 --- a/app/src/main/java/com/maxrave/simpmusic/common/Config.kt +++ b/app/src/main/java/com/maxrave/simpmusic/common/Config.kt @@ -21,6 +21,7 @@ object Config { const val RADIO_CLICK = "RADIO_CLICK" const val MINIPLAYER_CLICK = "MINIPLAYER_CLICK" const val SHARE = "SHARE" + const val RECOVER_TRACK_QUEUE = "RECOVER_TRACK_QUEUE" const val VN = "VN" diff --git a/app/src/main/java/com/maxrave/simpmusic/di/MusicServiceModule.kt b/app/src/main/java/com/maxrave/simpmusic/di/MusicServiceModule.kt index f43f271b..bbb6e5b3 100644 --- a/app/src/main/java/com/maxrave/simpmusic/di/MusicServiceModule.kt +++ b/app/src/main/java/com/maxrave/simpmusic/di/MusicServiceModule.kt @@ -3,12 +3,16 @@ package com.maxrave.simpmusic.di import android.app.PendingIntent import android.content.Context import android.content.Intent +import androidx.core.net.toUri import androidx.media3.common.AudioAttributes import androidx.media3.common.C import androidx.media3.common.util.UnstableApi import androidx.media3.database.DatabaseProvider import androidx.media3.database.StandaloneDatabaseProvider +import androidx.media3.datasource.DataSource +import androidx.media3.datasource.DataSpec import androidx.media3.datasource.DefaultHttpDataSource +import androidx.media3.datasource.ResolvingDataSource import androidx.media3.datasource.cache.CacheDataSource import androidx.media3.datasource.cache.CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR import androidx.media3.datasource.cache.NoOpCacheEvictor @@ -16,7 +20,10 @@ import androidx.media3.datasource.cache.SimpleCache import androidx.media3.exoplayer.ExoPlayer import androidx.media3.exoplayer.source.DefaultMediaSourceFactory import androidx.media3.exoplayer.trackselection.DefaultTrackSelector +import androidx.media3.extractor.mkv.MatroskaExtractor +import androidx.media3.extractor.mp4.FragmentedMp4Extractor import androidx.media3.session.MediaSession +import com.maxrave.simpmusic.common.QUALITY import com.maxrave.simpmusic.data.dataStore.DataStoreManager import com.maxrave.simpmusic.data.repository.MainRepository import com.maxrave.simpmusic.service.SimpleMediaServiceHandler @@ -28,6 +35,8 @@ import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.runBlocking import javax.inject.Qualifier import javax.inject.Singleton @@ -100,14 +109,53 @@ object MusicServiceModule { .setFlags(FLAG_IGNORE_CACHE_ON_ERROR) } +// @Provides +// @Singleton +// @UnstableApi +// fun provideMediaSourceFactory( +// @ApplicationContext context: Context, +// cacheDataSourceFactory: CacheDataSource.Factory +// ): DefaultMediaSourceFactory = +// DefaultMediaSourceFactory(context).setDataSourceFactory(cacheDataSourceFactory) + + @Provides + @Singleton + @UnstableApi + fun provideResolvingDataSourceFactory( + cacheDataSourceFactory: CacheDataSource.Factory, + @DownloadCache downloadCache: SimpleCache, @PlayerCache playerCache: SimpleCache, mainRepository: MainRepository, dataStoreManager: DataStoreManager + ): DataSource.Factory { + return ResolvingDataSource.Factory(cacheDataSourceFactory) { dataSpec -> + val mediaId = dataSpec.key ?: error("No media id") + val CHUNK_LENGTH = 512 * 1024L + if (downloadCache.isCached(mediaId, dataSpec.position, if (dataSpec.length >= 0) dataSpec.length else 1) || playerCache.isCached(mediaId, dataSpec.position, CHUNK_LENGTH)) { + return@Factory dataSpec + } + var dataSpecReturn: DataSpec? = null + runBlocking { + val itag = dataStoreManager.quality.first() + + mainRepository.getStream(mediaId, if (itag == QUALITY.items[0].toString()) QUALITY.itags[0] else QUALITY.itags[1]).collect { + if (it != null) { + dataSpecReturn = dataSpec.withUri(it.toUri()) + } + } + } + return@Factory dataSpecReturn!! + } + } + @Provides @Singleton @UnstableApi fun provideMediaSourceFactory( - @ApplicationContext context: Context, - cacheDataSourceFactory: CacheDataSource.Factory + dataSourceFactory: DataSource.Factory ): DefaultMediaSourceFactory = - DefaultMediaSourceFactory(context).setDataSourceFactory(cacheDataSourceFactory) + DefaultMediaSourceFactory( + dataSourceFactory + ) { + arrayOf(MatroskaExtractor(), FragmentedMp4Extractor()) + } @Provides @Singleton diff --git a/app/src/main/java/com/maxrave/simpmusic/extension/AllExt.kt b/app/src/main/java/com/maxrave/simpmusic/extension/AllExt.kt index 466a4daa..d728a523 100644 --- a/app/src/main/java/com/maxrave/simpmusic/extension/AllExt.kt +++ b/app/src/main/java/com/maxrave/simpmusic/extension/AllExt.kt @@ -7,8 +7,11 @@ import android.graphics.Color import android.view.View import android.view.ViewGroup import android.widget.ImageButton +import androidx.core.net.toUri import androidx.datastore.preferences.preferencesDataStore import androidx.media3.common.MediaItem +import androidx.media3.common.MediaMetadata +import androidx.media3.common.util.UnstableApi import androidx.sqlite.db.SimpleSQLiteQuery import com.maxrave.kotlinytmusicscraper.models.SongItem import com.maxrave.kotlinytmusicscraper.models.VideoItem @@ -277,6 +280,31 @@ fun MediaItem?.toSongEntity(): SongEntity? { downloadState = 0 ) else null } +@UnstableApi +fun Track.toMediaItem() : MediaItem { + return MediaItem.Builder() + .setMediaId(this.videoId) + .setUri(this.videoId) + .setCustomCacheKey(this.videoId) + .setMediaMetadata( + MediaMetadata.Builder() + .setTitle(this.title) + .setArtist(this.artists.toListName().connectArtists()) + .setArtworkUri(this.thumbnails?.lastOrNull()?.url?.toUri()) + .setAlbumTitle(this.album?.name) + .build() + ) + .build() +} + +@UnstableApi +fun List.toMediaItems(): List { + val listMediaItem = mutableListOf() + for (item in this) { + listMediaItem.add(item.toMediaItem()) + } + return listMediaItem +} @JvmName("SongResulttoListTrack") fun ArrayList.toListTrack(): ArrayList { diff --git a/app/src/main/java/com/maxrave/simpmusic/service/SimpleMediaServiceHandler.kt b/app/src/main/java/com/maxrave/simpmusic/service/SimpleMediaServiceHandler.kt index 69bfb0db..0ae1f99d 100644 --- a/app/src/main/java/com/maxrave/simpmusic/service/SimpleMediaServiceHandler.kt +++ b/app/src/main/java/com/maxrave/simpmusic/service/SimpleMediaServiceHandler.kt @@ -510,13 +510,14 @@ class SimpleMediaServiceHandler @Inject constructor( ) } fun release() { + stopBufferedUpdate() + stopProgressUpdate() sendCloseEqualizerIntent() player.removeListener(this) job?.cancel() sleepTimerJob?.cancel() volumeNormalizationJob?.cancel() updateNotificationJob?.cancel() - GlobalScope.cancel() } private fun updateNotification() { diff --git a/app/src/main/java/com/maxrave/simpmusic/service/test/source/FetchQueue.kt b/app/src/main/java/com/maxrave/simpmusic/service/test/source/FetchQueue.kt deleted file mode 100644 index cbe0276f..00000000 --- a/app/src/main/java/com/maxrave/simpmusic/service/test/source/FetchQueue.kt +++ /dev/null @@ -1,84 +0,0 @@ -package com.maxrave.simpmusic.service.test.source - -import android.app.Service -import android.content.Intent -import android.os.IBinder -import android.util.Log -import androidx.media3.common.util.UnstableApi -import com.maxrave.simpmusic.data.queue.Queue -import com.maxrave.simpmusic.service.SimpleMediaServiceHandler -import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.cancel -import kotlinx.coroutines.launch -import javax.inject.Inject - -@AndroidEntryPoint -class FetchQueue: Service() { - @Inject - lateinit var musicSource: MusicSource - - @Inject - lateinit var simpleMediaServiceHandler: SimpleMediaServiceHandler - - private val job = SupervisorJob() - private val scope = CoroutineScope(Dispatchers.Main + job) - - - override fun onBind(p0: Intent?): IBinder? { - return null - } - - @UnstableApi - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - val index = intent?.extras?.getInt("index") - val downloaded = intent?.extras?.getInt("downloaded") - Log.d("Check Index inside Service", "$index") - Log.d("Check Queue", "getRelated: ${Queue.getQueue().toString()}") - scope.launch { - if (downloaded == 1){ - musicSource.load(1) - } - else { - musicSource.load() - } - musicSource.stateFlow.collect{ state -> - if (state == StateSource.STATE_INITIALIZED) { - when (index) { - null -> { - musicSource.addFirstMediaItem(simpleMediaServiceHandler.getMediaItemWithIndex(0)) - } - -1 -> { - - } - else -> { - musicSource.addFirstMediaItemToIndex(simpleMediaServiceHandler.getMediaItemWithIndex(0), index) - Queue.getNowPlaying().let { song -> - if (song != null) { - musicSource.catalogMetadata.removeAt(0) - musicSource.catalogMetadata.add(index, song) - if (downloaded != 1){ - val tempUrl = musicSource.downloadUrl[0] - musicSource.downloadUrl.removeAt(0) - musicSource.downloadUrl.add(index, tempUrl) - } - } - } - } - } - stopSelf() - } - } - } - return START_NOT_STICKY - } - - override fun onDestroy() { - super.onDestroy() - scope.cancel() - Log.d("FetchQueue", "onDestroy: ") - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/maxrave/simpmusic/service/test/source/MusicSource.kt b/app/src/main/java/com/maxrave/simpmusic/service/test/source/MusicSource.kt index c1033cc5..0c8cba90 100644 --- a/app/src/main/java/com/maxrave/simpmusic/service/test/source/MusicSource.kt +++ b/app/src/main/java/com/maxrave/simpmusic/service/test/source/MusicSource.kt @@ -5,7 +5,6 @@ import androidx.core.net.toUri import androidx.media3.common.MediaItem import androidx.media3.common.MediaMetadata import androidx.media3.common.util.UnstableApi -import com.maxrave.simpmusic.common.QUALITY import com.maxrave.simpmusic.data.dataStore.DataStoreManager import com.maxrave.simpmusic.data.model.browse.album.Track import com.maxrave.simpmusic.data.model.searchResult.songs.Artist @@ -20,14 +19,11 @@ import com.maxrave.simpmusic.service.test.source.StateSource.STATE_INITIALIZED import com.maxrave.simpmusic.service.test.source.StateSource.STATE_INITIALIZING import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.runBlocking import javax.inject.Inject class MusicSource @Inject constructor(private val simpleMediaServiceHandler: SimpleMediaServiceHandler, private val dataStoreManager: DataStoreManager, private val mainRepository: MainRepository) { var catalogMetadata: ArrayList = (arrayListOf()) - var downloadUrl: ArrayList = arrayListOf() var added: MutableStateFlow = MutableStateFlow(false) @@ -69,7 +65,6 @@ class MusicSource @Inject constructor(private val simpleMediaServiceHandler: Sim fun reset() { _currentSongIndex.value = 0 catalogMetadata.clear() - downloadUrl.clear() state = STATE_CREATED } fun setCurrentSongIndex(index: Int) { @@ -88,12 +83,6 @@ class MusicSource @Inject constructor(private val simpleMediaServiceHandler: Sim state = STATE_INITIALIZING val tempQueue: ArrayList = arrayListOf() tempQueue.addAll(Queue.getQueue()) - val quality = runBlocking { dataStoreManager.quality.first() } - val itag = when (quality) { - QUALITY.items[0].toString() -> 250 - QUALITY.items[1].toString() -> 251 - else -> 251 - } for (i in 0 until tempQueue.size){ val track = tempQueue[i] var thumbUrl = track.thumbnails?.last()?.url ?: "http://i.ytimg.com/vi/${track.videoId}/maxresdefault.jpg" @@ -107,7 +96,8 @@ class MusicSource @Inject constructor(private val simpleMediaServiceHandler: Sim if (format != null) { val mediaItem = MediaItem.Builder() .setMediaId(track.videoId) - .setUri(track.videoId.toUri()) + .setUri(track.videoId) + .setCustomCacheKey(track.videoId) .setMediaMetadata( MediaMetadata.Builder() .setArtworkUri(thumbUrl.toUri()) @@ -122,12 +112,32 @@ class MusicSource @Inject constructor(private val simpleMediaServiceHandler: Sim artists = listOf(Artist(format.uploaderId, format.uploader?: "" )) )) } + else { + val mediaItem = MediaItem.Builder() + .setMediaId(track.videoId) + .setUri(track.videoId) + .setCustomCacheKey(track.videoId) + .setMediaMetadata( + MediaMetadata.Builder() + .setArtworkUri(thumbUrl.toUri()) + .setAlbumTitle(track.album?.name) + .setTitle(track.title) + .setArtist("Various Artists") + .build() + ) + .build() + simpleMediaServiceHandler.addMediaItemNotSet(mediaItem) + catalogMetadata.add(track.copy( + artists = listOf(Artist("", "Various Artists" )) + )) + } } } else { val mediaItem = MediaItem.Builder() .setMediaId(track.videoId) - .setUri(track.videoId.toUri()) + .setUri(track.videoId) + .setCustomCacheKey(track.videoId) .setMediaMetadata( MediaMetadata.Builder() .setArtworkUri(thumbUrl.toUri()) @@ -141,65 +151,77 @@ class MusicSource @Inject constructor(private val simpleMediaServiceHandler: Sim catalogMetadata.add(track) } Log.d("MusicSource", "updateCatalog: ${track.title}, ${catalogMetadata.size}") - downloadUrl.add(" ") added.value = true } else { - mainRepository.getStream(track.videoId, itag).collect { stream -> - if (stream != null) { - val uri = stream - val artistName: String = track.artists.toListName().connectArtists() - if (uri != null) { - if (!catalogMetadata.contains(track)) { - if (track.artists.isNullOrEmpty()) - { - mainRepository.getFormat(track.videoId).collect { format -> - if (format != null) { - catalogMetadata.add(track.copy( - artists = listOf(Artist(format.uploaderId, format.uploader?: "" )) - )) - simpleMediaServiceHandler.addMediaItemNotSet( - MediaItem.Builder().setUri(uri) - .setMediaId(track.videoId) - .setMediaMetadata( - MediaMetadata.Builder() - .setTitle(track.title) - .setArtist(format.uploader) - .setArtworkUri(thumbUrl.toUri()) - .setAlbumTitle(track.album?.name) - .build() - ) - .build() - ) - } - } - } - else { - simpleMediaServiceHandler.addMediaItemNotSet( - MediaItem.Builder().setUri(uri) - .setMediaId(track.videoId) - .setMediaMetadata( - MediaMetadata.Builder() - .setTitle(track.title) - .setArtist(artistName) - .setArtworkUri(thumbUrl.toUri()) - .setAlbumTitle(track.album?.name) - .build() - ) + val artistName: String = track.artists.toListName().connectArtists() + if (!catalogMetadata.contains(track)) { + if (track.artists.isNullOrEmpty()) + { + mainRepository.getFormat(track.videoId).collect { format -> + if (format != null) { + catalogMetadata.add(track.copy( + artists = listOf(Artist(format.uploaderId, format.uploader?: "" )) + )) + simpleMediaServiceHandler.addMediaItemNotSet( + MediaItem.Builder().setUri(track.videoId) + .setMediaId(track.videoId) + .setCustomCacheKey(track.videoId) + .setMediaMetadata( + MediaMetadata.Builder() + .setTitle(track.title) + .setArtist(format.uploader) + .setArtworkUri(thumbUrl.toUri()) + .setAlbumTitle(track.album?.name) + .build() + ) + .build() + ) + } + else { + val mediaItem = MediaItem.Builder() + .setMediaId(track.videoId) + .setUri(track.videoId) + .setCustomCacheKey(track.videoId) + .setMediaMetadata( + MediaMetadata.Builder() + .setArtworkUri(thumbUrl.toUri()) + .setAlbumTitle(track.album?.name) + .setTitle(track.title) + .setArtist("Various Artists") .build() ) - catalogMetadata.add(track) - } - Log.d( - "MusicSource", - "updateCatalog: ${track.title}, ${catalogMetadata.size}" - ) - downloadUrl.add(uri.toString()) - added.value = true - Log.d("MusicSource", "updateCatalog: ${track.title}") + .build() + simpleMediaServiceHandler.addMediaItemNotSet(mediaItem) + catalogMetadata.add(track.copy( + artists = listOf(Artist("", "Various Artists" )) + )) } } } + else { + simpleMediaServiceHandler.addMediaItemNotSet( + MediaItem.Builder().setUri(track.videoId) + .setMediaId(track.videoId) + .setCustomCacheKey(track.videoId) + .setMediaMetadata( + MediaMetadata.Builder() + .setTitle(track.title) + .setArtist(artistName) + .setArtworkUri(thumbUrl.toUri()) + .setAlbumTitle(track.album?.name) + .build() + ) + .build() + ) + catalogMetadata.add(track) + } + Log.d( + "MusicSource", + "updateCatalog: ${track.title}, ${catalogMetadata.size}" + ) + added.value = true + Log.d("MusicSource", "updateCatalog: ${track.title}") } } } diff --git a/app/src/main/java/com/maxrave/simpmusic/ui/MainActivity.kt b/app/src/main/java/com/maxrave/simpmusic/ui/MainActivity.kt index b3a869c0..877c716b 100644 --- a/app/src/main/java/com/maxrave/simpmusic/ui/MainActivity.kt +++ b/app/src/main/java/com/maxrave/simpmusic/ui/MainActivity.kt @@ -8,7 +8,6 @@ import android.graphics.drawable.GradientDrawable import android.net.Uri import android.os.Build import android.os.Bundle -import android.text.Html import android.util.Log import android.view.View import android.view.animation.AnimationUtils @@ -53,9 +52,7 @@ import com.maxrave.simpmusic.data.model.browse.album.Track import com.maxrave.simpmusic.data.queue.Queue import com.maxrave.simpmusic.databinding.ActivityMainBinding import com.maxrave.simpmusic.extension.isMyServiceRunning -import com.maxrave.simpmusic.extension.toTrack import com.maxrave.simpmusic.service.SimpleMediaService -import com.maxrave.simpmusic.service.test.source.FetchQueue import com.maxrave.simpmusic.service.test.source.MusicSource import com.maxrave.simpmusic.viewModel.SharedViewModel import com.maxrave.simpmusic.viewModel.UIEvent @@ -523,28 +520,8 @@ class MainActivity : AppCompatActivity() { } Queue.clear() Queue.addAll(queueData) - viewModel.removeSaveQueue() - if (!isMyServiceRunning(FetchQueue::class.java)) { - startService( - Intent( - this, - FetchQueue::class.java - ) - ) - } else { - stopService( - Intent( - this, - FetchQueue::class.java - ) - ) - startService( - Intent( - this, - FetchQueue::class.java - ) - ) - } + viewModel.resetRelated() + viewModel.addQueueToPlayer() checkForUpdate() } } @@ -572,10 +549,6 @@ class MainActivity : AppCompatActivity() { if (viewModel.isServiceRunning.value == true){ stopService(Intent(this, SimpleMediaService::class.java)) Log.d("Service", "Service stopped") - if (this.isMyServiceRunning(FetchQueue:: class.java)){ - stopService(Intent(this, FetchQueue::class.java)) - Log.d("Service", "FetchQueue stopped") - } if (this.isMyServiceRunning(DownloadService:: class.java)){ this.stopService(Intent(this, DownloadService::class.java)) viewModel.changeAllDownloadingToError() diff --git a/app/src/main/java/com/maxrave/simpmusic/ui/fragment/other/PlaylistFragment.kt b/app/src/main/java/com/maxrave/simpmusic/ui/fragment/other/PlaylistFragment.kt index 479beb6f..00354ad6 100644 --- a/app/src/main/java/com/maxrave/simpmusic/ui/fragment/other/PlaylistFragment.kt +++ b/app/src/main/java/com/maxrave/simpmusic/ui/fragment/other/PlaylistFragment.kt @@ -107,7 +107,10 @@ class PlaylistFragment: Fragment() { playlistItemAdapter = PlaylistItemAdapter(arrayListOf()) binding.rvListSong.apply { adapter = playlistItemAdapter - layoutManager = LinearLayoutManager(requireContext()) + layoutManager = LinearLayoutManager(requireContext()).also { + it.initialPrefetchItemCount = 20 + } + setHasFixedSize(false) } var id = requireArguments().getString("id") val downloaded = arguments?.getInt("downloaded") diff --git a/app/src/main/java/com/maxrave/simpmusic/ui/fragment/player/InfoFragment.kt b/app/src/main/java/com/maxrave/simpmusic/ui/fragment/player/InfoFragment.kt index f2136bcf..92ed5a9f 100644 --- a/app/src/main/java/com/maxrave/simpmusic/ui/fragment/player/InfoFragment.kt +++ b/app/src/main/java/com/maxrave/simpmusic/ui/fragment/player/InfoFragment.kt @@ -75,14 +75,12 @@ class InfoFragment: BottomSheetDialogFragment(){ override fun onViewCreated(view: View, savedInstanceState: Bundle?) { if (viewModel.nowPlayingMediaItem.value != null) { val data = musicSource.catalogMetadata[viewModel.getCurrentMediaItemIndex()] - val downloadUrl = musicSource.downloadUrl[viewModel.getCurrentMediaItemIndex()] with(binding){ toolbar.title = data.title artistsName.text = data.artists.toListName().connectArtists() "https://www.youtube.com/watch?v=${data.videoId}".also { youtubeUrl.text = it } title.text = data.title albumName.text = data.album?.name - binding.downloadUrl .text = downloadUrl if (viewModel.format.value != null){ val format = viewModel.format.value itag.text = format?.itag.toString() diff --git a/app/src/main/java/com/maxrave/simpmusic/ui/fragment/player/NowPlayingFragment.kt b/app/src/main/java/com/maxrave/simpmusic/ui/fragment/player/NowPlayingFragment.kt index befa2837..1f129190 100644 --- a/app/src/main/java/com/maxrave/simpmusic/ui/fragment/player/NowPlayingFragment.kt +++ b/app/src/main/java/com/maxrave/simpmusic/ui/fragment/player/NowPlayingFragment.kt @@ -42,6 +42,12 @@ import com.maxrave.simpmusic.R import com.maxrave.simpmusic.adapter.artist.SeeArtistOfNowPlayingAdapter import com.maxrave.simpmusic.adapter.playlist.AddToAPlaylistAdapter import com.maxrave.simpmusic.common.Config +import com.maxrave.simpmusic.common.Config.ALBUM_CLICK +import com.maxrave.simpmusic.common.Config.MINIPLAYER_CLICK +import com.maxrave.simpmusic.common.Config.PLAYLIST_CLICK +import com.maxrave.simpmusic.common.Config.SHARE +import com.maxrave.simpmusic.common.Config.SONG_CLICK +import com.maxrave.simpmusic.common.Config.VIDEO_CLICK import com.maxrave.simpmusic.common.DownloadState import com.maxrave.simpmusic.data.db.entities.LocalPlaylistEntity import com.maxrave.simpmusic.data.model.browse.album.Track @@ -53,7 +59,6 @@ import com.maxrave.simpmusic.databinding.BottomSheetSeeArtistOfNowPlayingBinding import com.maxrave.simpmusic.databinding.BottomSheetSleepTimerBinding import com.maxrave.simpmusic.databinding.FragmentNowPlayingBinding import com.maxrave.simpmusic.extension.connectArtists -import com.maxrave.simpmusic.extension.isMyServiceRunning import com.maxrave.simpmusic.extension.removeConflicts import com.maxrave.simpmusic.extension.setEnabledAll import com.maxrave.simpmusic.extension.toListName @@ -61,7 +66,6 @@ import com.maxrave.simpmusic.extension.toTrack import com.maxrave.simpmusic.service.RepeatState import com.maxrave.simpmusic.service.SimpleMediaServiceHandler import com.maxrave.simpmusic.service.test.download.MusicDownloadService -import com.maxrave.simpmusic.service.test.source.FetchQueue import com.maxrave.simpmusic.service.test.source.MusicSource import com.maxrave.simpmusic.utils.Resource import com.maxrave.simpmusic.viewModel.SharedViewModel @@ -150,7 +154,7 @@ class NowPlayingFragment : Fragment() { Log.d("check Video ID in Fragment", videoId.toString()) when (type) { - Config.SONG_CLICK -> { + SONG_CLICK -> { if (viewModel.videoId.value == videoId) { gradientDrawable = viewModel.gradientDrawable.value lyricsBackground = viewModel.lyricsBackground.value @@ -177,22 +181,23 @@ class NowPlayingFragment : Fragment() { // } // } musicSource.reset() - if (requireContext().isMyServiceRunning(FetchQueue::class.java)) { - requireActivity().stopService( - Intent( - requireContext(), - FetchQueue::class.java - ) - ) - } - viewModel.loadMediaItemFromTrack(it) + viewModel.resetRelated() +// if (requireContext().isMyServiceRunning(FetchQueue::class.java)) { +// requireActivity().stopService( +// Intent( +// requireContext(), +// FetchQueue::class.java +// ) +// ) +// } + viewModel.loadMediaItemFromTrack(it, SONG_CLICK) viewModel.videoId.postValue(it.videoId) viewModel.from.postValue(from) updateUIfromQueueNowPlaying() } } } - Config.SHARE -> { + SHARE -> { viewModel.stopPlayer() binding.ivArt.visibility = View.GONE binding.loadingArt.visibility = View.VISIBLE @@ -211,15 +216,16 @@ class NowPlayingFragment : Fragment() { Queue.clear() Queue.setNowPlaying(track) musicSource.reset() - if (requireContext().isMyServiceRunning(FetchQueue::class.java)) { - requireActivity().stopService( - Intent( - requireContext(), - FetchQueue::class.java - ) - ) - } - viewModel.loadMediaItemFromTrack(track) + viewModel.resetRelated() +// if (requireContext().isMyServiceRunning(FetchQueue::class.java)) { +// requireActivity().stopService( +// Intent( +// requireContext(), +// FetchQueue::class.java +// ) +// ) +// } + viewModel.loadMediaItemFromTrack(track, SHARE) viewModel.videoId.postValue(track.videoId) viewModel.from.postValue(from) updateUIfromQueueNowPlaying() @@ -241,7 +247,7 @@ class NowPlayingFragment : Fragment() { } } - Config.VIDEO_CLICK -> { + VIDEO_CLICK -> { if (viewModel.videoId.value == videoId) { gradientDrawable = viewModel.gradientDrawable.value lyricsBackground = viewModel.lyricsBackground.value @@ -258,15 +264,16 @@ class NowPlayingFragment : Fragment() { binding.tvSongArtist.visibility = View.GONE Queue.getNowPlaying()?.let { musicSource.reset() - if (requireContext().isMyServiceRunning(FetchQueue::class.java)) { - requireActivity().stopService( - Intent( - requireContext(), - FetchQueue::class.java - ) - ) - } - viewModel.loadMediaItemFromTrack(it) + viewModel.resetRelated() +// if (requireContext().isMyServiceRunning(FetchQueue::class.java)) { +// requireActivity().stopService( +// Intent( +// requireContext(), +// FetchQueue::class.java +// ) +// ) +// } + viewModel.loadMediaItemFromTrack(it, VIDEO_CLICK) viewModel.videoId.postValue(it.videoId) viewModel.from.postValue(from) updateUIfromQueueNowPlaying() @@ -287,7 +294,7 @@ class NowPlayingFragment : Fragment() { } } - Config.ALBUM_CLICK -> { + ALBUM_CLICK -> { if (viewModel.videoId.value == videoId) { gradientDrawable = viewModel.gradientDrawable.value lyricsBackground = viewModel.lyricsBackground.value @@ -304,15 +311,16 @@ class NowPlayingFragment : Fragment() { binding.tvSongArtist.visibility = View.GONE Queue.getNowPlaying()?.let { musicSource.reset() - if (requireContext().isMyServiceRunning(FetchQueue::class.java)) { - requireActivity().stopService( - Intent( - requireContext(), - FetchQueue::class.java - ) - ) - } - viewModel.loadMediaItemFromTrack(it) + viewModel.resetRelated() +// if (requireContext().isMyServiceRunning(FetchQueue::class.java)) { +// requireActivity().stopService( +// Intent( +// requireContext(), +// FetchQueue::class.java +// ) +// ) +// } + viewModel.loadMediaItemFromTrack(it, ALBUM_CLICK, index) viewModel.videoId.postValue(it.videoId) viewModel.from.postValue(from) // viewModel.resetLyrics() @@ -351,7 +359,7 @@ class NowPlayingFragment : Fragment() { } } - Config.PLAYLIST_CLICK -> { + PLAYLIST_CLICK -> { if (viewModel.videoId.value == videoId) { gradientDrawable = viewModel.gradientDrawable.value lyricsBackground = viewModel.lyricsBackground.value @@ -367,15 +375,16 @@ class NowPlayingFragment : Fragment() { binding.tvSongArtist.visibility = View.GONE Queue.getNowPlaying()?.let { musicSource.reset() - if (requireContext().isMyServiceRunning(FetchQueue::class.java)) { - requireActivity().stopService( - Intent( - requireContext(), - FetchQueue::class.java - ) - ) - } - viewModel.loadMediaItemFromTrack(it) + viewModel.resetRelated() +// if (requireContext().isMyServiceRunning(FetchQueue::class.java)) { +// requireActivity().stopService( +// Intent( +// requireContext(), +// FetchQueue::class.java +// ) +// ) +// } + viewModel.loadMediaItemFromTrack(it, PLAYLIST_CLICK, index) viewModel.videoId.postValue(it.videoId) viewModel.from.postValue(from) // viewModel.resetLyrics() @@ -414,7 +423,7 @@ class NowPlayingFragment : Fragment() { } } - Config.MINIPLAYER_CLICK -> { + MINIPLAYER_CLICK -> { videoId = viewModel.videoId.value from = viewModel.from.value metadataCurSong = viewModel.metadata.value?.data @@ -456,9 +465,9 @@ class NowPlayingFragment : Fragment() { launch { viewModel.nowPLaying.collectLatest { song -> if (song != null) { + viewModel.getFormat(song.mediaId) Log.i("Now Playing Fragment", "song ${song.mediaMetadata.title}") videoId = viewModel.videoId.value - viewModel.getFormat(song.mediaId) binding.ivArt.visibility = View.GONE binding.loadingArt.visibility = View.VISIBLE Log.d("Check Lyrics", viewModel._lyrics.value?.data.toString()) @@ -624,7 +633,6 @@ class NowPlayingFragment : Fragment() { } val job14 = launch { viewModel.format.collectLatest { format -> - Log.d("Check Format", format.toString()) if (format != null){ binding.uploaderLayout.visibility = View.VISIBLE binding.tvUploader.text = format.uploader @@ -638,91 +646,99 @@ class NowPlayingFragment : Fragment() { } val job15 = launch { viewModel.related.collectLatest { response -> - when (response) { - is Resource.Success -> { - val data = response.data!! - data.add(Queue.getNowPlaying()!!) - val listWithoutDuplicateElements: ArrayList = ArrayList() - for (element in data) { - // Check if element not exist in list, perform add element to list - if (!listWithoutDuplicateElements.contains(element)) { - listWithoutDuplicateElements.add(element) + if (response != null) { + when (response) { + is Resource.Success -> { + val data = response.data!! + data.add(Queue.getNowPlaying()!!) + val listWithoutDuplicateElements: ArrayList = ArrayList() + for (element in data) { + // Check if element not exist in list, perform add element to list + if (!listWithoutDuplicateElements.contains(element)) { + listWithoutDuplicateElements.add(element) + } } + Log.d("Queue", "getRelated: ${listWithoutDuplicateElements.size}") + Queue.clear() + Queue.addAll(listWithoutDuplicateElements) + Log.d("Queue", "getRelated: ${Queue.getQueue().size}") + viewModel.addQueueToPlayer() +// if (!requireContext().isMyServiceRunning(FetchQueue::class.java)) { +// requireActivity().startService( +// Intent( +// requireContext(), +// FetchQueue::class.java +// ) +// ) +// } else { +// requireActivity().stopService( +// Intent( +// requireContext(), +// FetchQueue::class.java +// ) +// ) +// requireActivity().startService( +// Intent( +// requireContext(), +// FetchQueue::class.java +// ) +// ) +// } } - Log.d("Queue", "getRelated: ${listWithoutDuplicateElements.size}") - Queue.clear() - Queue.addAll(listWithoutDuplicateElements) - Log.d("Queue", "getRelated: ${Queue.getQueue().size}") - if (!requireContext().isMyServiceRunning(FetchQueue::class.java)) { - requireActivity().startService( - Intent( - requireContext(), - FetchQueue::class.java - ) - ) - } else { - requireActivity().stopService( - Intent( - requireContext(), - FetchQueue::class.java - ) - ) - requireActivity().startService( - Intent( - requireContext(), - FetchQueue::class.java - ) - ) - } - } - - is Resource.Error -> { - if (response.message != "null") { - Toast.makeText(requireContext(), response.message, Toast.LENGTH_SHORT).show() - Log.d("Error", "${response.message}") - } - } - } - } - } - val job16 = launch { - viewModel.firstTrackAdded.collectLatest { added -> - if (added) { - when(type) { - Config.SONG_CLICK -> { - viewModel.nowPLaying.first()?.let { getRelated(it.mediaId) } - viewModel.changeFirstTrackAddedToFalse() - } - Config.SHARE -> { - viewModel.nowPLaying.first()?.let { getRelated(it.mediaId) } - viewModel.changeFirstTrackAddedToFalse() - } - Config.VIDEO_CLICK -> { -// viewModel.getFormat(it.videoId) - viewModel.nowPLaying.first()?.let { getRelated(it.mediaId) } - viewModel.changeFirstTrackAddedToFalse() - } - Config.ALBUM_CLICK -> { - if (index == null) { - fetchSourceFromQueue(downloaded = downloaded ?: 0) - } else { - fetchSourceFromQueue(index!!, downloaded = downloaded ?: 0) + is Resource.Error -> { + if (response.message != "null") { + Toast.makeText(requireContext(), response.message, Toast.LENGTH_SHORT).show() + Log.d("Error", "${response.message}") } - viewModel.changeFirstTrackAddedToFalse() - } - Config.PLAYLIST_CLICK -> { - if (index == null) { - fetchSourceFromQueue(downloaded = downloaded ?: 0) - } else { - fetchSourceFromQueue(index!!, downloaded = downloaded ?: 0) - } - viewModel.changeFirstTrackAddedToFalse() } } } } } +// val job16 = launch { +// viewModel.firstTrackAdded.collectLatest { added -> +// if (added) { +// when(type) { +// Config.SONG_CLICK -> { +// viewModel.nowPLaying.first()?.let { getRelated(it.mediaId) } +// viewModel.changeFirstTrackAddedToFalse() +// } +// Config.SHARE -> { +// viewModel.nowPLaying.first()?.let { getRelated(it.mediaId) } +// viewModel.changeFirstTrackAddedToFalse() +// } +// Config.VIDEO_CLICK -> { +// +//// viewModel.getFormat(it.videoId) +// viewModel.nowPLaying.first()?.let { getRelated(it.mediaId) } +// viewModel.changeFirstTrackAddedToFalse() +// } +// Config.ALBUM_CLICK -> { +// if (index == null) { +//// fetchSourceFromQueue(downloaded = downloaded ?: 0) +// viewModel.loadPlaylistOrAlbum(downloaded = downloaded ?: 0) +// } else { +//// fetchSourceFromQueue(index!!, downloaded = downloaded ?: 0) +// viewModel.loadPlaylistOrAlbum(downloaded = downloaded ?: 0, index = index) +// } +// +// viewModel.changeFirstTrackAddedToFalse() +// } +// Config.PLAYLIST_CLICK -> { +// if (index == null) { +//// fetchSourceFromQueue(downloaded = downloaded ?: 0) +// viewModel.loadPlaylistOrAlbum(downloaded = downloaded ?: 0) +// } else { +//// fetchSourceFromQueue(index!!, downloaded = downloaded ?: 0) +// viewModel.loadPlaylistOrAlbum(downloaded = downloaded ?: 0, index = index) +// } +// viewModel.changeFirstTrackAddedToFalse() +// } +// } +// } +// } +// } job1.join() job2.join() job3.join() @@ -738,7 +754,6 @@ class NowPlayingFragment : Fragment() { job12.join() job14.join() job15.join() - job16.join() } } binding.btFull.setOnClickListener { @@ -1113,34 +1128,6 @@ class NowPlayingFragment : Fragment() { } } - private fun fetchSourceFromQueue(index: Int? = null, downloaded: Int = 0) { - if (index == null) { - if (!requireContext().isMyServiceRunning(FetchQueue::class.java)) { - requireActivity().startService(Intent(requireContext(), FetchQueue::class.java)) - } else { - requireActivity().stopService(Intent(requireContext(), FetchQueue::class.java)) - requireActivity().startService(Intent(requireContext(), FetchQueue::class.java)) - } - } else { - Log.d("fetchSourceFromQueue", "fetchSourceFromQueue: $index") - val mIntent = Intent(requireContext(), FetchQueue::class.java) - mIntent.putExtra("index", index) - if (downloaded != 0) { - mIntent.putExtra("downloaded", downloaded) - } - if (!requireContext().isMyServiceRunning(FetchQueue::class.java)) { - requireActivity().startService(mIntent) - } else { - requireActivity().stopService(Intent(requireContext(), FetchQueue::class.java)) - requireActivity().startService(mIntent) - } - } - } - - private fun getRelated(videoId: String) { - viewModel.getRelated(videoId) - } - private fun updateUIfromQueueNowPlaying() { Log.w("CHECK NOW PLAYING IN QUEUE", "updateUIfromQueueNowPlaying: ${Queue.getNowPlaying()}") diff --git a/app/src/main/java/com/maxrave/simpmusic/viewModel/SharedViewModel.kt b/app/src/main/java/com/maxrave/simpmusic/viewModel/SharedViewModel.kt index 7b7f54d6..331d0811 100644 --- a/app/src/main/java/com/maxrave/simpmusic/viewModel/SharedViewModel.kt +++ b/app/src/main/java/com/maxrave/simpmusic/viewModel/SharedViewModel.kt @@ -22,8 +22,13 @@ import com.maxrave.kotlinytmusicscraper.models.sponsorblock.SkipSegments import com.maxrave.kotlinytmusicscraper.models.youtube.YouTubeInitialPage import com.maxrave.simpmusic.R import com.maxrave.simpmusic.common.Config +import com.maxrave.simpmusic.common.Config.ALBUM_CLICK +import com.maxrave.simpmusic.common.Config.PLAYLIST_CLICK +import com.maxrave.simpmusic.common.Config.RECOVER_TRACK_QUEUE +import com.maxrave.simpmusic.common.Config.SHARE +import com.maxrave.simpmusic.common.Config.SONG_CLICK +import com.maxrave.simpmusic.common.Config.VIDEO_CLICK import com.maxrave.simpmusic.common.DownloadState -import com.maxrave.simpmusic.common.QUALITY import com.maxrave.simpmusic.common.SELECTED_LANGUAGE import com.maxrave.simpmusic.data.dataStore.DataStoreManager import com.maxrave.simpmusic.data.dataStore.DataStoreManager.Settings.RESTORE_LAST_PLAYED_TRACK_AND_QUEUE_DONE @@ -51,9 +56,11 @@ import com.maxrave.simpmusic.service.SimpleMediaServiceHandler import com.maxrave.simpmusic.service.SimpleMediaState import com.maxrave.simpmusic.service.test.download.DownloadUtils import com.maxrave.simpmusic.service.test.source.MusicSource +import com.maxrave.simpmusic.service.test.source.StateSource import com.maxrave.simpmusic.utils.Resource import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow @@ -75,7 +82,7 @@ class SharedViewModel @Inject constructor(private var dataStoreManager: DataStor @Inject lateinit var downloadUtils: DownloadUtils - var restoreLastPlayedTrackDone: Boolean = false + private var restoreLastPlayedTrackDone: Boolean = false private var _allSongsDB: MutableLiveData> = MutableLiveData() val allSongsDB: LiveData> = _allSongsDB @@ -85,16 +92,15 @@ class SharedViewModel @Inject constructor(private var dataStoreManager: DataStor private var _liked: MutableStateFlow = MutableStateFlow(false) val liked: SharedFlow = _liked.asSharedFlow() - private var _firstTrackAdded: MutableStateFlow = MutableStateFlow(false) - val firstTrackAdded: SharedFlow = _firstTrackAdded.asSharedFlow() + private var loadMusicSourceJob: Job? = null protected val context get() = getApplication() val isServiceRunning = MutableLiveData(false) - private var _related = MutableStateFlow>>(Resource.Error("null")) - val related: StateFlow>> = _related + private var _related = MutableStateFlow>?>(null) + val related: StateFlow>?> = _related val listItag = listOf(171,249,250,251,140,141,256,258) var videoId = MutableLiveData() @@ -189,6 +195,7 @@ class SharedViewModel @Inject constructor(private var dataStoreManager: DataStor // } // recentPosition = runBlocking { (dataStoreManager.recentPosition.first()) } // } + loadMusicSourceJob = Job() viewModelScope.launch { val job1 = launch { simpleMediaServiceHandler.simpleMediaState.collect { mediaState -> @@ -216,6 +223,7 @@ class SharedViewModel @Inject constructor(private var dataStoreManager: DataStor notReady.value = false _duration.value = mediaState.duration _uiState.value = UIState.Ready + getFormat(nowPLaying.first()?.mediaId) } } } @@ -497,10 +505,9 @@ class SharedViewModel @Inject constructor(private var dataStoreManager: DataStor simpleMediaServiceHandler.playMediaItemInMediaSource(index) } @UnstableApi - fun loadMediaItemFromTrack(track: Track) { + fun loadMediaItemFromTrack(track: Track, type: String, index: Int? = null) { quality = runBlocking { dataStoreManager.quality.first() } viewModelScope.launch { - _firstTrackAdded.value = false simpleMediaServiceHandler.clearMediaItems() var uri = "" mainRepository.insertSong(track.toSongEntity()) @@ -515,15 +522,15 @@ class SharedViewModel @Inject constructor(private var dataStoreManager: DataStor mainRepository.updateListenCount(track.videoId) if (songDB.value?.downloadState == DownloadState.STATE_DOWNLOADED) { Log.d("Check Downloaded", "Downloaded") - musicSource.downloadUrl.add(0, "") var thumbUrl = track.thumbnails?.last()?.url!! if (thumbUrl.contains("w120")) { thumbUrl = Regex("([wh])120").replace(thumbUrl, "$1544") } simpleMediaServiceHandler.addMediaItem( MediaItem.Builder() - .setUri(track.videoId.toUri()) + .setUri(track.videoId) .setMediaId(track.videoId) + .setCustomCacheKey(track.videoId) .setMediaMetadata( MediaMetadata.Builder() .setTitle(track.title) @@ -539,23 +546,22 @@ class SharedViewModel @Inject constructor(private var dataStoreManager: DataStor "Check MediaItem Thumbnail", getCurrentMediaItem()?.mediaMetadata?.artworkUri.toString() ) - _firstTrackAdded.value = true musicSource.addFirstMetadata(track) getSavedLyrics(track.videoId, "${track.title} ${track.artists?.firstOrNull()?.name}") } else { - var itag = 0 - when (quality) { - QUALITY.items[0].toString() -> { - itag = QUALITY.itags[0] - } - - QUALITY.items[1].toString() -> { - itag = QUALITY.itags[1] - } - } - mainRepository.getStream(track.videoId, itag).collect{ stream -> - if (stream != null){ - uri = stream +// var itag = 0 +// when (quality) { +// QUALITY.items[0].toString() -> { +// itag = QUALITY.itags[0] +// } +// +// QUALITY.items[1].toString() -> { +// itag = QUALITY.itags[1] +// } +// } +// mainRepository.getStream(track.videoId, itag).collect{ stream -> +// if (stream != null){ +// uri = stream Log.d("Check URI", uri) val artistName: String = track.artists.toListName().connectArtists() var thumbUrl = track.thumbnails?.last()?.url!! @@ -563,10 +569,11 @@ class SharedViewModel @Inject constructor(private var dataStoreManager: DataStor thumbUrl = Regex("([wh])120").replace(thumbUrl, "$1544") } Log.d("Check URI", uri) - musicSource.downloadUrl.add(0, uri.toUri().toString()) simpleMediaServiceHandler.addMediaItem( - MediaItem.Builder().setUri(uri.toUri()) + MediaItem.Builder() + .setUri(track.videoId) .setMediaId(track.videoId) + .setCustomCacheKey(track.videoId) .setMediaMetadata( MediaMetadata.Builder() .setTitle(track.title) @@ -582,7 +589,6 @@ class SharedViewModel @Inject constructor(private var dataStoreManager: DataStor "Check MediaItem Thumbnail", getCurrentMediaItem()?.mediaMetadata?.artworkUri.toString() ) - _firstTrackAdded.value = true musicSource.addFirstMetadata(track) resetLyrics() mainRepository.getLyricsData("${track.title} ${track.artists?.firstOrNull()?.name}").collect { response -> @@ -604,7 +610,54 @@ class SharedViewModel @Inject constructor(private var dataStoreManager: DataStor Log.d("Check lyrics", "Loading") } } +// } +// } + } + } + when (type) { + SONG_CLICK -> { + getRelated(track.videoId) + } + VIDEO_CLICK -> { + getRelated(track.videoId) + } + SHARE -> { + getRelated(track.videoId) + } + PLAYLIST_CLICK -> { + if (index == null) { +// fetchSourceFromQueue(downloaded = downloaded ?: 0) + loadPlaylistOrAlbum() + } else { +// fetchSourceFromQueue(index!!, downloaded = downloaded ?: 0) + loadPlaylistOrAlbum(index = index) + } + } + ALBUM_CLICK -> { + if (index == null) { +// fetchSourceFromQueue(downloaded = downloaded ?: 0) + loadPlaylistOrAlbum() + } else { +// fetchSourceFromQueue(index!!, downloaded = downloaded ?: 0) + loadPlaylistOrAlbum(index = index) + } + } + RECOVER_TRACK_QUEUE -> { + if (getString(RESTORE_LAST_PLAYED_TRACK_AND_QUEUE_DONE) == DataStoreManager.FALSE) { + restoreLastPLayedTrackDone() + from.postValue(from_backup) + simpleMediaServiceHandler.seekTo(recentPosition) + Log.d("Check recentPosition", recentPosition) + songDB.value?.duration?.let { + if (it != "" && it.contains(":")) { + it.split(":").let { split -> + _duration.emit(((split[0].toInt() * 60) + split[1].toInt())*1000.toLong()) + Log.d("Check Duration", _duration.value.toString()) + calculateProgressValues(recentPosition.toLong()) + } + } } + getSaveQueue() } } } @@ -780,10 +833,6 @@ class SharedViewModel @Inject constructor(private var dataStoreManager: DataStor _songTransitions.value = false } - fun changeFirstTrackAddedToFalse() { - _firstTrackAdded.value = false - } - fun resetLyrics() { _lyrics.postValue(Resource.Error("reset")) lyricsFormat.postValue(arrayListOf()) @@ -881,28 +930,7 @@ class SharedViewModel @Inject constructor(private var dataStoreManager: DataStor if (song != null) { Queue.clear() Queue.setNowPlaying(song.toTrack()) - loadMediaItemFromTrack(song.toTrack()) - firstTrackAdded.collectLatest { added -> - if (added) { - if (_nowPlaying.value?.mediaId == mediaId && getString(RESTORE_LAST_PLAYED_TRACK_AND_QUEUE_DONE) == DataStoreManager.FALSE) { - restoreLastPLayedTrackDone() - from.postValue(from_backup) - changeFirstTrackAddedToFalse() - simpleMediaServiceHandler.seekTo(recentPosition) - Log.d("Check recentPosition", recentPosition) - songDB.value?.duration?.let { - if (it != "" && it.contains(":")) { - it.split(":").let { split -> - _duration.emit(((split[0].toInt() * 60) + split[1].toInt())*1000.toLong()) - Log.d("Check Duration", _duration.value.toString()) - calculateProgressValues(recentPosition.toLong()) - } - } - } - getSaveQueue() - } - } - } + loadMediaItemFromTrack(song.toTrack(), RECOVER_TRACK_QUEUE) } } } @@ -974,7 +1002,7 @@ class SharedViewModel @Inject constructor(private var dataStoreManager: DataStor } fun restoreLastPLayedTrackDone() { - putString(DataStoreManager.RESTORE_LAST_PLAYED_TRACK_AND_QUEUE_DONE, TRUE) + putString(RESTORE_LAST_PLAYED_TRACK_AND_QUEUE_DONE, TRUE) } fun removeSaveQueue() { viewModelScope.launch { @@ -1016,6 +1044,45 @@ class SharedViewModel @Inject constructor(private var dataStoreManager: DataStor } } } + + fun addQueueToPlayer() { + loadMusicSourceJob?.cancel() + loadMusicSourceJob = viewModelScope.launch { + musicSource.load() + } + } + + private fun loadPlaylistOrAlbum(index: Int? = null) { + loadMusicSourceJob?.cancel() + loadMusicSourceJob = viewModelScope.launch { + musicSource.load() + musicSource.stateFlow.collect{ state -> + if (state == StateSource.STATE_INITIALIZED) { + when (index) { + null -> { + musicSource.addFirstMediaItem(simpleMediaServiceHandler.getMediaItemWithIndex(0)) + } + -1 -> { + + } + else -> { + musicSource.addFirstMediaItemToIndex(simpleMediaServiceHandler.getMediaItemWithIndex(0), index) + Queue.getNowPlaying().let { song -> + if (song != null) { + musicSource.catalogMetadata.removeAt(0) + musicSource.catalogMetadata.add(index, song) + } + } + } + } + } + } + } + } + + fun resetRelated() { + _related.value = null + } } sealed class UIEvent { data object PlayPause : UIEvent() diff --git a/app/src/main/res/layout/info_fragment.xml b/app/src/main/res/layout/info_fragment.xml index 3d64892f..42577948 100644 --- a/app/src/main/res/layout/info_fragment.xml +++ b/app/src/main/res/layout/info_fragment.xml @@ -198,29 +198,6 @@ android:text="" android:textColorLink="@android:color/white"> - - - - - -