forked from recloudstream/cloudstream
trailers.to backup fix for movies
This commit is contained in:
parent
dcb97a1f63
commit
06bafa9801
6 changed files with 242 additions and 63 deletions
|
@ -5,6 +5,7 @@ import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
||||||
import com.uwetrottmann.tmdb2.Tmdb
|
import com.uwetrottmann.tmdb2.Tmdb
|
||||||
import com.uwetrottmann.tmdb2.entities.*
|
import com.uwetrottmann.tmdb2.entities.*
|
||||||
|
import retrofit2.awaitResponse
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,7 +16,8 @@ data class TmdbLink(
|
||||||
@JsonProperty("imdbID") val imdbID: String?,
|
@JsonProperty("imdbID") val imdbID: String?,
|
||||||
@JsonProperty("tmdbID") val tmdbID: Int?,
|
@JsonProperty("tmdbID") val tmdbID: Int?,
|
||||||
@JsonProperty("episode") val episode: Int?,
|
@JsonProperty("episode") val episode: Int?,
|
||||||
@JsonProperty("season") val season: Int?
|
@JsonProperty("season") val season: Int?,
|
||||||
|
@JsonProperty("movieName") val movieName: String? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
open class TmdbProvider : MainAPI() {
|
open class TmdbProvider : MainAPI() {
|
||||||
|
@ -144,6 +146,7 @@ open class TmdbProvider : MainAPI() {
|
||||||
this.id,
|
this.id,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
this.title ?: this.original_title,
|
||||||
).toJson(),
|
).toJson(),
|
||||||
getImageUrl(this.poster_path),
|
getImageUrl(this.poster_path),
|
||||||
this.release_date?.let {
|
this.release_date?.let {
|
||||||
|
@ -173,23 +176,33 @@ open class TmdbProvider : MainAPI() {
|
||||||
// it.toSearchResponse()
|
// it.toSearchResponse()
|
||||||
// } ?: listOf()
|
// } ?: listOf()
|
||||||
|
|
||||||
val discoverMovies = tmdb.discoverMovie().build().execute().body()?.results?.map {
|
var discoverMovies: List<MovieSearchResponse> = listOf()
|
||||||
|
var discoverSeries: List<TvSeriesSearchResponse> = listOf()
|
||||||
|
var topMovies: List<MovieSearchResponse> = listOf()
|
||||||
|
var topSeries: List<TvSeriesSearchResponse> = listOf()
|
||||||
|
argamap(
|
||||||
|
{
|
||||||
|
discoverMovies = tmdb.discoverMovie().build().awaitResponse().body()?.results?.map {
|
||||||
it.toSearchResponse()
|
it.toSearchResponse()
|
||||||
} ?: listOf()
|
} ?: listOf()
|
||||||
|
}, {
|
||||||
val discoverSeries = tmdb.discoverTv().build().execute().body()?.results?.map {
|
discoverSeries = tmdb.discoverTv().build().awaitResponse().body()?.results?.map {
|
||||||
it.toSearchResponse()
|
it.toSearchResponse()
|
||||||
} ?: listOf()
|
} ?: listOf()
|
||||||
|
}, {
|
||||||
// https://en.wikipedia.org/wiki/ISO_3166-1
|
// https://en.wikipedia.org/wiki/ISO_3166-1
|
||||||
val topMovies =
|
topMovies =
|
||||||
tmdb.moviesService().topRated(1, "en-US", "US").execute().body()?.results?.map {
|
tmdb.moviesService().topRated(1, "en-US", "US").awaitResponse()
|
||||||
|
.body()?.results?.map {
|
||||||
it.toSearchResponse()
|
it.toSearchResponse()
|
||||||
} ?: listOf()
|
} ?: listOf()
|
||||||
|
}, {
|
||||||
val topSeries = tmdb.tvService().topRated(1, "en-US").execute().body()?.results?.map {
|
topSeries =
|
||||||
|
tmdb.tvService().topRated(1, "en-US").awaitResponse().body()?.results?.map {
|
||||||
it.toSearchResponse()
|
it.toSearchResponse()
|
||||||
} ?: listOf()
|
} ?: listOf()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return HomePageResponse(
|
return HomePageResponse(
|
||||||
listOf(
|
listOf(
|
||||||
|
@ -232,19 +245,19 @@ open class TmdbProvider : MainAPI() {
|
||||||
|
|
||||||
return if (useMetaLoadResponse) {
|
return if (useMetaLoadResponse) {
|
||||||
return if (isTvSeries) {
|
return if (isTvSeries) {
|
||||||
val body = tmdb.tvService().tv(id, "en-US").execute().body()
|
val body = tmdb.tvService().tv(id, "en-US").awaitResponse().body()
|
||||||
body?.toLoadResponse()
|
body?.toLoadResponse()
|
||||||
} else {
|
} else {
|
||||||
val body = tmdb.moviesService().summary(id, "en-US").execute().body()
|
val body = tmdb.moviesService().summary(id, "en-US").awaitResponse().body()
|
||||||
body?.toLoadResponse()
|
body?.toLoadResponse()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
loadFromTmdb(id)?.let { return it }
|
loadFromTmdb(id)?.let { return it }
|
||||||
if (isTvSeries) {
|
if (isTvSeries) {
|
||||||
tmdb.tvService().externalIds(id, "en-US").execute().body()?.imdb_id?.let {
|
tmdb.tvService().externalIds(id, "en-US").awaitResponse().body()?.imdb_id?.let {
|
||||||
val fromImdb = loadFromImdb(it)
|
val fromImdb = loadFromImdb(it)
|
||||||
val result = if (fromImdb == null) {
|
val result = if (fromImdb == null) {
|
||||||
val details = tmdb.tvService().tv(id, "en-US").execute().body()
|
val details = tmdb.tvService().tv(id, "en-US").awaitResponse().body()
|
||||||
loadFromImdb(it, details?.seasons ?: listOf())
|
loadFromImdb(it, details?.seasons ?: listOf())
|
||||||
?: loadFromTmdb(id, details?.seasons ?: listOf())
|
?: loadFromTmdb(id, details?.seasons ?: listOf())
|
||||||
} else {
|
} else {
|
||||||
|
@ -254,16 +267,14 @@ open class TmdbProvider : MainAPI() {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tmdb.moviesService().externalIds(id, "en-US").execute()
|
tmdb.moviesService().externalIds(id, "en-US").awaitResponse()
|
||||||
.body()?.imdb_id?.let { loadFromImdb(it) }
|
.body()?.imdb_id?.let { loadFromImdb(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun search(query: String): List<SearchResponse>? {
|
override suspend fun search(query: String): List<SearchResponse>? {
|
||||||
return tmdb.searchService().multi(query, 1, "en-Us", "US", true).execute()
|
return tmdb.searchService().multi(query, 1, "en-Us", "US", true).awaitResponse()
|
||||||
.body()?.results?.mapNotNull {
|
.body()?.results?.mapNotNull {
|
||||||
it.movie?.toSearchResponse() ?: it.tvShow?.toSearchResponse()
|
it.movie?.toSearchResponse() ?: it.tvShow?.toSearchResponse()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
package com.lagradost.cloudstream3.movieproviders
|
package com.lagradost.cloudstream3.movieproviders
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import com.fasterxml.jackson.module.kotlin.readValue
|
import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.SubtitleFile
|
|
||||||
import com.lagradost.cloudstream3.TvType
|
|
||||||
import com.lagradost.cloudstream3.app
|
|
||||||
import com.lagradost.cloudstream3.mapper
|
|
||||||
import com.lagradost.cloudstream3.metaproviders.TmdbLink
|
import com.lagradost.cloudstream3.metaproviders.TmdbLink
|
||||||
import com.lagradost.cloudstream3.metaproviders.TmdbProvider
|
import com.lagradost.cloudstream3.metaproviders.TmdbProvider
|
||||||
|
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import com.lagradost.cloudstream3.utils.Qualities
|
import com.lagradost.cloudstream3.utils.Qualities
|
||||||
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
||||||
|
@ -20,6 +17,105 @@ class TrailersTwoProvider : TmdbProvider() {
|
||||||
override val useMetaLoadResponse = true
|
override val useMetaLoadResponse = true
|
||||||
override val instantLinkLoading = true
|
override val instantLinkLoading = true
|
||||||
|
|
||||||
|
data class TrailersEpisode(
|
||||||
|
// val tvShowItemID: Long?,
|
||||||
|
//val tvShow: String,
|
||||||
|
//val tvShowIMDB: String?,
|
||||||
|
//val tvShowTMDB: Long?,
|
||||||
|
@JsonProperty("ItemID")
|
||||||
|
val itemID: Int,
|
||||||
|
//val title: String,
|
||||||
|
//@JsonProperty("IMDb")
|
||||||
|
@JsonProperty("IMDb")
|
||||||
|
val imdb: String?,
|
||||||
|
//@JsonProperty("TMDb")
|
||||||
|
@JsonProperty("TMDb")
|
||||||
|
val tmdb: Int?,
|
||||||
|
//val releaseDate: String,
|
||||||
|
//val entryDate: String
|
||||||
|
)
|
||||||
|
|
||||||
|
data class TrailersMovie(
|
||||||
|
@JsonProperty("ItemID")
|
||||||
|
val itemID: Int,
|
||||||
|
@JsonProperty("IMDb")
|
||||||
|
val imdb: String?,
|
||||||
|
@JsonProperty("TMDb")
|
||||||
|
val tmdb: Int?,
|
||||||
|
//@JsonProperty("Title")
|
||||||
|
//val title: String?,
|
||||||
|
)
|
||||||
|
|
||||||
|
/*companion object {
|
||||||
|
private var tmdbToIdMovies: HashMap<Int, Int> = hashMapOf()
|
||||||
|
private var imdbToIdMovies: HashMap<String, Int> = hashMapOf()
|
||||||
|
private var tmdbToIdTvSeries: HashMap<Int, Int> = hashMapOf()
|
||||||
|
private var imdbToIdTvSeries: HashMap<String, Int> = hashMapOf()
|
||||||
|
|
||||||
|
private const val startDate = 1900
|
||||||
|
private const val endDate = 9999
|
||||||
|
|
||||||
|
fun getEpisode(tmdb: Int?, imdb: String?): Int? {
|
||||||
|
var currentId: Int? = null
|
||||||
|
if (tmdb != null) {
|
||||||
|
currentId = tmdbToIdTvSeries[tmdb]
|
||||||
|
}
|
||||||
|
if (imdb != null && currentId == null) {
|
||||||
|
currentId = imdbToIdTvSeries[imdb]
|
||||||
|
}
|
||||||
|
return currentId
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMovie(tmdb: Int?, imdb: String?): Int? {
|
||||||
|
var currentId: Int? = null
|
||||||
|
if (tmdb != null) {
|
||||||
|
currentId = tmdbToIdMovies[tmdb]
|
||||||
|
}
|
||||||
|
if (imdb != null && currentId == null) {
|
||||||
|
currentId = imdbToIdMovies[imdb]
|
||||||
|
}
|
||||||
|
return currentId
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun fillData(isMovie: Boolean) {
|
||||||
|
if (isMovie) {
|
||||||
|
if (tmdbToIdMovies.isNotEmpty() || imdbToIdMovies.isNotEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
parseJson<List<TrailersMovie>>(
|
||||||
|
app.get(
|
||||||
|
"https://trailers.to/movies?from=$startDate-01-01&to=$endDate",
|
||||||
|
timeout = 30
|
||||||
|
).text
|
||||||
|
).forEach { movie ->
|
||||||
|
movie.imdb?.let {
|
||||||
|
imdbToIdTvSeries[it] = movie.itemID
|
||||||
|
}
|
||||||
|
movie.tmdb?.let {
|
||||||
|
tmdbToIdTvSeries[it] = movie.itemID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (tmdbToIdTvSeries.isNotEmpty() || imdbToIdTvSeries.isNotEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
parseJson<List<TrailersEpisode>>(
|
||||||
|
app.get(
|
||||||
|
"https://trailers.to/episodes?from=$startDate-01-01&to=$endDate",
|
||||||
|
timeout = 30
|
||||||
|
).text
|
||||||
|
).forEach { episode ->
|
||||||
|
episode.imdb?.let {
|
||||||
|
imdbToIdTvSeries[it] = episode.itemID
|
||||||
|
}
|
||||||
|
episode.tmdb?.let {
|
||||||
|
tmdbToIdTvSeries[it] = episode.itemID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
override val supportedTypes = setOf(
|
override val supportedTypes = setOf(
|
||||||
TvType.Movie,
|
TvType.Movie,
|
||||||
TvType.TvSeries,
|
TvType.TvSeries,
|
||||||
|
@ -34,50 +130,99 @@ class TrailersTwoProvider : TmdbProvider() {
|
||||||
subtitleCallback: (SubtitleFile) -> Unit,
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
callback: (ExtractorLink) -> Unit
|
callback: (ExtractorLink) -> Unit
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val mappedData = mapper.readValue<TmdbLink>(data)
|
val mappedData = parseJson<TmdbLink>(data)
|
||||||
val (id, site) = if (mappedData.imdbID != null) listOf(
|
val (id, site) = if (mappedData.imdbID != null) listOf(
|
||||||
mappedData.imdbID,
|
mappedData.imdbID,
|
||||||
"imdb"
|
"imdb"
|
||||||
) else listOf(mappedData.tmdbID.toString(), "tmdb")
|
) else listOf(mappedData.tmdbID.toString(), "tmdb")
|
||||||
|
|
||||||
val isMovie = mappedData.episode == null && mappedData.season == null
|
val isMovie = mappedData.episode == null && mappedData.season == null
|
||||||
val subtitleUrl = if (isMovie) {
|
val (videoUrl, subtitleUrl) = if (isMovie) {
|
||||||
callback.invoke(
|
val suffix = "$user/$site/$id"
|
||||||
ExtractorLink(
|
Pair(
|
||||||
this.name,
|
"https://trailers.to/video/$suffix",
|
||||||
this.name,
|
"https://trailers.to/subtitles/$suffix"
|
||||||
"https://trailers.to/video/$user/$site/$id",
|
|
||||||
"https://trailers.to",
|
|
||||||
Qualities.Unknown.value,
|
|
||||||
false,
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
"https://trailers.to/subtitles/$user/$site/$id"
|
|
||||||
} else {
|
} else {
|
||||||
callback.invoke(
|
val suffix = "$user/$site/$id/S${mappedData.season ?: 1}E${mappedData.episode ?: 1}"
|
||||||
ExtractorLink(
|
Pair(
|
||||||
this.name,
|
"https://trailers.to/video/$suffix",
|
||||||
this.name,
|
"https://trailers.to/subtitles/$suffix"
|
||||||
"https://trailers.to/video/$user/$site/$id/S${mappedData.season ?: 1}E${mappedData.episode ?: 1}",
|
|
||||||
"https://trailers.to",
|
|
||||||
Qualities.Unknown.value,
|
|
||||||
false,
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
"https://trailers.to/subtitles/$user/$site/$id/S${mappedData.season ?: 1}E${mappedData.episode ?: 1}"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callback.invoke(
|
||||||
|
ExtractorLink(
|
||||||
|
this.name,
|
||||||
|
this.name,
|
||||||
|
videoUrl,
|
||||||
|
"https://trailers.to",
|
||||||
|
Qualities.Unknown.value,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
argamap(
|
||||||
|
{
|
||||||
val subtitles =
|
val subtitles =
|
||||||
app.get(subtitleUrl).text
|
app.get(subtitleUrl).text
|
||||||
val subtitlesMapped = mapper.readValue<List<TrailersSubtitleFile>>(subtitles)
|
val subtitlesMapped = parseJson<List<TrailersSubtitleFile>>(subtitles)
|
||||||
subtitlesMapped.forEach {
|
subtitlesMapped.forEach {
|
||||||
subtitleCallback.invoke(
|
subtitleCallback.invoke(
|
||||||
SubtitleFile(
|
SubtitleFile(
|
||||||
SubtitleHelper.fromTwoLettersToLanguage(it.LanguageCode ?: "en") ?: "English",
|
SubtitleHelper.fromTwoLettersToLanguage(it.LanguageCode ?: "en")
|
||||||
|
?: "English",
|
||||||
"https://trailers.to/subtitles/${it.ContentHash ?: return@forEach}/${it.LanguageCode ?: return@forEach}.vtt" // ${it.MetaInfo?.SubFormat ?: "srt"}"
|
"https://trailers.to/subtitles/${it.ContentHash ?: return@forEach}/${it.LanguageCode ?: return@forEach}.vtt" // ${it.MetaInfo?.SubFormat ?: "srt"}"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
//https://trailers.to/en/quick-search?q=iron man
|
||||||
|
val name = mappedData.movieName
|
||||||
|
if (name != null && isMovie) {
|
||||||
|
app.get("https://trailers.to/en/quick-search?q=${name}").document.select("a.post-minimal")
|
||||||
|
.mapNotNull {
|
||||||
|
it?.attr("href")
|
||||||
|
}.map { Regex("""/movie/(\d+)/""").find(it)?.groupValues?.getOrNull(1) }
|
||||||
|
.firstOrNull()?.let { movieId ->
|
||||||
|
val correctUrl = app.get(videoUrl).url
|
||||||
|
callback.invoke(
|
||||||
|
ExtractorLink(
|
||||||
|
this.name,
|
||||||
|
"${this.name} Backup",
|
||||||
|
correctUrl.replace("/$user/0/", "/$user/$movieId/"),
|
||||||
|
"https://trailers.to",
|
||||||
|
Qualities.Unknown.value,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
// the problem with this code is that it tages ages and the json file is 50mb or so for movies
|
||||||
|
fillData(isMovie)
|
||||||
|
val movieId = if (isMovie) {
|
||||||
|
getMovie(mappedData.tmdbID, mappedData.imdbID)
|
||||||
|
} else {
|
||||||
|
getEpisode(mappedData.tmdbID, mappedData.imdbID)
|
||||||
|
} ?: return@argamap
|
||||||
|
val request = app.get(data)
|
||||||
|
val endUrl = request.url
|
||||||
|
callback.invoke(
|
||||||
|
ExtractorLink(
|
||||||
|
this.name,
|
||||||
|
"${this.name} Backup",
|
||||||
|
endUrl.replace("/cloudstream/0/", "/cloudstream/$movieId/"),
|
||||||
|
"https://trailers.to",
|
||||||
|
Qualities.Unknown.value,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -293,6 +293,10 @@ open class Requests {
|
||||||
.followRedirects(allowRedirects)
|
.followRedirects(allowRedirects)
|
||||||
.followSslRedirects(allowRedirects)
|
.followSslRedirects(allowRedirects)
|
||||||
.callTimeout(timeout, TimeUnit.SECONDS)
|
.callTimeout(timeout, TimeUnit.SECONDS)
|
||||||
|
if (timeout > 0)
|
||||||
|
client
|
||||||
|
.connectTimeout(timeout, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(timeout, TimeUnit.SECONDS)
|
||||||
|
|
||||||
if (interceptor != null) client.addInterceptor(interceptor)
|
if (interceptor != null) client.addInterceptor(interceptor)
|
||||||
val request =
|
val request =
|
||||||
|
|
|
@ -236,6 +236,14 @@ abstract class AbstractPlayerFragment(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is InvalidFileException -> {
|
||||||
|
showToast(
|
||||||
|
activity,
|
||||||
|
"${ctx.getString(R.string.source_error)}\n${exception.message}",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
)
|
||||||
|
nextMirror()
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
showToast(activity, exception.message, Toast.LENGTH_SHORT)
|
showToast(activity, exception.message, Toast.LENGTH_SHORT)
|
||||||
}
|
}
|
||||||
|
|
|
@ -554,6 +554,15 @@ class CS3IPlayer : IPlayer {
|
||||||
updatedTime()
|
updatedTime()
|
||||||
if (!hasUsedFirstRender) { // this insures that we only call this once per player load
|
if (!hasUsedFirstRender) { // this insures that we only call this once per player load
|
||||||
Log.i(TAG, "Rendered first frame")
|
Log.i(TAG, "Rendered first frame")
|
||||||
|
|
||||||
|
val invalid = exoPlayer?.duration?.let { duration ->
|
||||||
|
duration < 20000L
|
||||||
|
} ?: false
|
||||||
|
if(invalid) {
|
||||||
|
playerError?.invoke(InvalidFileException("Too short playback"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
setPreferredSubtitles(currentSubtitles)
|
setPreferredSubtitles(currentSubtitles)
|
||||||
hasUsedFirstRender = true
|
hasUsedFirstRender = true
|
||||||
val format = exoPlayer?.videoFormat
|
val format = exoPlayer?.videoFormat
|
||||||
|
|
|
@ -44,6 +44,8 @@ enum class CSPlayerLoading {
|
||||||
//IsDone,
|
//IsDone,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class InvalidFileException(msg : String) : Exception(msg)
|
||||||
|
|
||||||
//http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4
|
//http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4
|
||||||
const val STATE_RESUME_WINDOW = "resumeWindow"
|
const val STATE_RESUME_WINDOW = "resumeWindow"
|
||||||
const val STATE_RESUME_POSITION = "resumePosition"
|
const val STATE_RESUME_POSITION = "resumePosition"
|
||||||
|
|
Loading…
Reference in a new issue