mirror of
				https://github.com/recloudstream/cloudstream.git
				synced 2024-08-15 01:53:11 +00:00 
			
		
		
		
	fixed sync stuff and tv stuff
This commit is contained in:
		
							parent
							
								
									10c945f497
								
							
						
					
					
						commit
						7cbdc1fc6c
					
				
					 24 changed files with 209 additions and 160 deletions
				
			
		| 
						 | 
				
			
			@ -13,6 +13,8 @@ import com.fasterxml.jackson.module.kotlin.KotlinModule
 | 
			
		|||
import com.lagradost.cloudstream3.animeproviders.*
 | 
			
		||||
import com.lagradost.cloudstream3.metaproviders.CrossTmdbProvider
 | 
			
		||||
import com.lagradost.cloudstream3.movieproviders.*
 | 
			
		||||
import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.aniListApi
 | 
			
		||||
import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.malApi
 | 
			
		||||
import com.lagradost.cloudstream3.ui.player.SubtitleData
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		||||
import okhttp3.Interceptor
 | 
			
		||||
| 
						 | 
				
			
			@ -119,10 +121,10 @@ object APIHolder {
 | 
			
		|||
        return null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getApiFromUrlNull(url : String?) : MainAPI? {
 | 
			
		||||
    fun getApiFromUrlNull(url: String?): MainAPI? {
 | 
			
		||||
        if (url == null) return null
 | 
			
		||||
        for (api in allProviders) {
 | 
			
		||||
            if(url.startsWith(api.mainUrl))
 | 
			
		||||
            if (url.startsWith(api.mainUrl))
 | 
			
		||||
                return api
 | 
			
		||||
        }
 | 
			
		||||
        return null
 | 
			
		||||
| 
						 | 
				
			
			@ -397,7 +399,7 @@ abstract class MainAPI {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /** An okhttp interceptor for used in OkHttpDataSource */
 | 
			
		||||
    open fun getVideoInterceptor(extractorLink: ExtractorLink) : Interceptor? {
 | 
			
		||||
    open fun getVideoInterceptor(extractorLink: ExtractorLink): Interceptor? {
 | 
			
		||||
        return null
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -571,10 +573,10 @@ enum class SearchQuality {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
/**Add anything to here if you find a site that uses some specific naming convention*/
 | 
			
		||||
fun getQualityFromString(string: String?) : SearchQuality? {
 | 
			
		||||
    val check = (string ?: return null).trim().lowercase().replace(" ","")
 | 
			
		||||
fun getQualityFromString(string: String?): SearchQuality? {
 | 
			
		||||
    val check = (string ?: return null).trim().lowercase().replace(" ", "")
 | 
			
		||||
 | 
			
		||||
    return when(check) {
 | 
			
		||||
    return when (check) {
 | 
			
		||||
        "cam" -> SearchQuality.Cam
 | 
			
		||||
        "camrip" -> SearchQuality.CamRip
 | 
			
		||||
        "hdcam" -> SearchQuality.HdCam
 | 
			
		||||
| 
						 | 
				
			
			@ -589,7 +591,7 @@ fun getQualityFromString(string: String?) : SearchQuality? {
 | 
			
		|||
        "telesync" -> SearchQuality.Telesync
 | 
			
		||||
        "ts" -> SearchQuality.Telesync
 | 
			
		||||
        "dvd" -> SearchQuality.DVD
 | 
			
		||||
        "blueray" ->  SearchQuality.BlueRay
 | 
			
		||||
        "blueray" -> SearchQuality.BlueRay
 | 
			
		||||
        "bluray" -> SearchQuality.BlueRay
 | 
			
		||||
        "br" -> SearchQuality.BlueRay
 | 
			
		||||
        "standard" -> SearchQuality.SD
 | 
			
		||||
| 
						 | 
				
			
			@ -614,7 +616,7 @@ interface SearchResponse {
 | 
			
		|||
    var type: TvType?
 | 
			
		||||
    var posterUrl: String?
 | 
			
		||||
    var id: Int?
 | 
			
		||||
    var quality : SearchQuality?
 | 
			
		||||
    var quality: SearchQuality?
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum class ActorRole {
 | 
			
		||||
| 
						 | 
				
			
			@ -703,8 +705,12 @@ interface LoadResponse {
 | 
			
		|||
    var recommendations: List<SearchResponse>?
 | 
			
		||||
    var actors: List<ActorData>?
 | 
			
		||||
    var comingSoon: Boolean
 | 
			
		||||
    var syncData: MutableMap<String, String>
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        val malIdPrefix = malApi.idPrefix
 | 
			
		||||
        val aniListIdPrefix = aniListApi.idPrefix
 | 
			
		||||
 | 
			
		||||
        @JvmName("addActorNames")
 | 
			
		||||
        fun LoadResponse.addActors(actors: List<String>?) {
 | 
			
		||||
            this.actors = actors?.map { ActorData(Actor(it)) }
 | 
			
		||||
| 
						 | 
				
			
			@ -725,6 +731,30 @@ interface LoadResponse {
 | 
			
		|||
            this.actors = actors?.map { actor -> ActorData(actor) }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fun LoadResponse.addMalId(id: Int?) {
 | 
			
		||||
            this.syncData[malIdPrefix] = (id ?: return).toString()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fun LoadResponse.addAniListId(id: Int?) {
 | 
			
		||||
            this.syncData[aniListIdPrefix] = (id ?: return).toString()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fun LoadResponse.addImdbUrl(url : String?) {
 | 
			
		||||
            addImdbId(imdbUrlToIdNullable(url))
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fun LoadResponse.addImdbId(id: String?) {
 | 
			
		||||
            // TODO add imdb sync
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fun LoadResponse.addTrackId(id: String?) {
 | 
			
		||||
            // TODO add trackt sync
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fun LoadResponse.addkitsuId(id: String?) {
 | 
			
		||||
            // TODO add kitsu sync
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fun LoadResponse.setDuration(input: String?) {
 | 
			
		||||
            val cleanInput = input?.trim()?.replace(" ", "") ?: return
 | 
			
		||||
            Regex("([0-9]*)h.*?([0-9]*)m").find(cleanInput)?.groupValues?.let { values ->
 | 
			
		||||
| 
						 | 
				
			
			@ -789,6 +819,7 @@ data class TorrentLoadResponse(
 | 
			
		|||
    override var recommendations: List<SearchResponse>? = null,
 | 
			
		||||
    override var actors: List<ActorData>? = null,
 | 
			
		||||
    override var comingSoon: Boolean = false,
 | 
			
		||||
    override var syncData: MutableMap<String, String> = mutableMapOf(),
 | 
			
		||||
) : LoadResponse
 | 
			
		||||
 | 
			
		||||
data class AnimeLoadResponse(
 | 
			
		||||
| 
						 | 
				
			
			@ -802,21 +833,20 @@ data class AnimeLoadResponse(
 | 
			
		|||
    override var posterUrl: String? = null,
 | 
			
		||||
    override var year: Int? = null,
 | 
			
		||||
 | 
			
		||||
    var episodes: HashMap<DubStatus, List<AnimeEpisode>> = hashMapOf(),
 | 
			
		||||
    var episodes: MutableMap<DubStatus, List<AnimeEpisode>> = mutableMapOf(),
 | 
			
		||||
    var showStatus: ShowStatus? = null,
 | 
			
		||||
 | 
			
		||||
    override var plot: String? = null,
 | 
			
		||||
    override var tags: List<String>? = null,
 | 
			
		||||
    var synonyms: List<String>? = null,
 | 
			
		||||
 | 
			
		||||
    var malId: Int? = null,
 | 
			
		||||
    var anilistId: Int? = null,
 | 
			
		||||
    override var rating: Int? = null,
 | 
			
		||||
    override var duration: Int? = null,
 | 
			
		||||
    override var trailerUrl: String? = null,
 | 
			
		||||
    override var recommendations: List<SearchResponse>? = null,
 | 
			
		||||
    override var actors: List<ActorData>? = null,
 | 
			
		||||
    override var comingSoon: Boolean = false,
 | 
			
		||||
    override var syncData: MutableMap<String, String> = mutableMapOf(),
 | 
			
		||||
) : LoadResponse
 | 
			
		||||
 | 
			
		||||
fun AnimeLoadResponse.addEpisodes(status: DubStatus, episodes: List<AnimeEpisode>?) {
 | 
			
		||||
| 
						 | 
				
			
			@ -828,15 +858,15 @@ fun MainAPI.newAnimeLoadResponse(
 | 
			
		|||
    name: String,
 | 
			
		||||
    url: String,
 | 
			
		||||
    type: TvType,
 | 
			
		||||
    comingSoonIfNone : Boolean,
 | 
			
		||||
    comingSoonIfNone: Boolean,
 | 
			
		||||
    initializer: AnimeLoadResponse.() -> Unit = { },
 | 
			
		||||
): AnimeLoadResponse {
 | 
			
		||||
    val builder = AnimeLoadResponse(name = name, url = url, apiName = this.name, type = type)
 | 
			
		||||
    builder.initializer()
 | 
			
		||||
    if(comingSoonIfNone) {
 | 
			
		||||
    if (comingSoonIfNone) {
 | 
			
		||||
        builder.comingSoon = true
 | 
			
		||||
        for (key in builder.episodes.keys)
 | 
			
		||||
            if(!builder.episodes[key].isNullOrEmpty()) {
 | 
			
		||||
            if (!builder.episodes[key].isNullOrEmpty()) {
 | 
			
		||||
                builder.comingSoon = false
 | 
			
		||||
                break
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -864,7 +894,6 @@ data class MovieLoadResponse(
 | 
			
		|||
    override var year: Int? = null,
 | 
			
		||||
    override var plot: String? = null,
 | 
			
		||||
 | 
			
		||||
    var imdbId: String? = null,
 | 
			
		||||
    override var rating: Int? = null,
 | 
			
		||||
    override var tags: List<String>? = null,
 | 
			
		||||
    override var duration: Int? = null,
 | 
			
		||||
| 
						 | 
				
			
			@ -872,6 +901,7 @@ data class MovieLoadResponse(
 | 
			
		|||
    override var recommendations: List<SearchResponse>? = null,
 | 
			
		||||
    override var actors: List<ActorData>? = null,
 | 
			
		||||
    override var comingSoon: Boolean = false,
 | 
			
		||||
    override var syncData: MutableMap<String, String> = mutableMapOf(),
 | 
			
		||||
) : LoadResponse
 | 
			
		||||
 | 
			
		||||
fun MainAPI.newMovieLoadResponse(
 | 
			
		||||
| 
						 | 
				
			
			@ -916,7 +946,6 @@ data class TvSeriesLoadResponse(
 | 
			
		|||
    override var plot: String? = null,
 | 
			
		||||
 | 
			
		||||
    var showStatus: ShowStatus? = null,
 | 
			
		||||
    var imdbId: String? = null,
 | 
			
		||||
    override var rating: Int? = null,
 | 
			
		||||
    override var tags: List<String>? = null,
 | 
			
		||||
    override var duration: Int? = null,
 | 
			
		||||
| 
						 | 
				
			
			@ -924,6 +953,7 @@ data class TvSeriesLoadResponse(
 | 
			
		|||
    override var recommendations: List<SearchResponse>? = null,
 | 
			
		||||
    override var actors: List<ActorData>? = null,
 | 
			
		||||
    override var comingSoon: Boolean = false,
 | 
			
		||||
    override var syncData: MutableMap<String, String> = mutableMapOf(),
 | 
			
		||||
) : LoadResponse
 | 
			
		||||
 | 
			
		||||
fun MainAPI.newTvSeriesLoadResponse(
 | 
			
		||||
| 
						 | 
				
			
			@ -954,5 +984,5 @@ fun fetchUrls(text: String?): List<String> {
 | 
			
		|||
    return linkRegex.findAll(text).map { it.value.trim().removeSurrounding("\"") }.toList()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun String?.toRatingInt() : Int? =
 | 
			
		||||
fun String?.toRatingInt(): Int? =
 | 
			
		||||
    this?.trim()?.toDoubleOrNull()?.absoluteValue?.times(1000f)?.toInt()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -275,21 +275,26 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
 | 
			
		|||
                    if (str.contains("/${api.redirectUrl}")) {
 | 
			
		||||
                        ioSafe {
 | 
			
		||||
                            Log.i(TAG, "handleAppIntent $str")
 | 
			
		||||
                            if (api.handleRedirect(str)) {
 | 
			
		||||
                            val isSuccessful = api.handleRedirect(str)
 | 
			
		||||
 | 
			
		||||
                            if (isSuccessful) {
 | 
			
		||||
                                Log.i(TAG, "authenticated ${api.name}")
 | 
			
		||||
                                this.runOnUiThread {
 | 
			
		||||
                                    try {
 | 
			
		||||
                                        showToast(
 | 
			
		||||
                                            this,
 | 
			
		||||
                                            getString(R.string.authenticated_user).format(api.name)
 | 
			
		||||
                                        )
 | 
			
		||||
                                    } catch (e: Exception) {
 | 
			
		||||
                                        logError(e) // format might fail
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                            } else {
 | 
			
		||||
                                Log.i(TAG, "failed to authenticate ${api.name}")
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            this.runOnUiThread {
 | 
			
		||||
                                try {
 | 
			
		||||
                                    showToast(
 | 
			
		||||
                                        this,
 | 
			
		||||
                                        getString(if (isSuccessful) R.string.authenticated_user else R.string.authenticated_user_fail).format(
 | 
			
		||||
                                            api.name
 | 
			
		||||
                                        )
 | 
			
		||||
                                    )
 | 
			
		||||
                                } catch (e: Exception) {
 | 
			
		||||
                                    logError(e) // format might fail
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,8 @@ package com.lagradost.cloudstream3.animeproviders
 | 
			
		|||
import com.fasterxml.jackson.annotation.JsonProperty
 | 
			
		||||
import com.fasterxml.jackson.module.kotlin.readValue
 | 
			
		||||
import com.lagradost.cloudstream3.*
 | 
			
		||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
 | 
			
		||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
 | 
			
		||||
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
 | 
			
		||||
import com.lagradost.cloudstream3.network.AppResponse
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		||||
| 
						 | 
				
			
			@ -305,8 +307,8 @@ class AnimePaheProvider : MainAPI() {
 | 
			
		|||
                    null
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this.malId = malId
 | 
			
		||||
                this.anilistId = anilistId
 | 
			
		||||
                addMalId(malId)
 | 
			
		||||
                addAniListId(anilistId)
 | 
			
		||||
                this.trailerUrl = trailer
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,13 @@
 | 
			
		|||
package com.lagradost.cloudstream3.animeproviders
 | 
			
		||||
 | 
			
		||||
import java.util.*
 | 
			
		||||
import org.json.JSONObject
 | 
			
		||||
import org.jsoup.nodes.Element
 | 
			
		||||
import com.lagradost.cloudstream3.*
 | 
			
		||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
 | 
			
		||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		||||
import com.lagradost.cloudstream3.utils.Qualities
 | 
			
		||||
import org.json.JSONObject
 | 
			
		||||
import org.jsoup.nodes.Element
 | 
			
		||||
import java.util.*
 | 
			
		||||
 | 
			
		||||
class AnimeWorldProvider : MainAPI() {
 | 
			
		||||
    override var mainUrl = "https://www.animeworld.tv"
 | 
			
		||||
| 
						 | 
				
			
			@ -170,8 +172,8 @@ class AnimeWorldProvider : MainAPI() {
 | 
			
		|||
            showStatus = status
 | 
			
		||||
            plot = description
 | 
			
		||||
            tags = genres
 | 
			
		||||
            this.malId = malId
 | 
			
		||||
            this.anilistId = anlId
 | 
			
		||||
            addMalId(malId)
 | 
			
		||||
            addAniListId(anlId)
 | 
			
		||||
            this.rating = rating
 | 
			
		||||
            this.duration = duration
 | 
			
		||||
            this.trailerUrl = trailerUrl
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,8 @@ import android.util.Log
 | 
			
		|||
import com.fasterxml.jackson.annotation.JsonProperty
 | 
			
		||||
import com.fasterxml.jackson.module.kotlin.readValue
 | 
			
		||||
import com.lagradost.cloudstream3.*
 | 
			
		||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
 | 
			
		||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
 | 
			
		||||
import com.lagradost.cloudstream3.movieproviders.SflixProvider.Companion.extractRabbitStream
 | 
			
		||||
import com.lagradost.cloudstream3.movieproviders.SflixProvider.Companion.runSflixExtractorVerifierJob
 | 
			
		||||
import com.lagradost.cloudstream3.network.Requests.Companion.await
 | 
			
		||||
| 
						 | 
				
			
			@ -291,8 +293,8 @@ class ZoroProvider : MainAPI() {
 | 
			
		|||
            this.tags = tags
 | 
			
		||||
            this.recommendations = recommendations
 | 
			
		||||
            this.actors = actors
 | 
			
		||||
            this.malId = syncData?.malId?.toIntOrNull()
 | 
			
		||||
            this.anilistId = syncData?.aniListId?.toIntOrNull()
 | 
			
		||||
            addMalId(syncData?.malId?.toIntOrNull())
 | 
			
		||||
            addAniListId(syncData?.aniListId?.toIntOrNull())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,7 @@ package com.lagradost.cloudstream3.metaproviders
 | 
			
		|||
import com.fasterxml.jackson.annotation.JsonProperty
 | 
			
		||||
import com.lagradost.cloudstream3.*
 | 
			
		||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
 | 
			
		||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addImdbId
 | 
			
		||||
import com.lagradost.cloudstream3.utils.AppUtils.toJson
 | 
			
		||||
import com.uwetrottmann.tmdb2.Tmdb
 | 
			
		||||
import com.uwetrottmann.tmdb2.entities.*
 | 
			
		||||
| 
						 | 
				
			
			@ -135,7 +136,8 @@ open class TmdbProvider : MainAPI() {
 | 
			
		|||
                }.get(Calendar.YEAR)
 | 
			
		||||
            }
 | 
			
		||||
            plot = overview
 | 
			
		||||
            imdbId = external_ids?.imdb_id
 | 
			
		||||
            addImdbId(external_ids?.imdb_id)
 | 
			
		||||
 | 
			
		||||
            tags = genres?.mapNotNull { it.name }
 | 
			
		||||
            duration = episode_run_time?.average()?.toInt()
 | 
			
		||||
            rating = this@toLoadResponse.rating
 | 
			
		||||
| 
						 | 
				
			
			@ -163,7 +165,7 @@ open class TmdbProvider : MainAPI() {
 | 
			
		|||
                }.get(Calendar.YEAR)
 | 
			
		||||
            }
 | 
			
		||||
            plot = overview
 | 
			
		||||
            imdbId = external_ids?.imdb_id
 | 
			
		||||
            addImdbId(external_ids?.imdb_id)
 | 
			
		||||
            tags = genres?.mapNotNull { it.name }
 | 
			
		||||
            duration = runtime
 | 
			
		||||
            rating = this@toLoadResponse.rating
 | 
			
		||||
| 
						 | 
				
			
			@ -251,7 +253,8 @@ open class TmdbProvider : MainAPI() {
 | 
			
		|||
        val found = idRegex.find(url)
 | 
			
		||||
 | 
			
		||||
        val isTvSeries = found?.groupValues?.getOrNull(1).equals("tv", ignoreCase = true)
 | 
			
		||||
        val id = found?.groupValues?.getOrNull(2)?.toIntOrNull() ?: throw ErrorLoadingException("No id found")
 | 
			
		||||
        val id = found?.groupValues?.getOrNull(2)?.toIntOrNull()
 | 
			
		||||
            ?: throw ErrorLoadingException("No id found")
 | 
			
		||||
 | 
			
		||||
        return if (useMetaLoadResponse) {
 | 
			
		||||
            return if (isTvSeries) {
 | 
			
		||||
| 
						 | 
				
			
			@ -263,8 +266,8 @@ open class TmdbProvider : MainAPI() {
 | 
			
		|||
                            ?.let {
 | 
			
		||||
                                it.results?.map { res -> res.toSearchResponse() }
 | 
			
		||||
                            }?.let { list ->
 | 
			
		||||
                            response.recommendations = list
 | 
			
		||||
                        }
 | 
			
		||||
                                response.recommendations = list
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                    if (response.actors.isNullOrEmpty())
 | 
			
		||||
                        tmdb.tvService().credits(id, "en-US").awaitResponse().body()?.let {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -167,7 +167,6 @@ class AllMoviesForYouProvider : MainAPI() {
 | 
			
		|||
                year?.toIntOrNull(),
 | 
			
		||||
                descipt,
 | 
			
		||||
                null,
 | 
			
		||||
                null,
 | 
			
		||||
                rating
 | 
			
		||||
            )
 | 
			
		||||
        } else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -107,7 +107,6 @@ class AsiaFlixProvider : MainAPI() {
 | 
			
		|||
            synopsis,
 | 
			
		||||
            getStatus(tvStatus ?: ""),
 | 
			
		||||
            null,
 | 
			
		||||
            null,
 | 
			
		||||
            genre?.split(",")?.map { it.trim() }
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -286,7 +286,6 @@ open class BflixProvider() : MainAPI() {
 | 
			
		|||
                    year?.toIntOrNull(),
 | 
			
		||||
                    description,
 | 
			
		||||
                    null,
 | 
			
		||||
                    null,
 | 
			
		||||
                    rating,
 | 
			
		||||
                    tags,
 | 
			
		||||
                    recommendations = recommendations,
 | 
			
		||||
| 
						 | 
				
			
			@ -303,7 +302,6 @@ open class BflixProvider() : MainAPI() {
 | 
			
		|||
                    poster,
 | 
			
		||||
                    year?.toIntOrNull(),
 | 
			
		||||
                    description,
 | 
			
		||||
                    null,
 | 
			
		||||
                    rating,
 | 
			
		||||
                    tags,
 | 
			
		||||
                    recommendations = recommendations,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -182,7 +182,6 @@ class IHaveNoTvProvider : MainAPI() {
 | 
			
		|||
                )?.destructured?.component1()?.toIntOrNull(),
 | 
			
		||||
                description,
 | 
			
		||||
                null,
 | 
			
		||||
                null,
 | 
			
		||||
                soup.selectFirst(".videoDetails").select("a[href*=\"/category/\"]")
 | 
			
		||||
                    .map { it.text().trim() }
 | 
			
		||||
            ))
 | 
			
		||||
| 
						 | 
				
			
			@ -204,7 +203,6 @@ class IHaveNoTvProvider : MainAPI() {
 | 
			
		|||
            description,
 | 
			
		||||
            null,
 | 
			
		||||
            null,
 | 
			
		||||
            null,
 | 
			
		||||
            categories.toList()
 | 
			
		||||
        ) else (episodes?.first() as MovieLoadResponse)
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -235,7 +235,6 @@ class LookMovieProvider : MainAPI() {
 | 
			
		|||
                poster,
 | 
			
		||||
                year,
 | 
			
		||||
                descript,
 | 
			
		||||
                null,
 | 
			
		||||
                rating
 | 
			
		||||
            )
 | 
			
		||||
        } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -292,7 +291,6 @@ class LookMovieProvider : MainAPI() {
 | 
			
		|||
                year,
 | 
			
		||||
                descript,
 | 
			
		||||
                null,
 | 
			
		||||
                null,
 | 
			
		||||
                rating
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,7 @@ package com.lagradost.cloudstream3.movieproviders
 | 
			
		|||
import com.fasterxml.jackson.annotation.JsonProperty
 | 
			
		||||
import com.fasterxml.jackson.module.kotlin.readValue
 | 
			
		||||
import com.lagradost.cloudstream3.*
 | 
			
		||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addImdbUrl
 | 
			
		||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
 | 
			
		||||
import com.lagradost.cloudstream3.utils.AppUtils.toJson
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		||||
| 
						 | 
				
			
			@ -144,17 +145,17 @@ class MeloMovieProvider : MainAPI() {
 | 
			
		|||
        if (type == 1) { // MOVIE
 | 
			
		||||
            val serialize = document.selectFirst("table.accordion__list")
 | 
			
		||||
                ?: throw ErrorLoadingException("No links found")
 | 
			
		||||
            return MovieLoadResponse(
 | 
			
		||||
            return newMovieLoadResponse(
 | 
			
		||||
                title,
 | 
			
		||||
                url,
 | 
			
		||||
                this.name,
 | 
			
		||||
                TvType.Movie,
 | 
			
		||||
                serializeData(serialize),
 | 
			
		||||
                poster,
 | 
			
		||||
                year,
 | 
			
		||||
                plot,
 | 
			
		||||
                imdbUrlToIdNullable(imdbUrl)
 | 
			
		||||
            )
 | 
			
		||||
                serializeData(serialize)
 | 
			
		||||
            ) {
 | 
			
		||||
                this.posterUrl = poster
 | 
			
		||||
                this.year = year
 | 
			
		||||
                this.plot = plot
 | 
			
		||||
                addImdbUrl(imdbUrl)
 | 
			
		||||
            }
 | 
			
		||||
        } else if (type == 2) {
 | 
			
		||||
            val episodes = ArrayList<TvSeriesEpisode>()
 | 
			
		||||
            val seasons = document.select("div.accordion__card")
 | 
			
		||||
| 
						 | 
				
			
			@ -175,18 +176,17 @@ class MeloMovieProvider : MainAPI() {
 | 
			
		|||
                }
 | 
			
		||||
            }
 | 
			
		||||
            episodes.reverse()
 | 
			
		||||
            return TvSeriesLoadResponse(
 | 
			
		||||
            return newTvSeriesLoadResponse(
 | 
			
		||||
                title,
 | 
			
		||||
                url,
 | 
			
		||||
                this.name,
 | 
			
		||||
                TvType.TvSeries,
 | 
			
		||||
                episodes,
 | 
			
		||||
                poster,
 | 
			
		||||
                year,
 | 
			
		||||
                plot,
 | 
			
		||||
                null,
 | 
			
		||||
                imdbUrlToIdNullable(imdbUrl)
 | 
			
		||||
            )
 | 
			
		||||
                episodes
 | 
			
		||||
            ) {
 | 
			
		||||
                this.posterUrl = poster
 | 
			
		||||
                this.year = year
 | 
			
		||||
                this.plot = plot
 | 
			
		||||
                addImdbUrl(imdbUrl)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return null
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -163,7 +163,6 @@ class PelisflixProvider : MainAPI() {
 | 
			
		|||
                year?.toIntOrNull(),
 | 
			
		||||
                descipt2,
 | 
			
		||||
                null,
 | 
			
		||||
                null,
 | 
			
		||||
                rating
 | 
			
		||||
            )
 | 
			
		||||
        } else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
package com.lagradost.cloudstream3.movieproviders
 | 
			
		||||
 | 
			
		||||
import com.lagradost.cloudstream3.*
 | 
			
		||||
import com.lagradost.cloudstream3.utils.*
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		||||
import com.lagradost.cloudstream3.utils.loadExtractor
 | 
			
		||||
import org.jsoup.nodes.Element
 | 
			
		||||
import java.util.*
 | 
			
		||||
 | 
			
		||||
class PelisplusHDProvider:MainAPI() {
 | 
			
		||||
    override var mainUrl = "https://pelisplushd.net"
 | 
			
		||||
| 
						 | 
				
			
			@ -137,7 +137,6 @@ class PelisplusHDProvider:MainAPI() {
 | 
			
		|||
                    description,
 | 
			
		||||
                    null,
 | 
			
		||||
                    null,
 | 
			
		||||
                    null,
 | 
			
		||||
                    tags,
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -152,7 +151,6 @@ class PelisplusHDProvider:MainAPI() {
 | 
			
		|||
                    year,
 | 
			
		||||
                    description,
 | 
			
		||||
                    null,
 | 
			
		||||
                    null,
 | 
			
		||||
                    tags,
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -160,7 +160,6 @@ class SeriesflixProvider : MainAPI() {
 | 
			
		|||
                year?.toIntOrNull(),
 | 
			
		||||
                descipt,
 | 
			
		||||
                null,
 | 
			
		||||
                null,
 | 
			
		||||
                rating
 | 
			
		||||
            )
 | 
			
		||||
        } else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,7 +76,6 @@ class VfFilmProvider : MainAPI() {
 | 
			
		|||
        val title = document?.selectFirst("div.SubTitle")?.text()
 | 
			
		||||
            ?: throw ErrorLoadingException("Service might be unavailable")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        val year = document.select("span.Date").text()?.toIntOrNull()
 | 
			
		||||
 | 
			
		||||
        val rating = document.select("span.AAIco-star").text()
 | 
			
		||||
| 
						 | 
				
			
			@ -88,7 +87,6 @@ class VfFilmProvider : MainAPI() {
 | 
			
		|||
 | 
			
		||||
        val descript = document.selectFirst("div.Description > p").text()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        val players = document.select("ul.TPlayerNv > li")
 | 
			
		||||
        var number_player = 0
 | 
			
		||||
        var found = false
 | 
			
		||||
| 
						 | 
				
			
			@ -108,17 +106,17 @@ class VfFilmProvider : MainAPI() {
 | 
			
		|||
 | 
			
		||||
        val data = getDirect("$mainUrl/?trembed=$i&trid=$trid&trtype=1")
 | 
			
		||||
 | 
			
		||||
        return MovieLoadResponse(
 | 
			
		||||
        return newMovieLoadResponse(
 | 
			
		||||
            title,
 | 
			
		||||
            url,
 | 
			
		||||
            this.name,
 | 
			
		||||
            TvType.Movie,
 | 
			
		||||
            data,
 | 
			
		||||
            poster,
 | 
			
		||||
            year,
 | 
			
		||||
            descript,
 | 
			
		||||
            rating,
 | 
			
		||||
            duration
 | 
			
		||||
        )
 | 
			
		||||
            data
 | 
			
		||||
        ) {
 | 
			
		||||
            this.posterUrl = poster
 | 
			
		||||
            this.year = year
 | 
			
		||||
            this.plot = descript
 | 
			
		||||
            //this.rating = rating
 | 
			
		||||
            this.duration = duration
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -160,7 +160,6 @@ class VfSerieProvider : MainAPI() {
 | 
			
		|||
            year,
 | 
			
		||||
            descript,
 | 
			
		||||
            null,
 | 
			
		||||
            null,
 | 
			
		||||
            rating
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -78,7 +78,6 @@ class FrenchStreamProvider : MainAPI() {
 | 
			
		|||
                poster,
 | 
			
		||||
                date,
 | 
			
		||||
                description,
 | 
			
		||||
                null,
 | 
			
		||||
                ratingAverage,
 | 
			
		||||
                tagsList,
 | 
			
		||||
                null,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -606,13 +606,15 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
 | 
			
		|||
        result_recommendations_btt?.isGone = isInvalid
 | 
			
		||||
        result_recommendations_btt?.setOnClickListener {
 | 
			
		||||
            if (result_overlapping_panels?.getSelectedPanel()?.ordinal == 1) {
 | 
			
		||||
                result_recommendations_btt?.nextFocusDownId = R.id.result_recommendations
 | 
			
		||||
                result_overlapping_panels?.openEndPanel()
 | 
			
		||||
            } else {
 | 
			
		||||
                result_recommendations_btt?.nextFocusDownId = R.id.result_description
 | 
			
		||||
                result_overlapping_panels?.closePanels()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        result_overlapping_panels?.setEndPanelLockState(if (isInvalid) OverlappingPanelsLayout.LockState.CLOSE else OverlappingPanelsLayout.LockState.UNLOCKED)
 | 
			
		||||
        result_recommendations.post {
 | 
			
		||||
        result_recommendations?.post {
 | 
			
		||||
            rec?.let { list ->
 | 
			
		||||
                (result_recommendations?.adapter as SearchAdapter?)?.updateList(list)
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -1337,6 +1339,7 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
 | 
			
		|||
                    result_sync_loading_shimmer?.stopShimmer()
 | 
			
		||||
                    result_sync_loading_shimmer?.isVisible = false
 | 
			
		||||
                    result_sync_holder?.isVisible = false
 | 
			
		||||
                    closed = true
 | 
			
		||||
                }
 | 
			
		||||
                is Resource.Loading -> {
 | 
			
		||||
                    result_sync_loading_shimmer?.startShimmer()
 | 
			
		||||
| 
						 | 
				
			
			@ -1420,6 +1423,10 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
 | 
			
		|||
            }
 | 
			
		||||
 | 
			
		||||
            result_series_parent?.isVisible = isSeriesVisible
 | 
			
		||||
            if (isSeriesVisible && activity?.currentFocus?.id == R.id.result_back && context?.isTrueTvSettings() == true) {
 | 
			
		||||
                result_resume_series_button?.requestFocus()
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (isSeriesVisible) {
 | 
			
		||||
                val down = when {
 | 
			
		||||
                    result_season_button?.isVisible == true -> result_season_button
 | 
			
		||||
| 
						 | 
				
			
			@ -1634,23 +1641,20 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
 | 
			
		|||
                    setRecommendations(d.recommendations)
 | 
			
		||||
                    setActors(d.actors)
 | 
			
		||||
 | 
			
		||||
                    if (SettingsFragment.accountEnabled)
 | 
			
		||||
                        if (d is AnimeLoadResponse) {
 | 
			
		||||
                            // don't inline these variables as it will cause them to not be called
 | 
			
		||||
                            val addedMal = setMalSync(d.malId)
 | 
			
		||||
                            val addedAniList = setAniListSync(d.anilistId)
 | 
			
		||||
                            if (
 | 
			
		||||
                                addedMal
 | 
			
		||||
                                ||
 | 
			
		||||
                                addedAniList
 | 
			
		||||
                            ) {
 | 
			
		||||
                                syncModel.updateMetaAndUser()
 | 
			
		||||
                                syncModel.updateSynced()
 | 
			
		||||
                            } else {
 | 
			
		||||
                                syncModel.addFromUrl(d.url)
 | 
			
		||||
                            }
 | 
			
		||||
                    if (SettingsFragment.accountEnabled) {
 | 
			
		||||
                        var isValid = false
 | 
			
		||||
                        for ((prefix, id) in d.syncData) {
 | 
			
		||||
                            isValid = isValid || syncModel.addSync(prefix, id)
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (isValid) {
 | 
			
		||||
                            syncModel.updateMetaAndUser()
 | 
			
		||||
                            syncModel.updateSynced()
 | 
			
		||||
                        } else {
 | 
			
		||||
                            syncModel.addFromUrl(d.url)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    result_meta_site?.text = d.apiName
 | 
			
		||||
 | 
			
		||||
                    val posterImageLink = d.posterUrl
 | 
			
		||||
| 
						 | 
				
			
			@ -1658,28 +1662,30 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
 | 
			
		|||
                        result_poster?.setImage(posterImageLink)
 | 
			
		||||
                        result_poster_blur?.setImageBlur(posterImageLink, 10, 3)
 | 
			
		||||
                        //Full screen view of Poster image
 | 
			
		||||
                        result_poster_holder?.setOnClickListener {
 | 
			
		||||
                            try {
 | 
			
		||||
                                context?.let { ctx ->
 | 
			
		||||
                                    val bitmap = result_poster.drawable.toBitmap()
 | 
			
		||||
                                    val sourceBuilder = AlertDialog.Builder(ctx)
 | 
			
		||||
                                    sourceBuilder.setView(R.layout.result_poster)
 | 
			
		||||
                        if (context?.isTrueTvSettings() == false) // Poster not clickable on tv
 | 
			
		||||
                            result_poster_holder?.setOnClickListener {
 | 
			
		||||
                                try {
 | 
			
		||||
                                    context?.let { ctx ->
 | 
			
		||||
                                        val bitmap = result_poster.drawable.toBitmap()
 | 
			
		||||
                                        val sourceBuilder = AlertDialog.Builder(ctx)
 | 
			
		||||
                                        sourceBuilder.setView(R.layout.result_poster)
 | 
			
		||||
 | 
			
		||||
                                    val sourceDialog = sourceBuilder.create()
 | 
			
		||||
                                    sourceDialog.show()
 | 
			
		||||
                                        val sourceDialog = sourceBuilder.create()
 | 
			
		||||
                                        sourceDialog.show()
 | 
			
		||||
 | 
			
		||||
                                    sourceDialog.findViewById<ImageView?>(R.id.imgPoster)
 | 
			
		||||
                                        ?.apply {
 | 
			
		||||
                                            setImageBitmap(bitmap)
 | 
			
		||||
                                            setOnClickListener {
 | 
			
		||||
                                                sourceDialog.dismissSafe()
 | 
			
		||||
                                        sourceDialog.findViewById<ImageView?>(R.id.imgPoster)
 | 
			
		||||
                                            ?.apply {
 | 
			
		||||
                                                setImageBitmap(bitmap)
 | 
			
		||||
                                                setOnClickListener {
 | 
			
		||||
                                                    sourceDialog.dismissSafe()
 | 
			
		||||
                                                }
 | 
			
		||||
                                            }
 | 
			
		||||
                                        }
 | 
			
		||||
                                    }
 | 
			
		||||
                                } catch (e: Exception) {
 | 
			
		||||
                                    logError(e)
 | 
			
		||||
                                }
 | 
			
		||||
                            } catch (e: Exception) {
 | 
			
		||||
                                logError(e)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    } else {
 | 
			
		||||
                        result_poster?.setImageResource(R.drawable.default_cover)
 | 
			
		||||
                        result_poster_blur?.setImageResource(R.drawable.default_cover)
 | 
			
		||||
| 
						 | 
				
			
			@ -1698,16 +1704,16 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
 | 
			
		|||
                        if (syno.length > MAX_SYNO_LENGH) {
 | 
			
		||||
                            syno = syno.substring(0, MAX_SYNO_LENGH) + "..."
 | 
			
		||||
                        }
 | 
			
		||||
                        result_descript.setOnClickListener {
 | 
			
		||||
                        result_description.setOnClickListener {
 | 
			
		||||
                            val builder: AlertDialog.Builder =
 | 
			
		||||
                                AlertDialog.Builder(requireContext())
 | 
			
		||||
                            builder.setMessage(d.plot)
 | 
			
		||||
                                .setTitle(if (d.type == TvType.Torrent) R.string.torrent_plot else R.string.result_plot)
 | 
			
		||||
                                .show()
 | 
			
		||||
                        }
 | 
			
		||||
                        result_descript.text = syno
 | 
			
		||||
                        result_description.text = syno
 | 
			
		||||
                    } else {
 | 
			
		||||
                        result_descript.text =
 | 
			
		||||
                        result_description.text =
 | 
			
		||||
                            if (d.type == TvType.Torrent) getString(R.string.torrent_no_plot) else getString(
 | 
			
		||||
                                R.string.normal_no_plot
 | 
			
		||||
                            )
 | 
			
		||||
| 
						 | 
				
			
			@ -1727,12 +1733,13 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
 | 
			
		|||
                        //result_tag_holder?.visibility = GONE
 | 
			
		||||
                    } else {
 | 
			
		||||
                        //result_tag_holder?.visibility = VISIBLE
 | 
			
		||||
 | 
			
		||||
                        val isOnTv = context?.isTrueTvSettings() == true
 | 
			
		||||
                        for ((index, tag) in tags.withIndex()) {
 | 
			
		||||
                            val viewBtt = layoutInflater.inflate(R.layout.result_tag, null)
 | 
			
		||||
                            val btt = viewBtt.findViewById<MaterialButton>(R.id.result_tag_card)
 | 
			
		||||
                            btt.text = tag
 | 
			
		||||
 | 
			
		||||
                            btt.isFocusable = !isOnTv
 | 
			
		||||
                            btt.isClickable = !isOnTv
 | 
			
		||||
                            result_tag?.addView(viewBtt, index)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1980,8 +1987,14 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
 | 
			
		|||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                result_meta_site?.setOnClickListener {
 | 
			
		||||
                    it.context?.openBrowser(tempUrl)
 | 
			
		||||
                // bloats the navigation on tv
 | 
			
		||||
                if (context?.isTrueTvSettings() == false) {
 | 
			
		||||
                    result_meta_site?.setOnClickListener {
 | 
			
		||||
                        it.context?.openBrowser(tempUrl)
 | 
			
		||||
                    }
 | 
			
		||||
                    result_meta_site?.isFocusable = true
 | 
			
		||||
                } else {
 | 
			
		||||
                    result_meta_site?.isFocusable = false
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (restart || viewModel.result.value == null) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -65,18 +65,19 @@ class SyncViewModel : ViewModel() {
 | 
			
		|||
        _currentSynced.postValue(getMissing())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun setMalId(id: String?) : Boolean {
 | 
			
		||||
        if(syncIds[malApi.idPrefix] == id ?: return false) return false
 | 
			
		||||
        syncIds[malApi.idPrefix] = id
 | 
			
		||||
        Log.i(TAG, "setMalId = $id")
 | 
			
		||||
    fun addSync(idPrefix: String, id : String) : Boolean {
 | 
			
		||||
        if(syncIds[idPrefix] == id) return false
 | 
			
		||||
        Log.i(TAG, "addSync $idPrefix = $id")
 | 
			
		||||
        syncIds[idPrefix] = id
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun setMalId(id: String?) : Boolean {
 | 
			
		||||
        return addSync(malApi.idPrefix,id ?: return false)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun setAniListId(id: String?) : Boolean {
 | 
			
		||||
        if(syncIds[aniListApi.idPrefix] == id ?: return false) return false
 | 
			
		||||
        syncIds[aniListApi.idPrefix] = id
 | 
			
		||||
        Log.i(TAG, "setAniListId = $id")
 | 
			
		||||
        return true
 | 
			
		||||
        return addSync(aniListApi.idPrefix,id ?: return false)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var hasAddedFromUrl: HashSet<String> = hashSetOf()
 | 
			
		||||
| 
						 | 
				
			
			@ -164,13 +165,15 @@ class SyncViewModel : ViewModel() {
 | 
			
		|||
        _userDataResponse.postValue(Resource.Loading())
 | 
			
		||||
        var lastError: Resource<SyncAPI.SyncStatus> = Resource.Failure(false, null, null, "No data")
 | 
			
		||||
        for ((prefix, id) in syncIds) {
 | 
			
		||||
            repos.firstOrNull { it.idPrefix == prefix }?.let {
 | 
			
		||||
                val result = it.getStatus(id)
 | 
			
		||||
                if (result is Resource.Success) {
 | 
			
		||||
                    _userDataResponse.postValue(result)
 | 
			
		||||
                    return@launch
 | 
			
		||||
                } else if (result is Resource.Failure) {
 | 
			
		||||
                    lastError = result
 | 
			
		||||
            repos.firstOrNull { it.idPrefix == prefix }?.let { repo ->
 | 
			
		||||
                if(repo.hasAccount()) {
 | 
			
		||||
                    val result = repo.getStatus(id)
 | 
			
		||||
                    if (result is Resource.Success) {
 | 
			
		||||
                        _userDataResponse.postValue(result)
 | 
			
		||||
                        return@launch
 | 
			
		||||
                    } else if (result is Resource.Failure) {
 | 
			
		||||
                        lastError = result
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -183,13 +186,15 @@ class SyncViewModel : ViewModel() {
 | 
			
		|||
        _metaResponse.postValue(Resource.Loading())
 | 
			
		||||
        var lastError: Resource<SyncAPI.SyncResult> = Resource.Failure(false, null, null, "No data")
 | 
			
		||||
        for ((prefix, id) in syncIds) {
 | 
			
		||||
            repos.firstOrNull { it.idPrefix == prefix }?.let {
 | 
			
		||||
                val result = it.getResult(id)
 | 
			
		||||
                if (result is Resource.Success) {
 | 
			
		||||
                    _metaResponse.postValue(result)
 | 
			
		||||
                    return@launch
 | 
			
		||||
                } else if (result is Resource.Failure) {
 | 
			
		||||
                    lastError = result
 | 
			
		||||
            repos.firstOrNull { it.idPrefix == prefix }?.let { repo ->
 | 
			
		||||
                if(repo.hasAccount()) {
 | 
			
		||||
                    val result = repo.getResult(id)
 | 
			
		||||
                    if (result is Resource.Success) {
 | 
			
		||||
                        _metaResponse.postValue(result)
 | 
			
		||||
                        return@launch
 | 
			
		||||
                    } else if (result is Resource.Failure) {
 | 
			
		||||
                        lastError = result
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -352,7 +352,7 @@
 | 
			
		|||
                                    android:layout_height="match_parent">
 | 
			
		||||
 | 
			
		||||
                                <TextView
 | 
			
		||||
                                        android:id="@+id/result_descript"
 | 
			
		||||
                                        android:id="@+id/result_description"
 | 
			
		||||
                                        android:layout_width="match_parent"
 | 
			
		||||
                                        android:layout_height="wrap_content"
 | 
			
		||||
                                        android:foreground="@drawable/outline_drawable"
 | 
			
		||||
| 
						 | 
				
			
			@ -390,7 +390,7 @@
 | 
			
		|||
                            android:minWidth="100dp"
 | 
			
		||||
                            android:nextFocusLeft="@id/result_back"
 | 
			
		||||
                            android:nextFocusRight="@id/result_search"
 | 
			
		||||
                            android:nextFocusUp="@id/result_descript"
 | 
			
		||||
                            android:nextFocusUp="@id/result_description"
 | 
			
		||||
 | 
			
		||||
                            android:nextFocusDown="@id/result_play_movie"
 | 
			
		||||
                            android:paddingTop="0dp"
 | 
			
		||||
| 
						 | 
				
			
			@ -751,7 +751,7 @@
 | 
			
		|||
                                        android:layout_marginStart="0dp"
 | 
			
		||||
                                        android:nextFocusLeft="@id/result_episode_select"
 | 
			
		||||
                                        android:nextFocusRight="@id/result_episode_select"
 | 
			
		||||
                                        android:nextFocusUp="@id/result_descript"
 | 
			
		||||
                                        android:nextFocusUp="@id/result_description"
 | 
			
		||||
                                        android:nextFocusDown="@id/result_episodes"
 | 
			
		||||
                                        android:visibility="gone"
 | 
			
		||||
                                        tools:text="Season 1"
 | 
			
		||||
| 
						 | 
				
			
			@ -766,7 +766,7 @@
 | 
			
		|||
                                        android:nextFocusLeft="@id/result_season_button"
 | 
			
		||||
                                        android:nextFocusRight="@id/result_season_button"
 | 
			
		||||
 | 
			
		||||
                                        android:nextFocusUp="@id/result_descript"
 | 
			
		||||
                                        android:nextFocusUp="@id/result_description"
 | 
			
		||||
                                        android:nextFocusDown="@id/result_episodes"
 | 
			
		||||
                                        android:visibility="gone"
 | 
			
		||||
                                        tools:text="50-100"
 | 
			
		||||
| 
						 | 
				
			
			@ -781,7 +781,7 @@
 | 
			
		|||
                                        android:nextFocusLeft="@id/result_season_button"
 | 
			
		||||
                                        android:nextFocusRight="@id/result_season_button"
 | 
			
		||||
 | 
			
		||||
                                        android:nextFocusUp="@id/result_descript"
 | 
			
		||||
                                        android:nextFocusUp="@id/result_description"
 | 
			
		||||
                                        android:nextFocusDown="@id/result_episodes"
 | 
			
		||||
                                        android:visibility="gone"
 | 
			
		||||
                                        tools:text="Dubbed"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,7 +70,7 @@
 | 
			
		|||
 | 
			
		||||
            <ImageView
 | 
			
		||||
                    android:nextFocusUp="@id/result_back"
 | 
			
		||||
                    android:nextFocusDown="@id/result_descript"
 | 
			
		||||
                    android:nextFocusDown="@id/result_description"
 | 
			
		||||
                    android:nextFocusLeft="@id/result_add_sync"
 | 
			
		||||
                    android:nextFocusRight="@id/result_open_in_browser"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -88,7 +88,7 @@
 | 
			
		|||
 | 
			
		||||
            <ImageView
 | 
			
		||||
                    android:nextFocusUp="@id/result_back"
 | 
			
		||||
                    android:nextFocusDown="@id/result_descript"
 | 
			
		||||
                    android:nextFocusDown="@id/result_description"
 | 
			
		||||
                    android:nextFocusLeft="@id/result_share"
 | 
			
		||||
                    android:nextFocusRight="@id/result_search"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -106,7 +106,7 @@
 | 
			
		|||
 | 
			
		||||
            <ImageView
 | 
			
		||||
                    android:nextFocusUp="@id/result_back"
 | 
			
		||||
                    android:nextFocusDown="@id/result_descript"
 | 
			
		||||
                    android:nextFocusDown="@id/result_description"
 | 
			
		||||
                    android:nextFocusLeft="@id/result_open_in_browser"
 | 
			
		||||
                    android:nextFocusRight="@id/result_recommendations_btt"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -122,9 +122,10 @@
 | 
			
		|||
                    android:contentDescription="@string/result_open_in_browser"
 | 
			
		||||
                    app:tint="?attr/textColor" />
 | 
			
		||||
            <ImageView
 | 
			
		||||
                    tools:visibility="visible"
 | 
			
		||||
                    android:visibility="gone"
 | 
			
		||||
                    android:nextFocusUp="@id/result_back"
 | 
			
		||||
                    android:nextFocusDown="@id/result_descript"
 | 
			
		||||
                    android:nextFocusDown="@id/result_description"
 | 
			
		||||
                    android:nextFocusLeft="@id/result_search"
 | 
			
		||||
                    android:nextFocusRight="@id/result_bookmark_button"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,14 +35,14 @@
 | 
			
		|||
        <item>None</item>
 | 
			
		||||
        <item>Google</item>
 | 
			
		||||
        <item>Cloudflare</item>
 | 
			
		||||
<!--        <item>OpenDns</item>-->
 | 
			
		||||
        <!--        <item>OpenDns</item>-->
 | 
			
		||||
        <item>AdGuard</item>
 | 
			
		||||
    </array>
 | 
			
		||||
    <array name="dns_pref_values">
 | 
			
		||||
        <item>0</item>
 | 
			
		||||
        <item>1</item>
 | 
			
		||||
        <item>2</item>
 | 
			
		||||
<!--        <item>3</item>-->
 | 
			
		||||
        <!--        <item>3</item>-->
 | 
			
		||||
        <item>4</item>
 | 
			
		||||
    </array>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -196,7 +196,7 @@
 | 
			
		|||
        <item>Normal</item>
 | 
			
		||||
        <item>Blue</item>
 | 
			
		||||
        <item>Red</item>
 | 
			
		||||
         <item>Purple</item>
 | 
			
		||||
        <item>Purple</item>
 | 
			
		||||
        <item>Green</item>
 | 
			
		||||
        <item>GreenApple</item>
 | 
			
		||||
        <item>Banana</item>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -401,6 +401,8 @@
 | 
			
		|||
    <string name="sync_total_episodes_none">/??</string>
 | 
			
		||||
    <string name="sync_total_episodes_some" formatted="true">/%d</string>
 | 
			
		||||
    <string name="authenticated_user" formatted="true">Authenticated %s</string>
 | 
			
		||||
    <string name="authenticated_user_fail" formatted="true">Failed to authenticate to %s</string>
 | 
			
		||||
 | 
			
		||||
    <!-- ============ -->
 | 
			
		||||
    <string name="none">None</string>
 | 
			
		||||
    <string name="normal">Normal</string>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue