dubbedanime provider

This commit is contained in:
LagradOst 2021-06-23 20:33:47 +02:00
parent 9e434030a4
commit 9e67291a8f
8 changed files with 221 additions and 36 deletions

View file

@ -5,6 +5,7 @@ import androidx.preference.PreferenceManager
import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.databind.json.JsonMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule import com.fasterxml.jackson.module.kotlin.KotlinModule
import com.lagradost.cloudstream3.animeproviders.DubbedAnimeProvider
import com.lagradost.cloudstream3.animeproviders.ShiroProvider import com.lagradost.cloudstream3.animeproviders.ShiroProvider
import com.lagradost.cloudstream3.movieproviders.MeloMovieProvider import com.lagradost.cloudstream3.movieproviders.MeloMovieProvider
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
@ -27,6 +28,7 @@ object APIHolder {
val apis = arrayListOf( val apis = arrayListOf(
ShiroProvider(), ShiroProvider(),
MeloMovieProvider(), MeloMovieProvider(),
DubbedAnimeProvider(),
) )
fun getApiFromName(apiName: String?): MainAPI { fun getApiFromName(apiName: String?): MainAPI {
@ -70,12 +72,20 @@ abstract class MainAPI {
} }
fun MainAPI.fixUrl(url: String): String { 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 return mainUrl + url
} else if (!url.startsWith("http") && !url.startsWith("//")) { }
return "$mainUrl/$url" return "$mainUrl/$url"
} }
return url
} }
fun sortUrls(urls: List<ExtractorLink>): List<ExtractorLink> { 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) 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( data class AnimeLoadResponse(
val engName: String?, val engName: String?,
val japName: String?, val japName: String?,
@ -179,16 +191,16 @@ 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<AnimeEpisode>?,
val subEpisodes: ArrayList<String>?, val subEpisodes: ArrayList<AnimeEpisode>?,
val showStatus: ShowStatus?, val showStatus: ShowStatus?,
override val plot: String?, override val plot: String?,
val tags: ArrayList<String>?, val tags: ArrayList<String>? = null,
val synonyms: ArrayList<String>?, val synonyms: ArrayList<String>? = null,
val malId: Int?, val malId: Int? = null,
val anilistId: Int?, val anilistId: Int? = null,
) : LoadResponse ) : LoadResponse
data class MovieLoadResponse( data class MovieLoadResponse(
@ -196,7 +208,7 @@ data class MovieLoadResponse(
override val url: String, override val url: String,
override val apiName: String, override val apiName: String,
override val type: TvType, override val type: TvType,
val movieUrl: String, val dataUrl: String,
override val posterUrl: String?, override val posterUrl: String?,
override val year: Int?, override val year: Int?,

View file

@ -1,8 +1,15 @@
package com.lagradost.cloudstream3.animeproviders 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.APIHolder.unixTime
import com.lagradost.cloudstream3.MainAPI import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.mapper import com.lagradost.cloudstream3.utils.getQualityFromName
import org.jsoup.Jsoup
import java.util.*
import kotlin.collections.ArrayList
class DubbedAnimeProvider : MainAPI() { class DubbedAnimeProvider : MainAPI() {
override val mainUrl: String override val mainUrl: String
@ -12,19 +19,187 @@ class DubbedAnimeProvider : MainAPI() {
override val hasQuickSearch: Boolean override val hasQuickSearch: Boolean
get() = true get() = true
override fun quickSearch(query: String): ArrayList<Any>? { data class QueryEpisodeResultRoot(
val url = "$mainUrl/xz/searchgrid.php?p=1&limit=12&s=$query&_=${unixTime}" @JsonProperty("result")
val response = khttp.get(url) 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 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,
)
}
}
} }

View file

@ -209,7 +209,8 @@ class ShiroProvider : MainAPI() {
val mapped = response.let { mapper.readValue<AnimePage>(it.text) } val mapped = response.let { mapper.readValue<AnimePage>(it.text) }
val data = mapped.data val data = mapped.data
val isDubbed = data.language == "dubbed" 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) { val status = when (data.status) {
"current" -> ShowStatus.Ongoing "current" -> ShowStatus.Ongoing
"finished" -> ShowStatus.Completed "finished" -> ShowStatus.Completed

View file

@ -3,9 +3,10 @@ package com.lagradost.cloudstream3.ui
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.View.* import android.view.View.*
import android.widget.* import android.widget.AbsListView
import androidx.appcompat.app.AlertDialog import android.widget.ArrayAdapter
import androidx.core.content.ContentProviderCompat.requireContext import android.widget.ImageView
import android.widget.ListView
import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.databind.json.JsonMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule 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.CastSession
import com.google.android.gms.cast.framework.media.RemoteMediaClient 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.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.gms.cast.framework.media.widget.ExpandedControllerActivity
import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialog
import com.lagradost.cloudstream3.APIHolder.getApiFromName import com.lagradost.cloudstream3.APIHolder.getApiFromName
import com.lagradost.cloudstream3.R 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.Resource
import com.lagradost.cloudstream3.mvvm.safeApiCall import com.lagradost.cloudstream3.mvvm.safeApiCall
import com.lagradost.cloudstream3.sortUrls import com.lagradost.cloudstream3.sortUrls

View file

@ -1129,7 +1129,7 @@ class PlayerFragment : Fragment() {
changeSkip() changeSkip()
initPlayer() // initPlayer()
} }
private fun getCurrentUrl(): ExtractorLink? { private fun getCurrentUrl(): ExtractorLink? {

View file

@ -86,11 +86,11 @@ class ResultViewModel : ViewModel() {
val episodes = ArrayList<ResultEpisode>() val episodes = ArrayList<ResultEpisode>()
for ((index, i) in dataList.withIndex()) { for ((index, i) in dataList.withIndex()) {
episodes.add(context.buildResultEpisode( episodes.add(context.buildResultEpisode(
null, // TODO ADD NAMES i.name,
null, null,
index + 1, //TODO MAKE ABLE TO NOT HAVE SOME EPISODE index + 1, //TODO MAKE ABLE TO NOT HAVE SOME EPISODE
null, // TODO FIX SEASON null, // TODO FIX SEASON
i, i.url,
apiName, apiName,
(mainId + index + 1), (mainId + index + 1),
index, index,
@ -122,7 +122,7 @@ class ResultViewModel : ViewModel() {
null, null,
null, null,
0, null, 0, null,
d.movieUrl, d.dataUrl,
d.apiName, d.apiName,
(mainId + 1), (mainId + 1),
0, 0,

View file

@ -148,7 +148,7 @@ class SearchFragment : Fragment() {
allApi.providersActive = requireActivity().getApiSettings() allApi.providersActive = requireActivity().getApiSettings()
//searchViewModel.search("iron man") //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() (requireActivity() as AppCompatActivity).supportFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.enter_anim, .setCustomAnimations(R.anim.enter_anim,

View file

@ -28,8 +28,7 @@ class Vidstream {
with(khttp.get(url)) { with(khttp.get(url)) {
val document = Jsoup.parse(this.text) val document = Jsoup.parse(this.text)
val primaryLinks = document.select("ul.list-server-items > li.linkserver") 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 // All vidstream links passed to extractors
primaryLinks.forEach { element -> primaryLinks.forEach { element ->