forked from recloudstream/cloudstream
		
	add watchasian provider. (#410)
* add watchasian provider. enable downloading on dramasee * applied pr changes. * shorthand for cleaning title
This commit is contained in:
		
							parent
							
								
									4215c094ff
								
							
						
					
					
						commit
						9dc186335e
					
				
					 3 changed files with 201 additions and 1 deletions
				
			
		|  | @ -67,7 +67,8 @@ object APIHolder { | |||
|         PinoyHDXyzProvider(), | ||||
|         PinoyMoviesEsProvider(), | ||||
|         TrailersTwoProvider(), | ||||
|         DramaSeeProvider() | ||||
|         DramaSeeProvider(), | ||||
|         WatchAsianProvider() | ||||
|     ) | ||||
| 
 | ||||
|     val restrictedApis = arrayListOf( | ||||
|  |  | |||
|  | @ -13,6 +13,7 @@ class DramaSeeProvider : MainAPI() { | |||
|     override val hasQuickSearch = false | ||||
|     override val hasMainPage = true | ||||
|     override val hasChromecastSupport = false | ||||
|     override val hasDownloadSupport = true | ||||
|     override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie) | ||||
| 
 | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|  |  | |||
|  | @ -0,0 +1,198 @@ | |||
| package com.lagradost.cloudstream3.movieproviders | ||||
| 
 | ||||
| import android.util.Log | ||||
| import com.fasterxml.jackson.module.kotlin.readValue | ||||
| import com.lagradost.cloudstream3.* | ||||
| import com.lagradost.cloudstream3.extractors.* | ||||
| import com.lagradost.cloudstream3.utils.AppUtils.toJson | ||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | ||||
| import com.lagradost.cloudstream3.utils.loadExtractor | ||||
| 
 | ||||
| class WatchAsianProvider : MainAPI() { | ||||
|     override val mainUrl = "https://watchasian.sh" | ||||
|     override val name = "WatchAsian" | ||||
|     override val hasQuickSearch = false | ||||
|     override val hasMainPage = true | ||||
|     override val hasChromecastSupport = false | ||||
|     override val hasDownloadSupport = true | ||||
|     override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie) | ||||
| 
 | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|         val headers = mapOf("X-Requested-By" to mainUrl) | ||||
|         val doc = app.get(mainUrl, headers = headers).document | ||||
|         val rowPair = mutableListOf<Pair<String, String>>() | ||||
|         doc.select("div.block-tab")?.forEach { | ||||
|             it?.select("ul.tab > li")?.mapNotNull { row -> | ||||
|                 val link = row?.attr("data-tab") ?: return@mapNotNull null | ||||
|                 val title = row.text() ?: return@mapNotNull null | ||||
|                 Pair(title, link) | ||||
|             }?.let { it1 -> | ||||
|                 rowPair.addAll( | ||||
|                     it1 | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return HomePageResponse( | ||||
|             rowPair.mapNotNull { row -> | ||||
|             val main = (doc.select("div.tab-content.${row.second}") | ||||
|                 ?: doc.select("div.tab-content.${row.second}.selected")) ?: return@mapNotNull null | ||||
| 
 | ||||
|             val title = row.first | ||||
|             val inner = main.select("li") ?: return@mapNotNull null | ||||
| 
 | ||||
|             HomePageList( | ||||
|                 title, | ||||
|                 inner.map { | ||||
|                 // Get inner div from article | ||||
|                 val innerBody = it?.selectFirst("a") | ||||
|                 // Fetch details | ||||
|                 val link = fixUrlNull(innerBody?.attr("href")) ?: return@map null | ||||
|                 val image = fixUrlNull(innerBody?.select("img")?.attr("data-original")) ?: "" | ||||
|                 val name = (innerBody?.selectFirst("h3.title")?.text() ?: innerBody?.text())?: "<Untitled>" | ||||
|                 //Log.i(this.name, "Result => (innerBody, image) ${innerBody} / ${image}") | ||||
|                 MovieSearchResponse( | ||||
|                     name, | ||||
|                     link, | ||||
|                     this.name, | ||||
|                     TvType.TvSeries, | ||||
|                     image, | ||||
|                     year = null, | ||||
|                     id = null, | ||||
|                 ) | ||||
|                 }.filterNotNull().distinctBy { c -> c.url }) | ||||
|             }.filter { a -> a.list.isNotEmpty() } | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|         val url = "$mainUrl/search?type=movies&keyword=$query" | ||||
|         val document = app.get(url).document.getElementsByTag("body") | ||||
|                 .select("div.block.tab-container > div > ul > li") ?: return listOf() | ||||
| 
 | ||||
|         return document.mapNotNull { | ||||
|             val innerA = it?.selectFirst("a") ?: return@mapNotNull null | ||||
|             val link = fixUrlNull(innerA.attr("href")) ?: return@mapNotNull null | ||||
|             val title = it.select("h3.title")?.text() ?: return@mapNotNull null | ||||
|             if (title.isEmpty()) { return@mapNotNull null } | ||||
|             val year = null | ||||
|             val imgsrc = innerA.select("img")?.attr("data-original") ?: return@mapNotNull null | ||||
|             val image = fixUrlNull(imgsrc) | ||||
|             //Log.i(this.name, "Result => (img movie) $title / $link") | ||||
|             MovieSearchResponse( | ||||
|                 title, | ||||
|                 link, | ||||
|                 this.name, | ||||
|                 TvType.Movie, | ||||
|                 image, | ||||
|                 year | ||||
|             ) | ||||
|         }.distinctBy { a -> a.url } | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|         val body = app.get(url).document | ||||
|         // Declare vars | ||||
|         val isDramaDetail = url.contains("/drama-detail/") | ||||
|         var poster = "" | ||||
|         var title = "" | ||||
|         var descript : String? = null | ||||
|         var year : Int? = null | ||||
|         if (isDramaDetail) { | ||||
|             val main = body.select("div.details") | ||||
|             val inner = main?.select("div.info") | ||||
|             // Video details | ||||
|             poster = fixUrlNull(main?.select("div.img > img")?.attr("src")) ?: "" | ||||
|             //Log.i(this.name, "Result => (imgLinkCode) ${imgLinkCode}") | ||||
|             title = inner?.select("h1")?.firstOrNull()?.text() ?: "" | ||||
|             year = if (title.length > 5) { | ||||
|                 title.replace(")", "").replace("(", "").substring(title.length - 5) | ||||
|                     .trim().trimEnd(')').toIntOrNull() | ||||
|             } else { | ||||
|                 null | ||||
|             } | ||||
|             //Log.i(this.name, "Result => (year) ${title.substring(title.length - 5)}") | ||||
|             descript = inner?.text() | ||||
|         } else { | ||||
|             poster = body.select("meta[itemprop=\"image\"]")?.attr("content") ?: "" | ||||
|             title = body.selectFirst("div.block.watch-drama")?.selectFirst("h1") | ||||
|                 ?.text() ?: "" | ||||
|             year = null | ||||
|             descript = body.select("meta[name=\"description\"]")?.attr("content") | ||||
|         } | ||||
| 
 | ||||
|         // Episodes Links | ||||
|         //Log.i(this.name, "Result => (all eps) ${body.select("ul.list-episode-item-2.all-episode > li")}") | ||||
|         val episodeList = body.select("ul.list-episode-item-2.all-episode > li")?.mapNotNull { ep -> | ||||
|             //Log.i(this.name, "Result => (epA) ${ep.select("a")}") | ||||
|             val innerA = ep.select("a") ?: return@mapNotNull null | ||||
|             //Log.i(this.name, "Result => (innerA) ${fixUrlNull(innerA.attr("href"))}") | ||||
|             val epLink = fixUrlNull(innerA.attr("href")) ?: return@mapNotNull null | ||||
| 
 | ||||
|             val regex = "(?<=episode-).*?(?=.html)".toRegex() | ||||
|             val count = regex.find(epLink, mainUrl.length)?.value?.toIntOrNull() ?: 0 | ||||
|             //Log.i(this.name, "Result => $epLink (regexYear) ${count}") | ||||
|             TvSeriesEpisode( | ||||
|                 name = null, | ||||
|                 season = null, | ||||
|                 episode = count, | ||||
|                 data = epLink, | ||||
|                 posterUrl = poster, | ||||
|                 date = null | ||||
|             ) | ||||
|         } ?: listOf() | ||||
|         //If there's only 1 episode, consider it a movie. | ||||
|         if (episodeList.size == 1) { | ||||
|             //Clean title | ||||
|             title = title.removeSuffix("Episode 1") | ||||
|             val streamlink = getServerLinks(episodeList[0].data) | ||||
|             //Log.i(this.name, "Result => (streamlink) $streamlink") | ||||
|             return MovieLoadResponse(title, url, this.name, TvType.Movie, streamlink, poster, year, descript, null, null) | ||||
|         } | ||||
|         return TvSeriesLoadResponse( | ||||
|             title, | ||||
|             url, | ||||
|             this.name, | ||||
|             TvType.TvSeries, | ||||
|             episodeList, | ||||
|             poster, | ||||
|             year, | ||||
|             descript, | ||||
|             null, | ||||
|             null, | ||||
|             null | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|         callback: (ExtractorLink) -> Unit | ||||
|     ): Boolean { | ||||
|         if (data == "about:blank") return false | ||||
|         if (data == "[]") return false | ||||
|         if (data.isEmpty()) return false | ||||
|         val links = if (data.startsWith(mainUrl)) { | ||||
|             getServerLinks(data) | ||||
|         } else { data } | ||||
|         mapper.readValue<List<String>>(links) | ||||
|             .forEach { item -> | ||||
|                 var url = item.trim() | ||||
|                 if (url.startsWith("//")) { | ||||
|                     url = "https:$url" | ||||
|                 } | ||||
|                 //Log.i(this.name, "Result => (url) $url") | ||||
|                 loadExtractor(url, mainUrl, callback) | ||||
|             } | ||||
|         return true | ||||
|     } | ||||
| 
 | ||||
|     private fun getServerLinks(url: String) : String { | ||||
|         val moviedoc = app.get(url, referer = mainUrl).document | ||||
|         return moviedoc.select("div.anime_muti_link > ul > li") | ||||
|             ?.mapNotNull { | ||||
|                 fixUrlNull(it?.attr("data-video")) ?: return@mapNotNull null | ||||
|             }?.toJson() ?: "" | ||||
|     } | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue