api stuff

This commit is contained in:
LagradOst 2021-05-16 20:28:00 +02:00
parent 22f2a8810e
commit 0fa16e3bbc
8 changed files with 228 additions and 94 deletions

View file

@ -143,6 +143,8 @@ interface LoadResponse {
} }
data class AnimeLoadResponse( data class AnimeLoadResponse(
val engName: String?,
val japName: String?,
override val name: String, override val name: String,
override val url: String, override val url: String,
override val apiName: String, override val apiName: String,
@ -151,9 +153,8 @@ data class AnimeLoadResponse(
override val posterUrl: String?, override val posterUrl: String?,
override val year: Int?, override val year: Int?,
val dubEpisodes: ArrayList<String>?, val dubEpisodes: ArrayList<Any>?,
val subEpisodes: ArrayList<String>?, val subEpisodes: ArrayList<Any>?,
val otherName: String?,
val showStatus: ShowStatus?, val showStatus: ShowStatus?,
val tags: ArrayList<String>?, val tags: ArrayList<String>?,

View file

@ -5,11 +5,21 @@ import com.fasterxml.jackson.module.kotlin.readValue
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import java.net.URLEncoder import java.net.URLEncoder
import java.util.* import java.util.*
import kotlin.collections.ArrayList
class ShiroProvider : MainAPI() { class ShiroProvider : MainAPI() {
companion object { companion object {
var token: String? = null var token: String? = null
fun getType(t: String): TvType {
return when (t) {
"TV" -> TvType.Anime
"OVA" -> TvType.ONA
"movie" -> TvType.Movie
else -> TvType.Anime
}
}
} }
fun autoLoadToken(): Boolean { fun autoLoadToken(): Boolean {
@ -45,7 +55,7 @@ class ShiroProvider : MainAPI() {
@JsonProperty("episodeCount") val episodeCount: String, @JsonProperty("episodeCount") val episodeCount: String,
@JsonProperty("language") val language: String, @JsonProperty("language") val language: String,
@JsonProperty("type") val type: String, @JsonProperty("type") val type: String,
@JsonProperty("year") val year: String, @JsonProperty("year") val year: String?,
@JsonProperty("canonicalTitle") val canonicalTitle: String, @JsonProperty("canonicalTitle") val canonicalTitle: String,
@JsonProperty("english") val english: String?, @JsonProperty("english") val english: String?,
) )
@ -72,51 +82,121 @@ class ShiroProvider : MainAPI() {
@JsonProperty("status") val status: String, @JsonProperty("status") val status: String,
) )
data class ShiroVideo(
@JsonProperty("video_id") val video_id: String,
@JsonProperty("host") val host: String,
)
data class ShiroEpisodes(
@JsonProperty("anime") val anime: AnimePageData?,
@JsonProperty("anime_slug") val anime_slug: String,
@JsonProperty("create") val create: String,
@JsonProperty("dayOfTheWeek") val dayOfTheWeek: String,
@JsonProperty("episode_number") val episode_number: Int,
@JsonProperty("slug") val slug: String,
@JsonProperty("update") val update: String,
@JsonProperty("_id") val _id: String,
@JsonProperty("videos") val videos: List<ShiroVideo>,
)
data class AnimePageData(
@JsonProperty("banner") val banner: String?,
@JsonProperty("canonicalTitle") val canonicalTitle: String?,
@JsonProperty("episodeCount") val episodeCount: String,
@JsonProperty("genres") val genres: List<String>?,
@JsonProperty("image") val image: String,
@JsonProperty("japanese") val japanese: String?,
@JsonProperty("english") val english: String?,
@JsonProperty("language") val language: String,
@JsonProperty("name") val name: String,
@JsonProperty("slug") val slug: String,
@JsonProperty("synopsis") val synopsis: String,
@JsonProperty("type") val type: String?,
@JsonProperty("views") val views: Int?,
@JsonProperty("year") val year: String?,
@JsonProperty("_id") val _id: String,
@JsonProperty("episodes") var episodes: List<ShiroEpisodes>?,
@JsonProperty("synonyms") var synonyms: List<String>?,
@JsonProperty("status") val status: String?,
@JsonProperty("schedule") val schedule: String?,
)
data class AnimePage(
@JsonProperty("data") val data: AnimePageData,
@JsonProperty("status") val status: String,
)
override fun search(query: String): ArrayList<Any>? { override fun search(query: String): ArrayList<Any>? {
try { if (!autoLoadToken()) return null
if (!autoLoadToken()) return null val returnValue: ArrayList<Any> = ArrayList()
val returnValue: ArrayList<Any> = ArrayList() val response = khttp.get("https://tapi.shiro.is/advanced?search=${
val response = khttp.get("https://tapi.shiro.is/advanced?search=${ URLEncoder.encode(
URLEncoder.encode( query,
query, "UTF-8"
"UTF-8" )
) }&token=$token".replace("+", "%20"))
}&token=$token".replace("+", "%20")) if (response.text == "{\"status\":\"Found\",\"data\":[]}") return returnValue // OR ELSE WILL CAUSE WEIRD ERROR
println(response.text)
val mapped = response.let { mapper.readValue<ShiroFullSearchResponse>(it.text) }
for (i in mapped.data.nav.currentPage.items) {
val type = when (i.type) { val mapped = response.let { mapper.readValue<ShiroFullSearchResponse>(it.text) }
"TV" -> TvType.Anime for (i in mapped.data.nav.currentPage.items) {
"OVA" -> TvType.ONA val type = getType(i.type)
"movie" -> TvType.Movie val isDubbed = i.language == "dubbed"
else -> TvType.Anime val set: EnumSet<DubStatus> = EnumSet.noneOf(DubStatus::class.java)
}
val isDubbed = i.language == "dubbed"
val set: EnumSet<DubStatus> = EnumSet.noneOf(DubStatus::class.java)
if (isDubbed) if (isDubbed)
set.add(DubStatus.HasDub) set.add(DubStatus.HasDub)
else else
set.add(DubStatus.HasSub) set.add(DubStatus.HasSub)
val episodeCount = i.episodeCount.toInt() val episodeCount = i.episodeCount.toInt()
returnValue.add(AnimeSearchResponse( returnValue.add(AnimeSearchResponse(
i.english ?: i.canonicalTitle, i.english ?: i.canonicalTitle,
"$mainUrl/${i.slug}", "$mainUrl/${i.slug}",
this.name, this.name,
type, type,
"https://cdn.shiro.is/${i.image}", "https://cdn.shiro.is/${i.image}",
i.year.toInt(), i.year?.toIntOrNull(),
i.canonicalTitle, i.canonicalTitle,
set, set,
if (isDubbed) episodeCount else null, if (isDubbed) episodeCount else null,
if (!isDubbed) episodeCount else null, if (!isDubbed) episodeCount else null,
)) ))
}
return returnValue
} catch (e: Exception) {
return null
} }
return returnValue
}
override fun load(url: String): Any? {
if (!autoLoadToken()) return null
val rurl = "https://tapi.shiro.is/anime/slug/${url}?token=${token}"
val response = khttp.get(rurl, timeout = 120.0)
val mapped = response.let { mapper.readValue<AnimePage>(it.text) }
val data = mapped.data
val isDubbed = data.language == "dubbed"
val episodes = ArrayList<Any>(data.episodes ?: ArrayList())
val status = when (data.status) {
"current" -> ShowStatus.Ongoing
"finished" -> ShowStatus.Completed
else -> null
}
return AnimeLoadResponse(
data.english,
data.japanese,
data.canonicalTitle ?: data.name.replace("Dubbed", ""),
url,
this.name,
getType(data.type ?: ""),
"https://cdn.shiro.is/${data.image}",
data.year?.toIntOrNull(),
if (isDubbed) episodes else null,
if (!isDubbed) episodes else null,
status,
ArrayList(data.genres ?: ArrayList()),
data.synopsis,
ArrayList(data.synonyms ?: ArrayList()),
null,
null,
)
} }
} }

View file

@ -0,0 +1,29 @@
package com.lagradost.cloudstream3.ui.result
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.lagradost.cloudstream3.R
class ResultFragment : Fragment() {
private lateinit var viewModel: ResultViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
viewModel =
ViewModelProvider(this).get(ResultViewModel::class.java)
return inflater.inflate(R.layout.fragment_result, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
}

View file

@ -0,0 +1,7 @@
package com.lagradost.cloudstream3.ui.result
import androidx.lifecycle.ViewModel
class ResultViewModel : ViewModel() {
}

View file

@ -1,18 +1,15 @@
package com.lagradost.cloudstream3.ui.search package com.lagradost.cloudstream3.ui.search
import android.content.DialogInterface
import android.content.res.Configuration import android.content.res.Configuration
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@ -22,8 +19,9 @@ import com.lagradost.cloudstream3.APIHolder.getApiSettings
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.UIHelper.fixPaddingStatusbar import com.lagradost.cloudstream3.UIHelper.fixPaddingStatusbar
import com.lagradost.cloudstream3.UIHelper.getGridIsCompact import com.lagradost.cloudstream3.UIHelper.getGridIsCompact
import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.observe
import kotlinx.android.synthetic.main.fragment_search.* import kotlinx.android.synthetic.main.fragment_search.*
import kotlin.concurrent.thread
class SearchFragment : Fragment() { class SearchFragment : Fragment() {
@ -106,19 +104,7 @@ class SearchFragment : Fragment() {
override fun onQueryTextSubmit(query: String): Boolean { override fun onQueryTextSubmit(query: String): Boolean {
search_exit_icon.alpha = 0f search_exit_icon.alpha = 0f
search_loading_bar.alpha = 1f search_loading_bar.alpha = 1f
thread { searchViewModel.search(query)
val data = allApi.search(query)//MainActivity.activeAPI.search(query)
activity?.runOnUiThread {
if (data == null) {
Toast.makeText(activity, "Server error", Toast.LENGTH_LONG).show()
} else {
(cardSpace.adapter as SearchAdapter).cardList = data
(cardSpace.adapter as SearchAdapter).notifyDataSetChanged()
}
search_exit_icon.alpha = 1f
search_loading_bar.alpha = 0f
}
}
return true return true
} }
@ -127,6 +113,20 @@ class SearchFragment : Fragment() {
} }
}) })
observe(searchViewModel.searchResponse) {
when (it) {
is Resource.Success -> {
(cardSpace.adapter as SearchAdapter).cardList = it.value
(cardSpace.adapter as SearchAdapter).notifyDataSetChanged()
}
is Resource.Failure -> {
Toast.makeText(activity, "Server error", Toast.LENGTH_LONG).show()
}
}
search_exit_icon.alpha = 1f
search_loading_bar.alpha = 0f
}
main_search.onActionViewExpanded() main_search.onActionViewExpanded()
} }

