diff --git a/app/phone/src/main/java/dev/jdtech/jellyfin/chromecast/CastOptionProvider.kt b/app/phone/src/main/java/dev/jdtech/jellyfin/chromecast/CastOptionProvider.kt deleted file mode 100644 index cd1f5ddbc6..0000000000 --- a/app/phone/src/main/java/dev/jdtech/jellyfin/chromecast/CastOptionProvider.kt +++ /dev/null @@ -1,34 +0,0 @@ -package dev.jdtech.jellyfin.chromecast - -import android.content.Context -import com.google.android.gms.cast.framework.CastOptions -import com.google.android.gms.cast.framework.OptionsProvider -import com.google.android.gms.cast.framework.SessionProvider -import com.google.android.gms.cast.framework.media.CastMediaOptions -import com.google.android.gms.cast.framework.media.NotificationOptions - - -class CastOptionsProvider : OptionsProvider { - - override fun getCastOptions(context: Context): CastOptions { - - val notificationOptions = NotificationOptions.Builder() - .setTargetActivityClassName(ExpandedControlsActivity::class.java.name) - .build() - - val mediaOptions = CastMediaOptions.Builder() - .setNotificationOptions(notificationOptions) - .setExpandedControllerActivityClassName(ExpandedControlsActivity::class.java.name) - .build() - - return CastOptions.Builder() - .setReceiverApplicationId("49B291C0") - .setCastMediaOptions(mediaOptions) - .build() - // .setSupportedNamespaces(supportedNamespaces) - } - - override fun getAdditionalSessionProviders(p0: Context): MutableList? { - return null - } -} \ No newline at end of file diff --git a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/EpisodeBottomSheetFragment.kt b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/EpisodeBottomSheetFragment.kt index a69f000289..fdf2018c0b 100644 --- a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/EpisodeBottomSheetFragment.kt +++ b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/EpisodeBottomSheetFragment.kt @@ -415,7 +415,7 @@ class EpisodeBottomSheetFragment : BottomSheetDialogFragment() { //remoteMediaClient.mediaStatus } if (session != null) { - if(session.remoteMediaClient?.isPaused() == true){ + if(session.remoteMediaClient?.isPaused == true){ print("yeet") } } diff --git a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MediaFragment.kt b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MediaFragment.kt index 649ad9409a..2cda75fe39 100644 --- a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MediaFragment.kt +++ b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MediaFragment.kt @@ -18,7 +18,6 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.navigation.fragment.findNavController -import com.google.android.gms.cast.framework.CastButtonFactory import dagger.hilt.android.AndroidEntryPoint import dev.jdtech.jellyfin.adapters.CollectionListAdapter import dev.jdtech.jellyfin.databinding.FragmentMediaBinding diff --git a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MovieFragment.kt b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MovieFragment.kt index eaf65e145b..602d0c660e 100644 --- a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MovieFragment.kt +++ b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MovieFragment.kt @@ -21,7 +21,6 @@ import androidx.navigation.fragment.navArgs import com.google.android.gms.cast.framework.CastContext import com.google.android.gms.cast.framework.CastState import com.google.android.gms.cast.framework.media.RemoteMediaClient -import com.google.android.material.R as MaterialR import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.hilt.android.AndroidEntryPoint import dev.jdtech.jellyfin.AppPreferences diff --git a/app/phone/src/main/res/layout/activity_main.xml b/app/phone/src/main/res/layout/activity_main.xml index 3fbf2901b0..2c94216d4e 100644 --- a/app/phone/src/main/res/layout/activity_main.xml +++ b/app/phone/src/main/res/layout/activity_main.xml @@ -4,7 +4,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - ) : PlayerItemState() - private fun loadRemoteMedia( + private suspend fun loadRemoteMedia( position: Int, mCastSession: CastSession, mediaInfo: MediaInfo, - streamUrl: String, item: PlayerItem, episode: BaseItemDto ) { - if (mCastSession == null) { - return - } + val remoteMediaClient = mCastSession.remoteMediaClient ?: return var previousSubtitleTrackIds: LongArray? = null var newIndex = -1 var subtitleIndex = -1 var newAudioIndex = 1 + //startProgressUpdates(item) + val callback = object : RemoteMediaClient.Callback() { + override fun onPreloadStatusUpdated() { + print("test") + } + + override fun onQueueStatusUpdated() { + print("test") + } + override fun onStatusUpdated() { val mediaStatus = remoteMediaClient.mediaStatus + + + + if (mediaStatus?.playerState == MediaStatus.PLAYER_STATE_IDLE) { + print("test") + } + // Check if playback is stopped by user + if (mediaStatus?.playerState == MediaStatus.PLAYER_STATE_PAUSED || + mediaStatus?.playerState == MediaStatus.PLAYER_STATE_LOADING + ) { + print("test") + } + + val activeSubtitleTrackIds = mediaStatus?.activeTrackIds val subtitlesOffset = - mediaInfo?.mediaTracks!!.size - item.externalSubtitles.size - val mediaInfo = mediaStatus?.mediaInfo - val externalSubtitleCount = mediaInfo?.textTrackStyle?.describeContents() + mediaInfo.mediaTracks!!.size - item.externalSubtitles.size + + if (mediaStatus?.playerState == MediaStatus.PLAYER_STATE_BUFFERING) { + viewModelScope.launch { + startProgressUpdates(item, mediaStatus.streamPosition.toInt()) + } + } + + if (mediaStatus != null) { - if (previousSubtitleTrackIds != mediaStatus.activeTrackIds && previousSubtitleTrackIds != null) { + if (!previousSubtitleTrackIds.contentEquals(mediaStatus.activeTrackIds) && previousSubtitleTrackIds != null) { if (activeSubtitleTrackIds != null) { if (activeSubtitleTrackIds.isNotEmpty()) { - newIndex = (mediaStatus.activeTrackIds!!.get(0)).toInt() if (newIndex < subtitlesOffset) { @@ -257,7 +287,9 @@ class PlayerViewModel @Inject internal constructor( .setAutoplay(true) .setCurrentTime(mediaStatus.streamPosition.toInt().toLong()) .build() + ) + } @@ -282,10 +314,24 @@ class PlayerViewModel @Inject internal constructor( ) - val mediaStatus = remoteMediaClient.mediaStatus - val activeMediaTracks = mediaStatus?.activeTrackIds + + } + + private suspend fun startProgressUpdates(item: PlayerItem, position: Int) { + jellyfinApi.playStateApi.reportPlaybackProgress( + data = PlaybackProgressInfo( + canSeek = true, + itemId = item.itemId, + isMuted = false, + isPaused = false, + playMethod = PlayMethod.TRANSCODE, + repeatMode = RepeatMode.REPEAT_NONE, + mediaSourceId = item.mediaSourceId, + positionTicks = position.toLong() * 10000 + ) + ) } private fun buildMediaInfo( @@ -303,10 +349,10 @@ class PlayerViewModel @Inject internal constructor( } if (thumbnailUrl != null) { - var thumbnailImage = WebImage(Uri.parse(thumbnailUrl)) + val thumbnailImage = WebImage(Uri.parse(thumbnailUrl)) mediaMetadata.addImage(thumbnailImage) } else { - var thumbnailImage = WebImage( + val thumbnailImage = WebImage( Uri.parse( jellyfinApi.api.imageApi.getItemImageUrl( item.itemId, @@ -322,7 +368,6 @@ class PlayerViewModel @Inject internal constructor( val mediaSubtitles = episode.mediaStreams?.mapIndexed { index, externalSubtitle -> MediaTrack.Builder(index.toLong(), MediaTrack.TYPE_TEXT) .setName(externalSubtitle.displayTitle + " " + externalSubtitle.type) - //.setContentId(jellyfinApi.api.createUrl("/videos/" + item.itemId + "/master.m3u8?DeviceId=" + jellyfinApi.api.deviceInfo.id + "&MediaSourceId=" + item.mediaSourceId + "&VideoCodec=h264,h264&AudioCodec=mp3&AudioStreamIndex=1&SubtitleStreamIndex=" + index + "&VideoBitrate=119872000&AudioBitrate=128000&AudioSampleRate=44100&MaxFramerate=23.976025&PlaySessionId=" + (Math.random() * 10000).toInt() + "&api_key=" + jellyfinApi.api.accessToken + "&SubtitleMethod=Encode&RequireAvc=false&SegmentContainer=ts&BreakOnNonKeyFrames=False&h264-level=40&h264-videobitdepth=8&h264-profile=high&h264-audiochannels=2&aac-profile=lc&TranscodeReasons=SubtitleCodecNotSupported") .setContentType("text/vtt") .setLanguage(externalSubtitle.language) .build() @@ -352,7 +397,7 @@ class PlayerViewModel @Inject internal constructor( if (session != null) { val mediaInfo = buildMediaInfo(streamUrl, item, episode) - loadRemoteMedia(0, session, mediaInfo, streamUrl, item, episode) + loadRemoteMedia(0, session, mediaInfo, item, episode) } } catch (e: Exception) {