add crunchy intro metadata to parser and update the skip intro function, closes #66

This commit is contained in:
Jannik 2022-10-28 22:57:42 +02:00
parent 6624e71228
commit 71d5c58653
Signed by: Seil0
GPG Key ID: E8459F3723C52C24
4 changed files with 58 additions and 11 deletions

View File

@ -34,6 +34,7 @@ import io.ktor.http.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.coroutines.*
import kotlinx.serialization.SerializationException
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.buildJsonObject
@ -52,6 +53,7 @@ object Crunchyroll {
}
}
private const val baseUrl = "https://beta-api.crunchyroll.com"
private const val staticUrl = "https://static.crunchyroll.com"
private const val basicApiTokenUrl = "https://gitlab.com/-/snippets/2274956/raw/main/snippetfile1.txt"
private var basicApiToken: String = ""
@ -164,12 +166,15 @@ object Crunchyroll {
}
}
/**
* Send a HTTP GET request with [params] to the [endpoint] at [url], if url is empty use baseUrl
*/
private suspend inline fun <reified T> requestGet(
endpoint: String,
params: List<Pair<String, Any?>> = listOf(),
url: String = ""
): T {
val path = url.ifEmpty { "$baseUrl$endpoint" }
val path = url.ifEmpty { baseUrl }.plus(endpoint)
return request(path, HttpMethod.Get, params)
}
@ -583,6 +588,23 @@ object Crunchyroll {
}
}
/**
* Get the intro meta data including start, end and duration of the intro.
*
* @param episodeId A episode ID as strings.
*/
suspend fun datalabIntro(episodeId: String): DatalabIntro {
val datalabIntroEndpoint = "/datalab-intro-v2/$episodeId.json"
return try {
val response: HttpResponse = requestGet(datalabIntroEndpoint, url = staticUrl)
Json.decodeFromString(response.bodyAsText())
} catch (ex: SerializationException) {
Log.e(TAG, "SerializationException in datalabIntro(). EpisodeId=$episodeId", ex)
NoneDatalabIntro
}
}
/**
* Get similar media for a show/movie.
*

View File

@ -347,6 +347,22 @@ data class PlayheadObject(
@SerialName("last_modified") val lastModified: String,
)
/**
* Meta data for a episode intro. All time values are in seconds.
*/
@Serializable
data class DatalabIntro(
@SerialName("media_id") val mediaId: String,
@SerialName("startTime") val startTime: Float,
@SerialName("endTime") val endTime: Float,
@SerialName("duration") val duration: Float,
@SerialName("comparedWith") val comparedWith: String,
@SerialName("ordering") val ordering: String,
@SerialName("last_updated") val lastUpdated: String,
)
val NoneDatalabIntro = DatalabIntro("", 0f, 0f, 0f, "", "", "")
/**
* playback/stream data classes
*/

View File

@ -325,19 +325,18 @@ class PlayerActivity : AppCompatActivity() {
hideButtonNextEp()
}
// if meta data is present and opening_start & opening_duration are valid, show skip opening
model.currentEpisodeMeta?.let {
if (it.openingDuration > 0 &&
currentPosition in it.openingStart..(it.openingStart + 10000) &&
!playerBinding.buttonSkipOp.isVisible
) {
// into metadata is present and we can show the skip button
if (model.currentIntroMetadata.duration >= 10) {
val startTime = model.currentIntroMetadata.startTime.toInt() * 1000
if (currentPosition in startTime..(startTime + 10000) && !playerBinding.buttonSkipOp.isVisible) {
showButtonSkipOp()
} else if (playerBinding.buttonSkipOp.isVisible &&
currentPosition !in it.openingStart..(it.openingStart + 10000)
currentPosition !in startTime..(startTime + 10000)
) {
// the button should only be visible, if currentEpisodeMeta != null
// the button should only be visible if currentEpisodeMeta != null
hideButtonSkipOp()
}
}
// if controls are visible, update them
@ -452,8 +451,9 @@ class PlayerActivity : AppCompatActivity() {
private fun skipOpening() {
// calculate the seek time
model.currentEpisodeMeta?.let {
val seekTime = (it.openingStart + it.openingDuration) - model.player.currentPosition
if (model.currentIntroMetadata.duration > 10) {
val endTime = model.currentIntroMetadata.endTime.toInt() * 1000
val seekTime = endTime - model.player.currentPosition
model.seekToOffset(seekTime)
}
}

View File

@ -65,6 +65,8 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
internal set
var currentPlayheads: PlayheadsMap = mutableMapOf()
internal set
var currentIntroMetadata: DatalabIntro = NoneDatalabIntro
internal set
// var tmdbTVSeason: TMDBTVSeason? =null
// internal set
@ -148,6 +150,10 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
// player actions
/**
* Seeks to a offset position specified in milliseconds in the current MediaItem.
* @param offset The offset position in the current MediaItem.
*/
fun seekToOffset(offset: Long) {
player.seekTo(player.currentPosition + offset)
}
@ -201,6 +207,9 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
(it.playhead.times(1000)).toLong()
}
}
},
viewModelScope.launch(Dispatchers.IO) {
currentIntroMetadata = Crunchyroll.datalabIntro(currentEpisode.id)
}
)
}