From 9e434030a4877ad64333e86fac70dfaa6f81c64f Mon Sep 17 00:00:00 2001 From: LagradOst Date: Thu, 17 Jun 2021 18:20:05 +0200 Subject: [PATCH] quick search --- .../com/lagradost/cloudstream3/AllProvider.kt | 44 +++++++++- .../com/lagradost/cloudstream3/MainAPI.kt | 15 ++-- .../animeproviders/DubbedAnimeProvider.kt | 30 +++++++ .../animeproviders/ShiroProvider.kt | 85 +++++++++++++------ .../movieproviders/MeloMovieProvider.kt | 6 ++ .../cloudstream3/mvvm/ArchComponentExt.kt | 23 +++-- .../cloudstream3/ui/search/SearchFragment.kt | 1 + .../cloudstream3/ui/search/SearchViewModel.kt | 17 +++- 8 files changed, 179 insertions(+), 42 deletions(-) create mode 100644 app/src/main/java/com/lagradost/cloudstream3/animeproviders/DubbedAnimeProvider.kt diff --git a/app/src/main/java/com/lagradost/cloudstream3/AllProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/AllProvider.kt index b11b1a1e..f1a5a64e 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/AllProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/AllProvider.kt @@ -1,6 +1,8 @@ package com.lagradost.cloudstream3 import com.lagradost.cloudstream3.APIHolder.apis +import com.lagradost.cloudstream3.mvvm.normalSafeApiCall +import com.lagradost.cloudstream3.mvvm.safeApiCall class AllProvider : MainAPI() { override val name: String @@ -8,11 +10,51 @@ class AllProvider : MainAPI() { var providersActive = HashSet() + override fun quickSearch(query: String): ArrayList? { + val list = apis.filter { a -> + a.name != this.name && (providersActive.size == 0 || providersActive.contains(a.name)) + }.filter { a -> a.hasQuickSearch }.pmap { a -> + normalSafeApiCall { + a.quickSearch(query) + } + } + + var maxCount = 0 + var providerCount = 0 + for (res in list) { + if (res != null) { + if (res.size > maxCount) { + maxCount = res.size + } + providerCount++ + } + } + + println("PROV: " + providerCount + "|" + maxCount) + if (providerCount == 0) return null + if (maxCount == 0) return ArrayList() + + val result = ArrayList() + for (i in 0..maxCount) { + for (res in list) { + if (res != null) { + if (i < res.size) { + result.add(res[i]) + } + } + } + } + + return result + } + override fun search(query: String): ArrayList? { val list = apis.filter { a -> a.name != this.name && (providersActive.size == 0 || providersActive.contains(a.name)) }.pmap { a -> - a.search(query) + normalSafeApiCall { + a.search(query) + } } var maxCount = 0 diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt index a1b839f1..fb51a113 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt @@ -17,6 +17,9 @@ val mapper = JsonMapper.builder().addModule(KotlinModule()) .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).build()!! object APIHolder { + val unixTime: Long + get() = System.currentTimeMillis() / 1000L + val allApi = AllProvider() private const val defProvider = 0 @@ -47,10 +50,15 @@ abstract class MainAPI { open val name = "NONE" open val mainUrl = "NONE" open val instantLinkLoading = false // THIS IS IF THE LINK IS STORED IN THE "DATA" + open val hasQuickSearch = false open fun search(query: String): ArrayList? { // SearchResponse return null } + open fun quickSearch(query: String) : ArrayList? { + return null + } + open fun load(slug: String): Any? { //LoadResponse return null } @@ -74,13 +82,6 @@ fun sortUrls(urls: List): List { return urls.sortedBy { t -> -t.quality } } -data class Link( - val name: String, - val url: String, - val quality: Int?, - val referer: String?, -) - enum class ShowStatus { Completed, Ongoing, diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/DubbedAnimeProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/DubbedAnimeProvider.kt new file mode 100644 index 00000000..c58e6c59 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/DubbedAnimeProvider.kt @@ -0,0 +1,30 @@ +package com.lagradost.cloudstream3.animeproviders + +import com.lagradost.cloudstream3.APIHolder.unixTime +import com.lagradost.cloudstream3.MainAPI +import com.lagradost.cloudstream3.mapper + +class DubbedAnimeProvider : MainAPI() { + override val mainUrl: String + get() = "https://bestdubbedanime.com" + override val name: String + get() = "DubbedAnime" + override val hasQuickSearch: Boolean + get() = true + + override fun quickSearch(query: String): ArrayList? { + val url = "$mainUrl/xz/searchgrid.php?p=1&limit=12&s=$query&_=${unixTime}" + val response = khttp.get(url) + + return super.quickSearch(query) + } + + /* + override fun search(query: String): ArrayList? { + val url = "$mainUrl/search/$query" + + mapper.readValue<>() + + return super.search(query) + }*/ +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ShiroProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ShiroProvider.kt index 03aec126..714058d8 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ShiroProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ShiroProvider.kt @@ -14,7 +14,7 @@ class ShiroProvider : MainAPI() { companion object { var token: String? = null - fun getType(t: String): TvType { + fun getType(t: String?): TvType { return when (t) { "TV" -> TvType.Anime "OVA" -> TvType.ONA @@ -52,14 +52,17 @@ class ShiroProvider : MainAPI() { override val name: String get() = "Shiro" + override val hasQuickSearch: Boolean + get() = true + data class ShiroSearchResponseShow( @JsonProperty("image") val image: String, @JsonProperty("_id") val _id: String, @JsonProperty("slug") val slug: String, @JsonProperty("name") val name: String, - @JsonProperty("episodeCount") val episodeCount: String, - @JsonProperty("language") val language: String, - @JsonProperty("type") val type: String, + @JsonProperty("episodeCount") val episodeCount: String?, + @JsonProperty("language") val language: String?, + @JsonProperty("type") val type: String?, @JsonProperty("year") val year: String?, @JsonProperty("canonicalTitle") val canonicalTitle: String, @JsonProperty("english") val english: String?, @@ -131,6 +134,56 @@ class ShiroProvider : MainAPI() { @JsonProperty("status") val status: String, ) + private fun turnSearchIntoResponse(data: ShiroSearchResponseShow): AnimeSearchResponse { + val type = getType(data.type) + val isDubbed = + if (data.language != null) + data.language == "dubbed" + else + data.slug.contains("dubbed") + val set: EnumSet = EnumSet.noneOf(DubStatus::class.java) + + if (isDubbed) + set.add(DubStatus.Dubbed) + else + set.add(DubStatus.Subbed) + val episodeCount = data.episodeCount?.toIntOrNull() + + return AnimeSearchResponse( + data.name.replace("Dubbed", ""), // i.english ?: i.canonicalTitle, + "$mainUrl/anime/${data.slug}", + data.slug, + this.name, + type, + "https://cdn.shiro.is/${data.image}", + data.year?.toIntOrNull(), + data.canonicalTitle, + set, + if (isDubbed) episodeCount else null, + if (!isDubbed) episodeCount else null, + ) + } + + override fun quickSearch(query: String): ArrayList { + val returnValue: ArrayList = ArrayList() + + val response = khttp.get("https://tapi.shiro.is/anime/auto-complete/${ + URLEncoder.encode( + query, + "UTF-8" + ) + }?token=$token".replace("+", "%20")) + if (response.text == "{\"status\":\"Found\",\"data\":[]}") return returnValue // OR ELSE WILL CAUSE WEIRD ERROR + println("QUICK: " + response.text) + val mapped = response.let { mapper.readValue(it.text) } + println("SIZE: " + mapped.data.size) + println("TOTAL: " + mapped) + for (i in mapped.data) { + returnValue.add(turnSearchIntoResponse(i)) + } + return returnValue + } + override fun search(query: String): ArrayList? { if (!autoLoadToken()) return null val returnValue: ArrayList = ArrayList() @@ -144,29 +197,7 @@ class ShiroProvider : MainAPI() { val mapped = response.let { mapper.readValue(it.text) } for (i in mapped.data.nav.currentPage.items) { - val type = getType(i.type) - val isDubbed = i.language == "dubbed" - val set: EnumSet = EnumSet.noneOf(DubStatus::class.java) - - if (isDubbed) - set.add(DubStatus.Dubbed) - else - set.add(DubStatus.Subbed) - val episodeCount = i.episodeCount.toInt() - - returnValue.add(AnimeSearchResponse( - i.name.replace("Dubbed", ""), // i.english ?: i.canonicalTitle, - "$mainUrl/anime/${i.slug}", - i.slug, - this.name, - type, - "https://cdn.shiro.is/${i.image}", - i.year?.toIntOrNull(), - i.canonicalTitle, - set, - if (isDubbed) episodeCount else null, - if (!isDubbed) episodeCount else null, - )) + returnValue.add(turnSearchIntoResponse(i)) } return returnValue } diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/MeloMovieProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/MeloMovieProvider.kt index c6eea1c4..64791b44 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/MeloMovieProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/MeloMovieProvider.kt @@ -15,6 +15,8 @@ class MeloMovieProvider : MainAPI() { get() = "https://melomovie.com" override val instantLinkLoading: Boolean get() = true + override val hasQuickSearch: Boolean + get() = true data class MeloMovieSearchResult( @JsonProperty("id") val id: Int, @@ -27,6 +29,10 @@ class MeloMovieProvider : MainAPI() { data class MeloMovieLink(val name: String, val link: String) + override fun quickSearch(query: String): ArrayList? { + return search(query) + } + override fun search(query: String): ArrayList? { val url = "$mainUrl/movie/search/?name=$query" val returnValue: ArrayList = ArrayList() diff --git a/app/src/main/java/com/lagradost/cloudstream3/mvvm/ArchComponentExt.kt b/app/src/main/java/com/lagradost/cloudstream3/mvvm/ArchComponentExt.kt index b0db9867..fb8f6ffc 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/mvvm/ArchComponentExt.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/mvvm/ArchComponentExt.kt @@ -29,6 +29,23 @@ sealed class Resource { data class Loading(val url : String? = null) : Resource() } +fun logError(throwable: Throwable) { + Log.d("ApiError", "-------------------------------------------------------------------") + Log.d("ApiError", "safeApiCall: " + throwable.localizedMessage) + Log.d("ApiError", "safeApiCall: " + throwable.message) + throwable.printStackTrace() + Log.d("ApiError", "-------------------------------------------------------------------") +} + +fun normalSafeApiCall(apiCall : () -> T) : T? { + return try { + apiCall.invoke() + } catch (throwable: Throwable) { + logError(throwable) + return null + } +} + suspend fun safeApiCall( apiCall: suspend () -> T, ): Resource { @@ -36,11 +53,7 @@ suspend fun safeApiCall( try { Resource.Success(apiCall.invoke()) } catch (throwable: Throwable) { - Log.d("ApiError", "-------------------------------------------------------------------") - Log.d("ApiError", "safeApiCall: " + throwable.localizedMessage) - Log.d("ApiError", "safeApiCall: " + throwable.message) - throwable.printStackTrace() - Log.d("ApiError", "-------------------------------------------------------------------") + logError(throwable) when (throwable) { /*is HttpException -> { Resource.Failure(false, throwable.code(), throwable.response()?.errorBody(), throwable.localizedMessage) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchFragment.kt index 6b5d6027..e656fc4b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchFragment.kt @@ -119,6 +119,7 @@ class SearchFragment : Fragment() { } override fun onQueryTextChange(newText: String): Boolean { + searchViewModel.quickSearch(newText) return true } }) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchViewModel.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchViewModel.kt index d2dc1077..1e0304b9 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchViewModel.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchViewModel.kt @@ -5,8 +5,6 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.lagradost.cloudstream3.APIHolder.allApi -import com.lagradost.cloudstream3.APIHolder.apis -import com.lagradost.cloudstream3.MainAPI import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.safeApiCall import kotlinx.coroutines.launch @@ -14,13 +12,28 @@ import kotlinx.coroutines.launch class SearchViewModel : ViewModel() { private val _searchResponse: MutableLiveData>> = MutableLiveData() val searchResponse: LiveData>> get() = _searchResponse + var searchCounter = 0 fun search(query: String) = viewModelScope.launch { + searchCounter++ + val localSearchCounter = searchCounter _searchResponse.postValue(Resource.Loading()) val data = safeApiCall { allApi.search(query) } + if(localSearchCounter != searchCounter) return@launch + _searchResponse.postValue(data as Resource>?) + } + fun quickSearch(query: String) = viewModelScope.launch { + searchCounter++ + val localSearchCounter = searchCounter + _searchResponse.postValue(Resource.Loading()) + val data = safeApiCall { + allApi.quickSearch(query) + } + + if(localSearchCounter != searchCounter) return@launch _searchResponse.postValue(data as Resource>?) } } \ No newline at end of file