View file

@ -3,20 +3,24 @@ package com.lagradost.cloudstream3.ui.search
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.lagradost.cloudstream3.APIHolder.apis import com.lagradost.cloudstream3.APIHolder.apis
import com.lagradost.cloudstream3.MainAPI import com.lagradost.cloudstream3.MainAPI
import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.safeApiCall import com.lagradost.cloudstream3.mvvm.safeApiCall
import kotlinx.coroutines.launch
class SearchViewModel : ViewModel() { class SearchViewModel : ViewModel() {
val api: MainAPI = apis[0]
private val _text = MutableLiveData<String>().apply { private val _searchResponse: MutableLiveData<Resource<ArrayList<Any>>> = MutableLiveData()
value = "This is dashboard Fragment" val searchResponse: LiveData<Resource<ArrayList<Any>>> get() = _searchResponse
}
val text: LiveData<String> = _text
val api : MainAPI = apis[0] fun search(query: String) = viewModelScope.launch {
val data = safeApiCall {
api.search(query)
}
suspend fun search(query: String) = safeApiCall { _searchResponse.postValue(data as Resource<ArrayList<Any>>?)
api.search(query)
} }
} }

View file

@ -1,35 +1,42 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout <FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/container" android:id="@+id/container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
android:paddingTop="0dp"> android:paddingTop="0dp">
<FrameLayout
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="@color/darkBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="@menu/bottom_nav_menu"/>
<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:defaultNavHost="true" android:id="@+id/homeRoot"
app:layout_constraintBottom_toTopOf="@id/nav_view" >
app:layout_constraintLeft_toLeftOf="parent" <androidx.constraintlayout.widget.ConstraintLayout android:layout_height="match_parent"
app:layout_constraintRight_toRightOf="parent" android:layout_width="match_parent">
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/mobile_navigation"
/>
</androidx.constraintlayout.widget.ConstraintLayout> <com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/darkBackground"
app:itemRippleColor="@color/colorRipple"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="@menu/bottom_nav_menu"
app:layout_constraintBottom_toBottomOf="parent"/>
<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="@+id/nav_view"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/mobile_navigation"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>
</FrameLayout>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.constraintlayout.widget.ConstraintLayout>