forked from recloudstream/cloudstream
dubbedanime provider
This commit is contained in:
parent
9e434030a4
commit
9e67291a8f
8 changed files with 221 additions and 36 deletions
|
@ -5,6 +5,7 @@ import androidx.preference.PreferenceManager
|
|||
import com.fasterxml.jackson.databind.DeserializationFeature
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper
|
||||
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
||||
import com.lagradost.cloudstream3.animeproviders.DubbedAnimeProvider
|
||||
import com.lagradost.cloudstream3.animeproviders.ShiroProvider
|
||||
import com.lagradost.cloudstream3.movieproviders.MeloMovieProvider
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
|
@ -27,6 +28,7 @@ object APIHolder {
|
|||
val apis = arrayListOf(
|
||||
ShiroProvider(),
|
||||
MeloMovieProvider(),
|
||||
DubbedAnimeProvider(),
|
||||
)
|
||||
|
||||
fun getApiFromName(apiName: String?): MainAPI {
|
||||
|
@ -70,12 +72,20 @@ abstract class MainAPI {
|
|||
}
|
||||
|
||||
fun MainAPI.fixUrl(url: String): String {
|
||||
if (url.startsWith('/')) {
|
||||
if(url.startsWith("http")) {
|
||||
return url
|
||||
}
|
||||
|
||||
val startsWithNoHttp = url.startsWith("//")
|
||||
if(startsWithNoHttp) {
|
||||
return "https:$url"
|
||||
}
|
||||
else {
|
||||
if(url.startsWith('/')) {
|
||||
return mainUrl + url
|
||||
} else if (!url.startsWith("http") && !url.startsWith("//")) {
|
||||
}
|
||||
return "$mainUrl/$url"
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
fun sortUrls(urls: List<ExtractorLink>): List<ExtractorLink> {
|
||||
|
@ -168,6 +178,8 @@ fun LoadResponse?.isAnimeBased(): Boolean {
|
|||
return (this.type == TvType.Anime || this.type == TvType.ONA) // && (this is AnimeLoadResponse)
|
||||
}
|
||||
|
||||
data class AnimeEpisode(val url: String, val name : String? = null)
|
||||
|
||||
data class AnimeLoadResponse(
|
||||
val engName: String?,
|
||||
val japName: String?,
|
||||
|
@ -179,16 +191,16 @@ data class AnimeLoadResponse(
|
|||
override val posterUrl: String?,
|
||||
override val year: Int?,
|
||||
|
||||
val dubEpisodes: ArrayList<String>?,
|
||||
val subEpisodes: ArrayList<String>?,
|
||||
val dubEpisodes: ArrayList<AnimeEpisode>?,
|
||||
val subEpisodes: ArrayList<AnimeEpisode>?,
|
||||
val showStatus: ShowStatus?,
|
||||
|
||||
override val plot: String?,
|
||||
val tags: ArrayList<String>?,
|
||||
val synonyms: ArrayList<String>?,
|
||||
val tags: ArrayList<String>? = null,
|
||||
val synonyms: ArrayList<String>? = null,
|
||||
|
||||
val malId: Int?,
|
||||
val anilistId: Int?,
|
||||
val malId: Int? = null,
|
||||
val anilistId: Int? = null,
|
||||
) : LoadResponse
|
||||
|
||||
data class MovieLoadResponse(
|
||||
|
@ -196,7 +208,7 @@ data class MovieLoadResponse(
|
|||
override val url: String,
|
||||
override val apiName: String,
|
||||
override val type: TvType,
|
||||
val movieUrl: String,
|
||||
val dataUrl: String,
|
||||
|
||||
override val posterUrl: String?,
|
||||
override val year: Int?,
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
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.APIHolder.unixTime
|
||||
import com.lagradost.cloudstream3.MainAPI
|
||||
import com.lagradost.cloudstream3.mapper
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
import org.jsoup.Jsoup
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
|
||||
class DubbedAnimeProvider : MainAPI() {
|
||||
override val mainUrl: String
|
||||
|
@ -12,19 +19,187 @@ class DubbedAnimeProvider : MainAPI() {
|
|||
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)
|
||||
data class QueryEpisodeResultRoot(
|
||||
@JsonProperty("result")
|
||||
val result: QueryEpisodeResult,
|
||||
)
|
||||
|
||||
return super.quickSearch(query)
|
||||
}
|
||||
data class QueryEpisodeResult(
|
||||
@JsonProperty("anime") val anime: List<EpisodeInfo>,
|
||||
@JsonProperty("error") val error: Boolean,
|
||||
@JsonProperty("errorMSG") val errorMSG: String?,
|
||||
)
|
||||
|
||||
data class EpisodeInfo(
|
||||
@JsonProperty("serversHTML") val serversHTML: String,
|
||||
@JsonProperty("title") val title: String,
|
||||
@JsonProperty("preview_img") val previewImg: String?,
|
||||
@JsonProperty("wideImg") val wideImg: String?,
|
||||
@JsonProperty("year") val year: String?,
|
||||
@JsonProperty("desc") val desc: String?,
|
||||
|
||||
/*
|
||||
override fun search(query: String): ArrayList<Any>? {
|
||||
@JsonProperty("rowid") val rowid: String,
|
||||
@JsonProperty("status") val status: String,
|
||||
@JsonProperty("skips") val skips: String,
|
||||
@JsonProperty("totalEp") val totalEp: Long,
|
||||
@JsonProperty("ep") val ep: String,
|
||||
@JsonProperty("NextEp") val nextEp: Long,
|
||||
@JsonProperty("slug") val slug: String,
|
||||
@JsonProperty("showid") val showid: String,
|
||||
@JsonProperty("Epviews") val epviews: String,
|
||||
@JsonProperty("TotalViews") val totalViews: String,
|
||||
@JsonProperty("tags") val tags: String,*/
|
||||
)
|
||||
|
||||
private fun getAnimeEpisode(slug: String, isMovie: Boolean): EpisodeInfo {
|
||||
val url =
|
||||
mainUrl + (if (isMovie) "/movies/jsonMovie" else "/xz/v3/jsonEpi") + ".php?slug=$slug&_=$unixTime"
|
||||
val response = khttp.get(url)
|
||||
val mapped = response.let { mapper.readValue<QueryEpisodeResultRoot>(it.text) }
|
||||
|
||||
return mapped.result.anime.first()
|
||||
}
|
||||
|
||||
|
||||
private fun getIsMovie(href: String): Boolean {
|
||||
return href.contains("movies/")
|
||||
}
|
||||
|
||||
private fun getSlug(href: String): String {
|
||||
return href.replace("$mainUrl/", "")
|
||||
}
|
||||
|
||||
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)
|
||||
val document = Jsoup.parse(response.text)
|
||||
val items = document.select("div.grid__item > a")
|
||||
if (items.isEmpty()) return ArrayList()
|
||||
val returnValue = ArrayList<Any>()
|
||||
for (i in items) {
|
||||
val href = fixUrl(i.attr("href"))
|
||||
val title = i.selectFirst("div.gridtitlek").text()
|
||||
val img = fixUrl(i.selectFirst("img.grid__img").attr("src"))
|
||||
returnValue.add(
|
||||
if (getIsMovie(href)) {
|
||||
MovieSearchResponse(
|
||||
title, href, getSlug(href), this.name, TvType.Movie, img, null
|
||||
)
|
||||
} else {
|
||||
AnimeSearchResponse(title,
|
||||
href,
|
||||
getSlug(href),
|
||||
this.name,
|
||||
TvType.Anime,
|
||||
img,
|
||||
null,
|
||||
null,
|
||||
EnumSet.of(DubStatus.Dubbed),
|
||||
null,
|
||||
null)
|
||||
})
|
||||
}
|
||||
return returnValue
|
||||
}
|
||||
|
||||
override fun search(query: String): ArrayList<Any> {
|
||||
val url = "$mainUrl/search/$query"
|
||||
val response = khttp.get(url)
|
||||
val document = Jsoup.parse(response.text)
|
||||
val items = document.select("div.resultinner > a.resulta")
|
||||
if (items.isEmpty()) return ArrayList()
|
||||
val returnValue = ArrayList<Any>()
|
||||
for (i in items) {
|
||||
val innerDiv = i.selectFirst("> div.result")
|
||||
val href = fixUrl(i.attr("href"))
|
||||
val img = fixUrl(innerDiv.selectFirst("> div.imgkz > img").attr("src"))
|
||||
val title = innerDiv.selectFirst("> div.titleresults").text()
|
||||
|
||||
mapper.readValue<>()
|
||||
returnValue.add(
|
||||
if (getIsMovie(href)) {
|
||||
MovieSearchResponse(
|
||||
title, href, getSlug(href), this.name, TvType.Movie, img, null
|
||||
)
|
||||
} else {
|
||||
AnimeSearchResponse(title,
|
||||
href,
|
||||
getSlug(href),
|
||||
this.name,
|
||||
TvType.Anime,
|
||||
img,
|
||||
null,
|
||||
null,
|
||||
EnumSet.of(DubStatus.Dubbed),
|
||||
null,
|
||||
null)
|
||||
})
|
||||
}
|
||||
|
||||
return super.search(query)
|
||||
}*/
|
||||
return returnValue
|
||||
}
|
||||
|
||||
override fun loadLinks(data: String, isCasting: Boolean, callback: (ExtractorLink) -> Unit): Boolean {
|
||||
val serversHTML = (if (data.startsWith(mainUrl)) { // CLASSIC EPISODE
|
||||
val slug = getSlug(data)
|
||||
getAnimeEpisode(slug, false).serversHTML
|
||||
} else data).replace("\\", "")
|
||||
|
||||
val hls = ArrayList("hl=\"(.*?)\"".toRegex().findAll(serversHTML).map {
|
||||
it.groupValues[1]
|
||||
}.toList())
|
||||
for (hl in hls) {
|
||||
try {
|
||||
val sources = khttp.get("$mainUrl/xz/api/playeri.php?url=$hl&_=$unixTime")
|
||||
val txt = sources.text
|
||||
val find = "src=\"(.*?)\".*?label=\"(.*?)\"".toRegex().find(txt)
|
||||
if (find != null) {
|
||||
val quality = find.groupValues[2]
|
||||
callback.invoke(ExtractorLink(this.name,
|
||||
this.name + " " + quality + if (quality.endsWith('p')) "" else 'p',
|
||||
fixUrl(find.groupValues[1]),
|
||||
this.mainUrl,
|
||||
getQualityFromName(quality)))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun load(slug: String): Any {
|
||||
if (getIsMovie(slug)) {
|
||||
val realSlug = slug.replace("movies/", "")
|
||||
val episode = getAnimeEpisode(realSlug, true)
|
||||
val poster = episode.previewImg ?: episode.wideImg
|
||||
return MovieLoadResponse(episode.title,
|
||||
realSlug,
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
episode.serversHTML,
|
||||
if (poster == null) null else fixUrl(poster),
|
||||
episode.year?.toIntOrNull(),
|
||||
episode.desc,
|
||||
null)
|
||||
} else {
|
||||
val response = khttp.get("$mainUrl/$slug")
|
||||
val document = Jsoup.parse(response.text)
|
||||
val title = document.selectFirst("h4").text()
|
||||
val descriptHeader = document.selectFirst("div.animeDescript")
|
||||
val descript = descriptHeader.selectFirst("> p").text()
|
||||
val year = descriptHeader.selectFirst("> div.distatsx > div.sroverd").text().replace("Released: ", "")
|
||||
.toIntOrNull()
|
||||
|
||||
val episodes = document.select("a.epibloks").map {
|
||||
val epTitle = it.selectFirst("> div.inwel > span.isgrxx")?.text()
|
||||
AnimeEpisode(fixUrl(it.attr("href")), epTitle)
|
||||
}
|
||||
|
||||
val img = fixUrl(document.select("div.fkimgs > img").attr("src"))
|
||||
return AnimeLoadResponse(
|
||||
null, null, title, slug, this.name, TvType.Anime, img, year, ArrayList(episodes), null, null, descript,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -209,7 +209,8 @@ class ShiroProvider : MainAPI() {
|
|||
val mapped = response.let { mapper.readValue<AnimePage>(it.text) }
|
||||
val data = mapped.data
|
||||
val isDubbed = data.language == "dubbed"
|
||||
val episodes = ArrayList<String>(data.episodes?.map { it.videos[0].video_id } ?: ArrayList<String>())
|
||||
val episodes = ArrayList<AnimeEpisode>(data.episodes?.map { AnimeEpisode(it.videos[0].video_id) }
|
||||
?: ArrayList<AnimeEpisode>())
|
||||
val status = when (data.status) {
|
||||
"current" -> ShowStatus.Ongoing
|
||||
"finished" -> ShowStatus.Completed
|
||||
|
|
|
@ -3,9 +3,10 @@ package com.lagradost.cloudstream3.ui
|
|||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.View.*
|
||||
import android.widget.*
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContentProviderCompat.requireContext
|
||||
import android.widget.AbsListView
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.ImageView
|
||||
import android.widget.ListView
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper
|
||||
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
||||
|
@ -15,13 +16,10 @@ import com.google.android.gms.cast.framework.CastButtonFactory
|
|||
import com.google.android.gms.cast.framework.CastSession
|
||||
import com.google.android.gms.cast.framework.media.RemoteMediaClient
|
||||
import com.google.android.gms.cast.framework.media.uicontroller.UIController
|
||||
import com.google.android.gms.cast.framework.media.widget.CastSeekBar
|
||||
import com.google.android.gms.cast.framework.media.widget.ExpandedControllerActivity
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.lagradost.cloudstream3.APIHolder.getApiFromName
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.UIHelper
|
||||
import com.lagradost.cloudstream3.UIHelper.colorFromAttribute
|
||||
import com.lagradost.cloudstream3.mvvm.Resource
|
||||
import com.lagradost.cloudstream3.mvvm.safeApiCall
|
||||
import com.lagradost.cloudstream3.sortUrls
|
||||
|
|
|
@ -1129,7 +1129,7 @@ class PlayerFragment : Fragment() {
|
|||
|
||||
changeSkip()
|
||||
|
||||
initPlayer()
|
||||
// initPlayer()
|
||||
}
|
||||
|
||||
private fun getCurrentUrl(): ExtractorLink? {
|
||||
|
|
|
@ -86,11 +86,11 @@ class ResultViewModel : ViewModel() {
|
|||
val episodes = ArrayList<ResultEpisode>()
|
||||
for ((index, i) in dataList.withIndex()) {
|
||||
episodes.add(context.buildResultEpisode(
|
||||
null, // TODO ADD NAMES
|
||||
i.name,
|
||||
null,
|
||||
index + 1, //TODO MAKE ABLE TO NOT HAVE SOME EPISODE
|
||||
null, // TODO FIX SEASON
|
||||
i,
|
||||
i.url,
|
||||
apiName,
|
||||
(mainId + index + 1),
|
||||
index,
|
||||
|
@ -122,7 +122,7 @@ class ResultViewModel : ViewModel() {
|
|||
null,
|
||||
null,
|
||||
0, null,
|
||||
d.movieUrl,
|
||||
d.dataUrl,
|
||||
d.apiName,
|
||||
(mainId + 1),
|
||||
0,
|
||||
|
|
|
@ -148,7 +148,7 @@ class SearchFragment : Fragment() {
|
|||
allApi.providersActive = requireActivity().getApiSettings()
|
||||
|
||||
//searchViewModel.search("iron man")
|
||||
(activity as AppCompatActivity).loadResult("https://shiro.is/overlord-dubbed", "overlord-dubbed", "Shiro")
|
||||
//(activity as AppCompatActivity).loadResult("https://shiro.is/overlord-dubbed", "overlord-dubbed", "Shiro")
|
||||
/*
|
||||
(requireActivity() as AppCompatActivity).supportFragmentManager.beginTransaction()
|
||||
.setCustomAnimations(R.anim.enter_anim,
|
||||
|
|
|
@ -28,8 +28,7 @@ class Vidstream {
|
|||
with(khttp.get(url)) {
|
||||
val document = Jsoup.parse(this.text)
|
||||
val primaryLinks = document.select("ul.list-server-items > li.linkserver")
|
||||
val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
||||
|
||||
//val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
||||
|
||||
// All vidstream links passed to extractors
|
||||
primaryLinks.forEach { element ->
|
||||
|
|
Loading…
Reference in a new issue