From 9e67291a8f627e64e46086a2f788eb4e4a9006a4 Mon Sep 17 00:00:00 2001 From: LagradOst Date: Wed, 23 Jun 2021 20:33:47 +0200 Subject: [PATCH] dubbedanime provider --- .../com/lagradost/cloudstream3/MainAPI.kt | 34 ++- .../animeproviders/DubbedAnimeProvider.kt | 197 +++++++++++++++++- .../animeproviders/ShiroProvider.kt | 3 +- .../cloudstream3/ui/ControllerActivity.kt | 10 +- .../cloudstream3/ui/player/PlayerFragment.kt | 2 +- .../cloudstream3/ui/result/ResultViewModel.kt | 6 +- .../cloudstream3/ui/search/SearchFragment.kt | 2 +- .../utils/extractors/Vidstream.kt | 3 +- 8 files changed, 221 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt index fb51a113..c8092449 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt @@ -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('/')) { - return mainUrl + url - } else if (!url.startsWith("http") && !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" } - return url } fun sortUrls(urls: List): List { @@ -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?, - val subEpisodes: ArrayList?, + val dubEpisodes: ArrayList?, + val subEpisodes: ArrayList?, val showStatus: ShowStatus?, override val plot: String?, - val tags: ArrayList?, - val synonyms: ArrayList?, + val tags: ArrayList? = null, + val synonyms: ArrayList? = 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?, diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/DubbedAnimeProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/DubbedAnimeProvider.kt index c58e6c59..0790f976 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/DubbedAnimeProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/DubbedAnimeProvider.kt @@ -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? { - 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, + @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?, + + /* + @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(it.text) } + + return mapped.result.anime.first() } - /* - override fun search(query: String): ArrayList? { + + 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 { + 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() + 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 { 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() + 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, + ) + } + } } \ 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 714058d8..4d5b56ff 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ShiroProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ShiroProvider.kt @@ -209,7 +209,8 @@ class ShiroProvider : MainAPI() { val mapped = response.let { mapper.readValue(it.text) } val data = mapped.data val isDubbed = data.language == "dubbed" - val episodes = ArrayList(data.episodes?.map { it.videos[0].video_id } ?: ArrayList()) + val episodes = ArrayList(data.episodes?.map { AnimeEpisode(it.videos[0].video_id) } + ?: ArrayList()) val status = when (data.status) { "current" -> ShowStatus.Ongoing "finished" -> ShowStatus.Completed diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/ControllerActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/ControllerActivity.kt index 824960da..d3102d49 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/ControllerActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/ControllerActivity.kt @@ -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 diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerFragment.kt index 9432528e..45e3245c 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerFragment.kt @@ -1129,7 +1129,7 @@ class PlayerFragment : Fragment() { changeSkip() - initPlayer() + // initPlayer() } private fun getCurrentUrl(): ExtractorLink? { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt index 52e38369..5cd3f56f 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt @@ -86,11 +86,11 @@ class ResultViewModel : ViewModel() { val episodes = ArrayList() 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, 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 e656fc4b..b9a9643a 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 @@ -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, diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Vidstream.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Vidstream.kt index 1fa3af56..72ae464b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Vidstream.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Vidstream.kt @@ -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 = mutableListOf() - + //val extractedLinksList: MutableList = mutableListOf() // All vidstream links passed to extractors primaryLinks.forEach { element ->