mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
quick search
This commit is contained in:
parent
850be93a8b
commit
9e434030a4
8 changed files with 179 additions and 42 deletions
|
@ -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<String>()
|
||||
|
||||
override fun quickSearch(query: String): ArrayList<Any>? {
|
||||
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<Any>()
|
||||
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<Any>? {
|
||||
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
|
||||
|
|
|
@ -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<Any>? { // SearchResponse
|
||||
return null
|
||||
}
|
||||
|
||||
open fun quickSearch(query: String) : ArrayList<Any>? {
|
||||
return null
|
||||
}
|
||||
|
||||
open fun load(slug: String): Any? { //LoadResponse
|
||||
return null
|
||||
}
|
||||
|
@ -74,13 +82,6 @@ fun sortUrls(urls: List<ExtractorLink>): List<ExtractorLink> {
|
|||
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,
|
||||
|
|
|
@ -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<Any>? {
|
||||
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<Any>? {
|
||||
val url = "$mainUrl/search/$query"
|
||||
|
||||
mapper.readValue<>()
|
||||
|
||||
return super.search(query)
|
||||
}*/
|
||||
}
|
|
@ -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<DubStatus> = 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<Any> {
|
||||
val returnValue: ArrayList<Any> = 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<ShiroSearchResponse>(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<Any>? {
|
||||
if (!autoLoadToken()) return null
|
||||
val returnValue: ArrayList<Any> = ArrayList()
|
||||
|
@ -144,29 +197,7 @@ class ShiroProvider : MainAPI() {
|
|||
|
||||
val mapped = response.let { mapper.readValue<ShiroFullSearchResponse>(it.text) }
|
||||
for (i in mapped.data.nav.currentPage.items) {
|
||||
val type = getType(i.type)
|
||||
val isDubbed = i.language == "dubbed"
|
||||
val set: EnumSet<DubStatus> = 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
|
||||
}
|
||||
|
|
|
@ -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<Any>? {
|
||||
return search(query)
|
||||
}
|
||||
|
||||
override fun search(query: String): ArrayList<Any>? {
|
||||
val url = "$mainUrl/movie/search/?name=$query"
|
||||
val returnValue: ArrayList<Any> = ArrayList()
|
||||
|
|
|
@ -29,6 +29,23 @@ sealed class Resource<out T> {
|
|||
data class Loading(val url : String? = null) : Resource<Nothing>()
|
||||
}
|
||||
|
||||
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<T> normalSafeApiCall(apiCall : () -> T) : T? {
|
||||
return try {
|
||||
apiCall.invoke()
|
||||
} catch (throwable: Throwable) {
|
||||
logError(throwable)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun <T> safeApiCall(
|
||||
apiCall: suspend () -> T,
|
||||
): Resource<T> {
|
||||
|
@ -36,11 +53,7 @@ suspend fun <T> 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)
|
||||
|
|
|
@ -119,6 +119,7 @@ class SearchFragment : Fragment() {
|
|||
}
|
||||
|
||||
override fun onQueryTextChange(newText: String): Boolean {
|
||||
searchViewModel.quickSearch(newText)
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
|
|
@ -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<Resource<ArrayList<Any>>> = MutableLiveData()
|
||||
val searchResponse: LiveData<Resource<ArrayList<Any>>> 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<ArrayList<Any>>?)
|
||||
}
|
||||
|
||||
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<ArrayList<Any>>?)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue