From e24dc692d0e757bba339d09852d711d130210525 Mon Sep 17 00:00:00 2001 From: reduplicated <110570621+reduplicated@users.noreply.github.com> Date: Sat, 5 Nov 2022 00:32:40 +0100 Subject: [PATCH] small fixes --- .../ui/player/AbstractPlayerFragment.kt | 2 +- .../cloudstream3/ui/player/CS3IPlayer.kt | 55 +++++++++++-------- .../cloudstream3/ui/player/GeneratorPlayer.kt | 33 +++++++---- .../cloudstream3/ui/player/IPlayer.kt | 2 +- .../lagradost/cloudstream3/utils/AniSkip.kt | 27 +++++++-- 5 files changed, 78 insertions(+), 41 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt index 5037b37d..21047db3 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt @@ -104,7 +104,7 @@ abstract class AbstractPlayerFragment( throw NotImplementedError() } - open fun onTimestamp(timestamp: EpisodeSkip.SkipStamp) { + open fun onTimestamp(timestamp: EpisodeSkip.SkipStamp?) { } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt index d132406c..8eda6e30 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt @@ -117,7 +117,7 @@ class CS3IPlayer : IPlayer { private var playerUpdated: ((Any?) -> Unit)? = null private var embeddedSubtitlesFetched: ((List) -> Unit)? = null private var onTracksInfoChanged: (() -> Unit)? = null - private var onTimestampInvoked: ((EpisodeSkip.SkipStamp) -> Unit)? = null + private var onTimestampInvoked: ((EpisodeSkip.SkipStamp?) -> Unit)? = null private var onTimestampSkipped: ((EpisodeSkip.SkipStamp) -> Unit)? = null override fun releaseCallbacks() { @@ -150,7 +150,7 @@ class CS3IPlayer : IPlayer { subtitlesUpdates: (() -> Unit)?, embeddedSubtitlesFetched: ((List) -> Unit)?, onTracksInfoChanged: (() -> Unit)?, - onTimestampInvoked: ((EpisodeSkip.SkipStamp) -> Unit)?, + onTimestampInvoked: ((EpisodeSkip.SkipStamp?) -> Unit)?, onTimestampSkipped: ((EpisodeSkip.SkipStamp) -> Unit)?, ) { this.playerUpdated = playerUpdated @@ -731,7 +731,7 @@ class CS3IPlayer : IPlayer { source } - println("PLAYBACK POS $playbackPosition") + //println("PLAYBACK POS $playbackPosition") return exoPlayerBuilder.build().apply { setPlayWhenReady(playWhenReady) seekTo(currentWindow, playbackPosition) @@ -747,8 +747,22 @@ class CS3IPlayer : IPlayer { } } - fun updatedTime() { - val position = exoPlayer?.currentPosition + private fun getCurrentTimestamp(writePosition : Long? = null): EpisodeSkip.SkipStamp? { + val position = writePosition ?: this@CS3IPlayer.getPosition() ?: return null + for (lastTimeStamp in lastTimeStamps) { + if (lastTimeStamp.startMs <= position && position < lastTimeStamp.endMs) { + return lastTimeStamp + } + } + return null + } + + fun updatedTime(writePosition : Long? = null) { + getCurrentTimestamp(writePosition)?.let { timestamp -> + onTimestampInvoked?.invoke(timestamp) + } + + val position = writePosition ?: exoPlayer?.currentPosition val duration = exoPlayer?.contentDuration if (duration != null && position != null) { playerPositionChanged?.invoke(Pair(position, duration)) @@ -760,12 +774,12 @@ class CS3IPlayer : IPlayer { } override fun seekTo(time: Long) { - updatedTime() + updatedTime(time) exoPlayer?.seekTo(time) } private fun ExoPlayer.seekTime(time: Long) { - updatedTime() + updatedTime(currentPosition + time) seekTo(currentPosition + time) } @@ -803,18 +817,13 @@ class CS3IPlayer : IPlayer { CSPlayerEvent.PrevEpisode -> prevEpisode?.invoke() CSPlayerEvent.SkipCurrentChapter -> { //val dur = this@CS3IPlayer.getDuration() ?: return@apply - val pos = this@CS3IPlayer.getPosition() ?: return@apply - for (lastTimeStamp in lastTimeStamps) { - if (lastTimeStamp.startMs <= pos && pos < lastTimeStamp.endMs) { - if (lastTimeStamp.skipToNextEpisode) { - handleEvent(CSPlayerEvent.NextEpisode) - } else { - seekTo(lastTimeStamp.endMs) - } - - onTimestampSkipped?.invoke(lastTimeStamp) - break + getCurrentTimestamp()?.let { lastTimeStamp -> + if (lastTimeStamp.skipToNextEpisode) { + handleEvent(CSPlayerEvent.NextEpisode) + } else { + seekTo(lastTimeStamp.endMs + 1L) } + onTimestampSkipped?.invoke(lastTimeStamp) } } } @@ -1039,16 +1048,18 @@ class CS3IPlayer : IPlayer { override fun addTimeStamps(timeStamps: List) { lastTimeStamps = timeStamps timeStamps.forEach { timestamp -> - exoPlayer?.createMessage { _, payload -> - if (payload is EpisodeSkip.SkipStamp) // this should always be true - onTimestampInvoked?.invoke(payload) + exoPlayer?.createMessage { _, _ -> + updatedTime() + //if (payload is EpisodeSkip.SkipStamp) // this should always be true + // onTimestampInvoked?.invoke(payload) } ?.setLooper(Looper.getMainLooper()) ?.setPosition(timestamp.startMs) - ?.setPayload(timestamp) + //?.setPayload(timestamp) ?.setDeleteAfterDelivery(false) ?.send() } + updatedTime() } fun onRenderFirst() { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt index 25925871..e1f1d99d 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt @@ -646,8 +646,8 @@ class GeneratorPlayer : FullScreenPlayer() { true, {}) { settingsManager.edit().putString( - ctx.getString(R.string.subtitles_encoding_key), prefValues[it] - ).apply() + ctx.getString(R.string.subtitles_encoding_key), prefValues[it] + ).apply() updateForcedEncoding(ctx) dismiss() @@ -869,7 +869,7 @@ class GeneratorPlayer : FullScreenPlayer() { if ((currentMeta as? ResultEpisode)?.tvType == TvType.NSFW) return val (position, duration) = posDur - if (duration == 0L) return // idk how you achieved this, but div by zero crash + if (duration <= 0L) return // idk how you achieved this, but div by zero crash if (!hasRequestedStamps) { hasRequestedStamps = true viewModel.loadStamps(duration) @@ -1151,8 +1151,13 @@ class GeneratorPlayer : FullScreenPlayer() { var timestampShowState = false + var skipAnimator: ValueAnimator? = null + var skipIndex = 0 + private fun displayTimeStamp(show: Boolean) { - if(timestampShowState == show) return + if (timestampShowState == show) return + skipIndex++ + println("displayTimeStamp = $show") timestampShowState = show skip_chapter_button?.apply { val showWidth = 170.toPx @@ -1163,14 +1168,14 @@ class GeneratorPlayer : FullScreenPlayer() { val to = if (show) showWidth else noShowWidth val from = if (!show) showWidth else noShowWidth + skipAnimator?.cancel() isVisible = true // just in case val lay = layoutParams lay.width = from layoutParams = lay - - ValueAnimator.ofInt( + skipAnimator = ValueAnimator.ofInt( from, to ).apply { addListener(onEnd = { @@ -1192,12 +1197,18 @@ class GeneratorPlayer : FullScreenPlayer() { displayTimeStamp(false) } - override fun onTimestamp(timestamp: EpisodeSkip.SkipStamp) { - skip_chapter_button.setText(timestamp.uiText) - displayTimeStamp(true) - skip_chapter_button?.handler?.postDelayed({ + override fun onTimestamp(timestamp: EpisodeSkip.SkipStamp?) { + if (timestamp != null) { + skip_chapter_button.setText(timestamp.uiText) + displayTimeStamp(true) + val currentIndex = skipIndex + skip_chapter_button?.handler?.postDelayed({ + if (skipIndex == currentIndex) + displayTimeStamp(false) + }, 6000) + } else { displayTimeStamp(false) - }, 6000) + } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/IPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/IPlayer.kt index 6c1f1108..ba5a4a85 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/IPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/IPlayer.kt @@ -126,7 +126,7 @@ interface IPlayer { subtitlesUpdates: (() -> Unit)? = null, // callback from player to inform that subtitles have updated in some way embeddedSubtitlesFetched: ((List) -> Unit)? = null, // callback from player to give all embedded subtitles onTracksInfoChanged: (() -> Unit)? = null, // Callback when tracks are changed, used for UI changes - onTimestampInvoked: ((EpisodeSkip.SkipStamp) -> Unit)? = null, // Callback when timestamps appear + onTimestampInvoked: ((EpisodeSkip.SkipStamp?) -> Unit)? = null, // Callback when timestamps appear, null when it should disappear onTimestampSkipped: ((EpisodeSkip.SkipStamp) -> Unit)? = null, // callback for when a chapter is skipped, aka when event is handled (or for future use when skip automatically ads/sponsor) ) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/AniSkip.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/AniSkip.kt index 07233871..e9b69c5b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/AniSkip.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/AniSkip.kt @@ -8,6 +8,7 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.getMalId import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.ui.result.ResultEpisode import com.lagradost.cloudstream3.ui.result.txt +import java.lang.Long.min object EpisodeSkip { private const val TAG = "EpisodeSkip" @@ -37,14 +38,14 @@ object EpisodeSkip { private val cachedStamps = HashMap>() private fun shouldSkipToNextEpisode(endMs: Long, episodeDurationMs: Long): Boolean { - return episodeDurationMs - endMs < 12_000L + return episodeDurationMs - endMs < 20_000L // some might have outro that we don't care about tbh } suspend fun getStamps( data: LoadResponse, episode: ResultEpisode, episodeDurationMs: Long, - hasNextEpisode : Boolean, + hasNextEpisode: Boolean, ): List { cachedStamps[episode.id]?.let { list -> return list @@ -55,7 +56,14 @@ object EpisodeSkip { if (data is AnimeLoadResponse && (data.type == TvType.Anime || data.type == TvType.OVA)) { data.getMalId()?.toIntOrNull()?.let { malId -> - AniSkip.getResult(malId, episode.episode, episodeDurationMs)?.mapNotNull { stamp -> + val (resultLength, stamps) = AniSkip.getResult( + malId, + episode.episode, + episodeDurationMs + ) ?: return@let null + // because it also returns an expected episode length we use that just in case it is mismatched with like 2s next episode will still work + val dur = min(episodeDurationMs, resultLength) + stamps.mapNotNull { stamp -> val skipType = when (stamp.skipType) { "op" -> SkipType.Opening "ed" -> SkipType.Ending @@ -68,7 +76,10 @@ object EpisodeSkip { val start = (stamp.interval.startTime * 1000.0).toLong() SkipStamp( type = skipType, - skipToNextEpisode = hasNextEpisode && shouldSkipToNextEpisode(end, episodeDurationMs), + skipToNextEpisode = hasNextEpisode && shouldSkipToNextEpisode( + end, + dur + ), startMs = start, endMs = end ) @@ -87,7 +98,11 @@ object EpisodeSkip { // the following is GPLv3 code https://github.com/saikou-app/saikou/blob/main/LICENSE.md object AniSkip { private const val TAG = "AniSkip" - suspend fun getResult(malId: Int, episodeNumber: Int, episodeLength: Long): List? { + suspend fun getResult( + malId: Int, + episodeNumber: Int, + episodeLength: Long + ): Pair>? { return try { val url = "https://api.aniskip.com/v2/skip-times/$malId/$episodeNumber?types[]=ed&types[]=mixed-ed&types[]=mixed-op&types[]=op&types[]=recap&episodeLength=${episodeLength / 1000L}" @@ -96,7 +111,7 @@ object AniSkip { val a = app.get(url) val res = a.parsed() Log.i(TAG, "Found ${res.found} with ${res.results?.size} results") - if (res.found) res.results else null + if (res.found && !res.results.isNullOrEmpty()) (res.results[0].episodeLength * 1000).toLong() to res.results else null } catch (t: Throwable) { Log.i(TAG, "error = ${t.message}") logError(t)