small fixes

This commit is contained in:
reduplicated 2022-11-05 00:32:40 +01:00
parent 415c173524
commit e24dc692d0
5 changed files with 78 additions and 41 deletions

View file

@ -104,7 +104,7 @@ abstract class AbstractPlayerFragment(
throw NotImplementedError() throw NotImplementedError()
} }
open fun onTimestamp(timestamp: EpisodeSkip.SkipStamp) { open fun onTimestamp(timestamp: EpisodeSkip.SkipStamp?) {
} }

View file

@ -117,7 +117,7 @@ class CS3IPlayer : IPlayer {
private var playerUpdated: ((Any?) -> Unit)? = null private var playerUpdated: ((Any?) -> Unit)? = null
private var embeddedSubtitlesFetched: ((List<SubtitleData>) -> Unit)? = null private var embeddedSubtitlesFetched: ((List<SubtitleData>) -> Unit)? = null
private var onTracksInfoChanged: (() -> 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 private var onTimestampSkipped: ((EpisodeSkip.SkipStamp) -> Unit)? = null
override fun releaseCallbacks() { override fun releaseCallbacks() {
@ -150,7 +150,7 @@ class CS3IPlayer : IPlayer {
subtitlesUpdates: (() -> Unit)?, subtitlesUpdates: (() -> Unit)?,
embeddedSubtitlesFetched: ((List<SubtitleData>) -> Unit)?, embeddedSubtitlesFetched: ((List<SubtitleData>) -> Unit)?,
onTracksInfoChanged: (() -> Unit)?, onTracksInfoChanged: (() -> Unit)?,
onTimestampInvoked: ((EpisodeSkip.SkipStamp) -> Unit)?, onTimestampInvoked: ((EpisodeSkip.SkipStamp?) -> Unit)?,
onTimestampSkipped: ((EpisodeSkip.SkipStamp) -> Unit)?, onTimestampSkipped: ((EpisodeSkip.SkipStamp) -> Unit)?,
) { ) {
this.playerUpdated = playerUpdated this.playerUpdated = playerUpdated
@ -731,7 +731,7 @@ class CS3IPlayer : IPlayer {
source source
} }
println("PLAYBACK POS $playbackPosition") //println("PLAYBACK POS $playbackPosition")
return exoPlayerBuilder.build().apply { return exoPlayerBuilder.build().apply {
setPlayWhenReady(playWhenReady) setPlayWhenReady(playWhenReady)
seekTo(currentWindow, playbackPosition) seekTo(currentWindow, playbackPosition)
@ -747,8 +747,22 @@ class CS3IPlayer : IPlayer {
} }
} }
fun updatedTime() { private fun getCurrentTimestamp(writePosition : Long? = null): EpisodeSkip.SkipStamp? {
val position = exoPlayer?.currentPosition 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 val duration = exoPlayer?.contentDuration
if (duration != null && position != null) { if (duration != null && position != null) {
playerPositionChanged?.invoke(Pair(position, duration)) playerPositionChanged?.invoke(Pair(position, duration))
@ -760,12 +774,12 @@ class CS3IPlayer : IPlayer {
} }
override fun seekTo(time: Long) { override fun seekTo(time: Long) {
updatedTime() updatedTime(time)
exoPlayer?.seekTo(time) exoPlayer?.seekTo(time)
} }
private fun ExoPlayer.seekTime(time: Long) { private fun ExoPlayer.seekTime(time: Long) {
updatedTime() updatedTime(currentPosition + time)
seekTo(currentPosition + time) seekTo(currentPosition + time)
} }
@ -803,18 +817,13 @@ class CS3IPlayer : IPlayer {
CSPlayerEvent.PrevEpisode -> prevEpisode?.invoke() CSPlayerEvent.PrevEpisode -> prevEpisode?.invoke()
CSPlayerEvent.SkipCurrentChapter -> { CSPlayerEvent.SkipCurrentChapter -> {
//val dur = this@CS3IPlayer.getDuration() ?: return@apply //val dur = this@CS3IPlayer.getDuration() ?: return@apply
val pos = this@CS3IPlayer.getPosition() ?: return@apply getCurrentTimestamp()?.let { lastTimeStamp ->
for (lastTimeStamp in lastTimeStamps) { if (lastTimeStamp.skipToNextEpisode) {
if (lastTimeStamp.startMs <= pos && pos < lastTimeStamp.endMs) { handleEvent(CSPlayerEvent.NextEpisode)
if (lastTimeStamp.skipToNextEpisode) { } else {
handleEvent(CSPlayerEvent.NextEpisode) seekTo(lastTimeStamp.endMs + 1L)
} else {
seekTo(lastTimeStamp.endMs)
}
onTimestampSkipped?.invoke(lastTimeStamp)
break
} }
onTimestampSkipped?.invoke(lastTimeStamp)
} }
} }
} }
@ -1039,16 +1048,18 @@ class CS3IPlayer : IPlayer {
override fun addTimeStamps(timeStamps: List<EpisodeSkip.SkipStamp>) { override fun addTimeStamps(timeStamps: List<EpisodeSkip.SkipStamp>) {
lastTimeStamps = timeStamps lastTimeStamps = timeStamps
timeStamps.forEach { timestamp -> timeStamps.forEach { timestamp ->
exoPlayer?.createMessage { _, payload -> exoPlayer?.createMessage { _, _ ->
if (payload is EpisodeSkip.SkipStamp) // this should always be true updatedTime()
onTimestampInvoked?.invoke(payload) //if (payload is EpisodeSkip.SkipStamp) // this should always be true
// onTimestampInvoked?.invoke(payload)
} }
?.setLooper(Looper.getMainLooper()) ?.setLooper(Looper.getMainLooper())
?.setPosition(timestamp.startMs) ?.setPosition(timestamp.startMs)
?.setPayload(timestamp) //?.setPayload(timestamp)
?.setDeleteAfterDelivery(false) ?.setDeleteAfterDelivery(false)
?.send() ?.send()
} }
updatedTime()
} }
fun onRenderFirst() { fun onRenderFirst() {

View file

@ -646,8 +646,8 @@ class GeneratorPlayer : FullScreenPlayer() {
true, true,
{}) { {}) {
settingsManager.edit().putString( settingsManager.edit().putString(
ctx.getString(R.string.subtitles_encoding_key), prefValues[it] ctx.getString(R.string.subtitles_encoding_key), prefValues[it]
).apply() ).apply()
updateForcedEncoding(ctx) updateForcedEncoding(ctx)
dismiss() dismiss()
@ -869,7 +869,7 @@ class GeneratorPlayer : FullScreenPlayer() {
if ((currentMeta as? ResultEpisode)?.tvType == TvType.NSFW) return if ((currentMeta as? ResultEpisode)?.tvType == TvType.NSFW) return
val (position, duration) = posDur 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) { if (!hasRequestedStamps) {
hasRequestedStamps = true hasRequestedStamps = true
viewModel.loadStamps(duration) viewModel.loadStamps(duration)
@ -1151,8 +1151,13 @@ class GeneratorPlayer : FullScreenPlayer() {
var timestampShowState = false var timestampShowState = false
var skipAnimator: ValueAnimator? = null
var skipIndex = 0
private fun displayTimeStamp(show: Boolean) { private fun displayTimeStamp(show: Boolean) {
if(timestampShowState == show) return if (timestampShowState == show) return
skipIndex++
println("displayTimeStamp = $show")
timestampShowState = show timestampShowState = show
skip_chapter_button?.apply { skip_chapter_button?.apply {
val showWidth = 170.toPx val showWidth = 170.toPx
@ -1163,14 +1168,14 @@ class GeneratorPlayer : FullScreenPlayer() {
val to = if (show) showWidth else noShowWidth val to = if (show) showWidth else noShowWidth
val from = if (!show) showWidth else noShowWidth val from = if (!show) showWidth else noShowWidth
skipAnimator?.cancel()
isVisible = true isVisible = true
// just in case // just in case
val lay = layoutParams val lay = layoutParams
lay.width = from lay.width = from
layoutParams = lay layoutParams = lay
skipAnimator = ValueAnimator.ofInt(
ValueAnimator.ofInt(
from, to from, to
).apply { ).apply {
addListener(onEnd = { addListener(onEnd = {
@ -1192,12 +1197,18 @@ class GeneratorPlayer : FullScreenPlayer() {
displayTimeStamp(false) displayTimeStamp(false)
} }
override fun onTimestamp(timestamp: EpisodeSkip.SkipStamp) { override fun onTimestamp(timestamp: EpisodeSkip.SkipStamp?) {
skip_chapter_button.setText(timestamp.uiText) if (timestamp != null) {
displayTimeStamp(true) skip_chapter_button.setText(timestamp.uiText)
skip_chapter_button?.handler?.postDelayed({ displayTimeStamp(true)
val currentIndex = skipIndex
skip_chapter_button?.handler?.postDelayed({
if (skipIndex == currentIndex)
displayTimeStamp(false)
}, 6000)
} else {
displayTimeStamp(false) displayTimeStamp(false)
}, 6000) }
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

View file

@ -126,7 +126,7 @@ interface IPlayer {
subtitlesUpdates: (() -> Unit)? = null, // callback from player to inform that subtitles have updated in some way subtitlesUpdates: (() -> Unit)? = null, // callback from player to inform that subtitles have updated in some way
embeddedSubtitlesFetched: ((List<SubtitleData>) -> Unit)? = null, // callback from player to give all embedded subtitles embeddedSubtitlesFetched: ((List<SubtitleData>) -> Unit)? = null, // callback from player to give all embedded subtitles
onTracksInfoChanged: (() -> Unit)? = null, // Callback when tracks are changed, used for UI changes 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) 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)
) )

View file

@ -8,6 +8,7 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.getMalId
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.ui.result.ResultEpisode import com.lagradost.cloudstream3.ui.result.ResultEpisode
import com.lagradost.cloudstream3.ui.result.txt import com.lagradost.cloudstream3.ui.result.txt
import java.lang.Long.min
object EpisodeSkip { object EpisodeSkip {
private const val TAG = "EpisodeSkip" private const val TAG = "EpisodeSkip"
@ -37,14 +38,14 @@ object EpisodeSkip {
private val cachedStamps = HashMap<Int, List<SkipStamp>>() private val cachedStamps = HashMap<Int, List<SkipStamp>>()
private fun shouldSkipToNextEpisode(endMs: Long, episodeDurationMs: Long): Boolean { 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( suspend fun getStamps(
data: LoadResponse, data: LoadResponse,
episode: ResultEpisode, episode: ResultEpisode,
episodeDurationMs: Long, episodeDurationMs: Long,
hasNextEpisode : Boolean, hasNextEpisode: Boolean,
): List<SkipStamp> { ): List<SkipStamp> {
cachedStamps[episode.id]?.let { list -> cachedStamps[episode.id]?.let { list ->
return list return list
@ -55,7 +56,14 @@ object EpisodeSkip {
if (data is AnimeLoadResponse && (data.type == TvType.Anime || data.type == TvType.OVA)) { if (data is AnimeLoadResponse && (data.type == TvType.Anime || data.type == TvType.OVA)) {
data.getMalId()?.toIntOrNull()?.let { malId -> 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) { val skipType = when (stamp.skipType) {
"op" -> SkipType.Opening "op" -> SkipType.Opening
"ed" -> SkipType.Ending "ed" -> SkipType.Ending
@ -68,7 +76,10 @@ object EpisodeSkip {
val start = (stamp.interval.startTime * 1000.0).toLong() val start = (stamp.interval.startTime * 1000.0).toLong()
SkipStamp( SkipStamp(
type = skipType, type = skipType,
skipToNextEpisode = hasNextEpisode && shouldSkipToNextEpisode(end, episodeDurationMs), skipToNextEpisode = hasNextEpisode && shouldSkipToNextEpisode(
end,
dur
),
startMs = start, startMs = start,
endMs = end endMs = end
) )
@ -87,7 +98,11 @@ object EpisodeSkip {
// the following is GPLv3 code https://github.com/saikou-app/saikou/blob/main/LICENSE.md // the following is GPLv3 code https://github.com/saikou-app/saikou/blob/main/LICENSE.md
object AniSkip { object AniSkip {
private const val TAG = "AniSkip" private const val TAG = "AniSkip"
suspend fun getResult(malId: Int, episodeNumber: Int, episodeLength: Long): List<Stamp>? { suspend fun getResult(
malId: Int,
episodeNumber: Int,
episodeLength: Long
): Pair<Long, List<Stamp>>? {
return try { return try {
val url = 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}" "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 a = app.get(url)
val res = a.parsed<AniSkipResponse>() val res = a.parsed<AniSkipResponse>()
Log.i(TAG, "Found ${res.found} with ${res.results?.size} results") 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) { } catch (t: Throwable) {
Log.i(TAG, "error = ${t.message}") Log.i(TAG, "error = ${t.message}")
logError(t) logError(t)