mirror of
				https://github.com/recloudstream/cloudstream.git
				synced 2024-08-15 01:53:11 +00:00 
			
		
		
		
	small subtitle support
This commit is contained in:
		
							parent
							
								
									672dc8c8d1
								
							
						
					
					
						commit
						9fc732c68c
					
				
					 12 changed files with 266 additions and 124 deletions
				
			
		|  | @ -72,7 +72,7 @@ abstract class MainAPI { | |||
|     } | ||||
| 
 | ||||
|     // callback is fired once a link is found, will return true if method is executed successfully | ||||
|     open fun loadLinks(data: String, isCasting: Boolean, callback: (ExtractorLink) -> Unit): Boolean { | ||||
|     open fun loadLinks(data: String, isCasting: Boolean, subtitleCallback : (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit): Boolean { | ||||
|         return false | ||||
|     } | ||||
| } | ||||
|  | @ -120,6 +120,8 @@ enum class TvType { | |||
|     ONA, | ||||
| } | ||||
| 
 | ||||
| data class SubtitleFile(val lang : String, val url : String) | ||||
| 
 | ||||
| interface SearchResponse { | ||||
|     val name: String | ||||
|     val url: String // PUBLIC URL FOR OPEN IN APP | ||||
|  |  | |||
|  | @ -86,7 +86,8 @@ class DubbedAnimeProvider : MainAPI() { | |||
|                         title, href, getSlug(href), this.name, TvType.Movie, img, null | ||||
|                     ) | ||||
|                 } else { | ||||
|                     AnimeSearchResponse(title, | ||||
|                     AnimeSearchResponse( | ||||
|                         title, | ||||
|                         href, | ||||
|                         getSlug(href), | ||||
|                         this.name, | ||||
|  | @ -96,8 +97,10 @@ class DubbedAnimeProvider : MainAPI() { | |||
|                         null, | ||||
|                         EnumSet.of(DubStatus.Dubbed), | ||||
|                         null, | ||||
|                         null) | ||||
|                 }) | ||||
|                         null | ||||
|                     ) | ||||
|                 } | ||||
|             ) | ||||
|         } | ||||
|         return returnValue | ||||
|     } | ||||
|  | @ -121,7 +124,8 @@ class DubbedAnimeProvider : MainAPI() { | |||
|                         title, href, getSlug(href), this.name, TvType.Movie, img, null | ||||
|                     ) | ||||
|                 } else { | ||||
|                     AnimeSearchResponse(title, | ||||
|                     AnimeSearchResponse( | ||||
|                         title, | ||||
|                         href, | ||||
|                         getSlug(href), | ||||
|                         this.name, | ||||
|  | @ -131,14 +135,21 @@ class DubbedAnimeProvider : MainAPI() { | |||
|                         null, | ||||
|                         EnumSet.of(DubStatus.Dubbed), | ||||
|                         null, | ||||
|                         null) | ||||
|                 }) | ||||
|                         null | ||||
|                     ) | ||||
|                 } | ||||
|             ) | ||||
|         } | ||||
| 
 | ||||
|         return returnValue | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks(data: String, isCasting: Boolean, callback: (ExtractorLink) -> Unit): Boolean { | ||||
|     override fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|         callback: (ExtractorLink) -> Unit | ||||
|     ): Boolean { | ||||
|         val serversHTML = (if (data.startsWith(mainUrl)) { // CLASSIC EPISODE | ||||
|             val slug = getSlug(data) | ||||
|             getAnimeEpisode(slug, false).serversHTML | ||||
|  | @ -154,11 +165,15 @@ class DubbedAnimeProvider : MainAPI() { | |||
|                 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))) | ||||
|                     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) { | ||||
|                 //IDK | ||||
|  | @ -172,7 +187,8 @@ class DubbedAnimeProvider : MainAPI() { | |||
|             val realSlug = slug.replace("movies/", "") | ||||
|             val episode = getAnimeEpisode(realSlug, true) | ||||
|             val poster = episode.previewImg ?: episode.wideImg | ||||
|             return MovieLoadResponse(episode.title, | ||||
|             return MovieLoadResponse( | ||||
|                 episode.title, | ||||
|                 realSlug, | ||||
|                 this.name, | ||||
|                 TvType.Movie, | ||||
|  | @ -180,7 +196,8 @@ class DubbedAnimeProvider : MainAPI() { | |||
|                 if (poster == null) null else fixUrl(poster), | ||||
|                 episode.year?.toIntOrNull(), | ||||
|                 episode.desc, | ||||
|                 null) | ||||
|                 null | ||||
|             ) | ||||
|         } else { | ||||
|             val response = khttp.get("$mainUrl/$slug") | ||||
|             val document = Jsoup.parse(response.text) | ||||
|  |  | |||
|  | @ -167,12 +167,14 @@ class ShiroProvider : MainAPI() { | |||
|     override fun quickSearch(query: String): ArrayList<SearchResponse> { | ||||
|         val returnValue: ArrayList<SearchResponse> = ArrayList() | ||||
| 
 | ||||
|         val response = khttp.get("https://tapi.shiro.is/anime/auto-complete/${ | ||||
|             URLEncoder.encode( | ||||
|                 query, | ||||
|                 "UTF-8" | ||||
|             ) | ||||
|         }?token=$token".replace("+", "%20")) | ||||
|         val response = khttp.get( | ||||
|             "https://tapi.shiro.is/anime/auto-complete/${ | ||||
|                 URLEncoder.encode( | ||||
|                     query, | ||||
|                     "UTF-8" | ||||
|                 ) | ||||
|             }?token=$token".replace("+", "%20") | ||||
|         ) | ||||
|         if (response.text == "{\"status\":\"Found\",\"data\":[]}") return returnValue // OR ELSE WILL CAUSE WEIRD ERROR | ||||
| 
 | ||||
|         val mapped = response.let { mapper.readValue<ShiroSearchResponse>(it.text) } | ||||
|  | @ -185,12 +187,14 @@ class ShiroProvider : MainAPI() { | |||
|     override fun search(query: String): ArrayList<SearchResponse>? { | ||||
|         if (!autoLoadToken()) return null | ||||
|         val returnValue: ArrayList<SearchResponse> = ArrayList() | ||||
|         val response = khttp.get("https://tapi.shiro.is/advanced?search=${ | ||||
|             URLEncoder.encode( | ||||
|                 query, | ||||
|                 "UTF-8" | ||||
|             ) | ||||
|         }&token=$token".replace("+", "%20")) | ||||
|         val response = khttp.get( | ||||
|             "https://tapi.shiro.is/advanced?search=${ | ||||
|                 URLEncoder.encode( | ||||
|                     query, | ||||
|                     "UTF-8" | ||||
|                 ) | ||||
|             }&token=$token".replace("+", "%20") | ||||
|         ) | ||||
|         if (response.text == "{\"status\":\"Found\",\"data\":[]}") return returnValue // OR ELSE WILL CAUSE WEIRD ERROR | ||||
| 
 | ||||
|         val mapped = response.let { mapper.readValue<ShiroFullSearchResponse>(it.text) } | ||||
|  | @ -235,7 +239,12 @@ class ShiroProvider : MainAPI() { | |||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks(data: String, isCasting: Boolean, callback: (ExtractorLink) -> Unit): Boolean { | ||||
|     override fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|         callback: (ExtractorLink) -> Unit | ||||
|     ): Boolean { | ||||
|         return Vidstream().getUrl(data, isCasting) { | ||||
|             callback.invoke(it) | ||||
|         } | ||||
|  |  | |||
|  | @ -29,17 +29,26 @@ class HDMProvider : MainAPI() { | |||
|         return returnValue | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks(data: String, isCasting: Boolean, callback: (ExtractorLink) -> Unit): Boolean { | ||||
|     override fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|         callback: (ExtractorLink) -> Unit | ||||
|     ): Boolean { | ||||
|         if (data == "") return false | ||||
|         val slug = ".*/(.*?)\\.mp4".toRegex().find(data)?.groupValues?.get(1) ?: return false | ||||
|         val response = khttp.get(data) | ||||
|         val key = "playlist\\.m3u8(.*?)\"".toRegex().find(response.text)?.groupValues?.get(1) ?: return false | ||||
|         callback.invoke(ExtractorLink(this.name, | ||||
|             this.name, | ||||
|             "https://hls.1o.to/vod/$slug/playlist.m3u8$key", | ||||
|             "", | ||||
|             Qualities.HD.value, | ||||
|             true)) | ||||
|         callback.invoke( | ||||
|             ExtractorLink( | ||||
|                 this.name, | ||||
|                 this.name, | ||||
|                 "https://hls.1o.to/vod/$slug/playlist.m3u8$key", | ||||
|                 "", | ||||
|                 Qualities.HD.value, | ||||
|                 true | ||||
|             ) | ||||
|         ) | ||||
|         return true | ||||
|     } | ||||
| 
 | ||||
|  | @ -51,9 +60,11 @@ class HDMProvider : MainAPI() { | |||
|         val descript = document.selectFirst("div.synopsis > p").text() | ||||
|         val year = document.select("div.movieInfoAll > div.row > div.col-md-6")?.get(1)?.selectFirst("> p > a")?.text() | ||||
|             ?.toIntOrNull() | ||||
|         val data = "src/player/\\?v=(.*?)\"".toRegex().find(response.text)?.groupValues?.get(1) ?: return  null | ||||
|         val data = "src/player/\\?v=(.*?)\"".toRegex().find(response.text)?.groupValues?.get(1) ?: return null | ||||
| 
 | ||||
|         return MovieLoadResponse(title, slug, this.name, TvType.Movie, | ||||
|             "$mainUrl/src/player/?v=$data", poster, year, descript, null) | ||||
|         return MovieLoadResponse( | ||||
|             title, slug, this.name, TvType.Movie, | ||||
|             "$mainUrl/src/player/?v=$data", poster, year, descript, null | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|  | @ -5,7 +5,6 @@ import com.fasterxml.jackson.module.kotlin.readValue | |||
| import com.lagradost.cloudstream3.* | ||||
| import com.lagradost.cloudstream3.APIHolder.unixTime | ||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | ||||
| import com.lagradost.cloudstream3.utils.Qualities | ||||
| import com.lagradost.cloudstream3.utils.extractors.M3u8Manifest | ||||
| import com.lagradost.cloudstream3.utils.getQualityFromName | ||||
| import org.jsoup.Jsoup | ||||
|  | @ -43,7 +42,7 @@ class LookMovieProvider : MainAPI() { | |||
| 
 | ||||
|     data class LookMovieTokenSubtitle( | ||||
|         @JsonProperty("language") val language: String, | ||||
|         //@JsonProperty("source") val source: String, | ||||
|         @JsonProperty("source") val source: String?, | ||||
|         //@JsonProperty("source_id") val source_id: String, | ||||
|         //@JsonProperty("kind") val kind: String, | ||||
|         //@JsonProperty("id") val id: String, | ||||
|  | @ -77,26 +76,34 @@ class LookMovieProvider : MainAPI() { | |||
|         if (!movies.isNullOrEmpty()) { | ||||
|             for (m in movies) { | ||||
|                 val url = "$mainUrl/movies/view/${m.slug}" | ||||
|                 returnValue.add(MovieSearchResponse(m.title, | ||||
|                     url, | ||||
|                     url,//m.slug, | ||||
|                     this.name, | ||||
|                     TvType.Movie, | ||||
|                     m.poster ?: m.backdrop, | ||||
|                     m.year?.toIntOrNull())) | ||||
|                 returnValue.add( | ||||
|                     MovieSearchResponse( | ||||
|                         m.title, | ||||
|                         url, | ||||
|                         url,//m.slug, | ||||
|                         this.name, | ||||
|                         TvType.Movie, | ||||
|                         m.poster ?: m.backdrop, | ||||
|                         m.year?.toIntOrNull() | ||||
|                     ) | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (!shows.isNullOrEmpty()) { | ||||
|             for (s in shows) { | ||||
|                 val url = "$mainUrl/shows/view/${s.slug}" | ||||
|                 returnValue.add(MovieSearchResponse(s.title, | ||||
|                     url, | ||||
|                     url,//s.slug, | ||||
|                     this.name, | ||||
|                     TvType.TvSeries, | ||||
|                     s.poster ?: s.backdrop, | ||||
|                     s.year?.toIntOrNull())) | ||||
|                 returnValue.add( | ||||
|                     MovieSearchResponse( | ||||
|                         s.title, | ||||
|                         url, | ||||
|                         url,//s.slug, | ||||
|                         this.name, | ||||
|                         TvType.TvSeries, | ||||
|                         s.poster ?: s.backdrop, | ||||
|                         s.year?.toIntOrNull() | ||||
|                     ) | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  | @ -119,14 +126,15 @@ class LookMovieProvider : MainAPI() { | |||
|                 val poster = posterHolder.selectFirst("> img")?.attr("data-src") | ||||
|                 val year = posterHolder.selectFirst("> p.year")?.text()?.toIntOrNull() | ||||
| 
 | ||||
|                 returnValue.add(if (isMovie) { | ||||
|                     MovieSearchResponse( | ||||
|                         name, href, href, this.name, TvType.Movie, poster, year | ||||
|                     ) | ||||
|                 } else | ||||
|                     TvSeriesSearchResponse( | ||||
|                         name, href, href, this.name, TvType.TvSeries, poster, year, null | ||||
|                     ) | ||||
|                 returnValue.add( | ||||
|                     if (isMovie) { | ||||
|                         MovieSearchResponse( | ||||
|                             name, href, href, this.name, TvType.Movie, poster, year | ||||
|                         ) | ||||
|                     } else | ||||
|                         TvSeriesSearchResponse( | ||||
|                             name, href, href, this.name, TvType.TvSeries, poster, year, null | ||||
|                         ) | ||||
|                 ) | ||||
|             } | ||||
|             return returnValue | ||||
|  | @ -138,15 +146,52 @@ class LookMovieProvider : MainAPI() { | |||
|         return movieList | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks(data: String, isCasting: Boolean, callback: (ExtractorLink) -> Unit): Boolean { | ||||
|         val response = khttp.get(data.replace("\$unixtime", unixTime.toString())) | ||||
|     data class LookMovieLinkLoad(val url: String, val extraUrl: String, val isMovie: Boolean) | ||||
| 
 | ||||
|     private fun addSubtitles(subs: List<LookMovieTokenSubtitle>?, subtitleCallback: (SubtitleFile) -> Unit) { | ||||
|         if (subs == null) return | ||||
|         subs.forEach { | ||||
|             if (it.source != "opensubtitle") | ||||
|                 subtitleCallback.invoke(SubtitleFile(it.language, fixUrl(it.file))) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private fun loadCurrentLinks(url: String, callback: (ExtractorLink) -> Unit) { | ||||
|         val response = khttp.get(url.replace("\$unixtime", unixTime.toString())) | ||||
|         M3u8Manifest.extractLinks(response.text).forEach { | ||||
|             callback.invoke(ExtractorLink(this.name, | ||||
|                 "${this.name} - ${it.second}", | ||||
|                 fixUrl(it.first), | ||||
|                 "", | ||||
|                 getQualityFromName(it.second), | ||||
|                 true)) | ||||
|             callback.invoke( | ||||
|                 ExtractorLink( | ||||
|                     this.name, | ||||
|                     "${this.name} - ${it.second}", | ||||
|                     fixUrl(it.first), | ||||
|                     "", | ||||
|                     getQualityFromName(it.second), | ||||
|                     true | ||||
|                 ) | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|         callback: (ExtractorLink) -> Unit | ||||
|     ): Boolean { | ||||
|         val localData: LookMovieLinkLoad = mapper.readValue(data) | ||||
| 
 | ||||
|         if (localData.isMovie) { | ||||
|             val tokenResponse = khttp.get(localData.url) | ||||
|             val root = mapper.readValue<LookMovieTokenRoot>(tokenResponse.text) | ||||
|             val accessToken = root.data?.accessToken ?: return false | ||||
|             addSubtitles(root.data.subtitles, subtitleCallback) | ||||
|             loadCurrentLinks(localData.extraUrl.replace("\$accessToken", accessToken), callback) | ||||
|             return true | ||||
|         } else { | ||||
|             loadCurrentLinks(localData.url, callback) | ||||
|             val subResponse = khttp.get(localData.extraUrl) | ||||
|             val subs = mapper.readValue<List<LookMovieTokenSubtitle>>(subResponse.text) | ||||
|             addSubtitles(subs, subtitleCallback) | ||||
|         } | ||||
|         return true | ||||
|     } | ||||
|  | @ -159,7 +204,7 @@ class LookMovieProvider : MainAPI() { | |||
|         val watchHeader = document.selectFirst("div.watch-heading") | ||||
|         val nameHeader = watchHeader.selectFirst("> h1.bd-hd") | ||||
|         val year = nameHeader.selectFirst("> span")?.text()?.toIntOrNull() | ||||
|         val name = nameHeader.ownText() | ||||
|         val title = nameHeader.ownText() | ||||
|         val rating = parseRating(watchHeader.selectFirst("> div.movie-rate > div.rate > p > span").text()) | ||||
|         val imgElement = document.selectFirst("div.movie-img > p.movie__poster") | ||||
|         val img = imgElement?.attr("style") | ||||
|  | @ -173,22 +218,31 @@ class LookMovieProvider : MainAPI() { | |||
|         val realUrl = | ||||
|             "$mainUrl/api/v1/security/${if (isMovie) "movie" else "show"}-access?${if (isMovie) "id_movie=$id" else "slug=$realSlug"}&token=1&sk=&step=1" | ||||
| 
 | ||||
|         val tokenResponse = khttp.get(realUrl) | ||||
|         val root = mapper.readValue<LookMovieTokenRoot>(tokenResponse.text) | ||||
|         val accessToken = root.data?.accessToken ?: return null | ||||
| 
 | ||||
|         if (isMovie) { | ||||
|             return MovieLoadResponse(name, | ||||
|             val localData = mapper.writeValueAsString( | ||||
|                 LookMovieLinkLoad( | ||||
|                     realUrl, | ||||
|                     "$mainUrl/manifests/movies/json/$id/\$unixtime/\$accessToken/master.m3u8", | ||||
|                     true | ||||
|                 ) | ||||
|             ) | ||||
|             return MovieLoadResponse( | ||||
|                 title, | ||||
|                 slug, | ||||
|                 this.name, | ||||
|                 TvType.Movie, | ||||
|                 "$mainUrl/manifests/movies/json/$id/\$unixtime/$accessToken/master.m3u8", | ||||
|                 localData, | ||||
|                 poster, | ||||
|                 year, | ||||
|                 descript, | ||||
|                 null, | ||||
|                 rating) | ||||
|                 rating | ||||
|             ) | ||||
|         } else { | ||||
|             val tokenResponse = khttp.get(realUrl) | ||||
|             val root = mapper.readValue<LookMovieTokenRoot>(tokenResponse.text) | ||||
|             val accessToken = root.data?.accessToken ?: return null | ||||
| 
 | ||||
|             val window = | ||||
|                 "window\\[\\'show_storage\\'\\] =((.|\\n)*?\\<)".toRegex().find(response.text)?.groupValues?.get(1) | ||||
|                     ?: return null | ||||
|  | @ -208,13 +262,24 @@ class LookMovieProvider : MainAPI() { | |||
|             val realJson = "[" + json.substring(0, json.lastIndexOf(',')) + "]" | ||||
| 
 | ||||
|             val episodes = mapper.readValue<List<LookMovieEpisode>>(realJson).map { | ||||
|                 TvSeriesEpisode(it.title, | ||||
|                 val localData = mapper.writeValueAsString( | ||||
|                     LookMovieLinkLoad( | ||||
|                         "$mainUrl/manifests/shows/json/$accessToken/\$unixtime/${it.idEpisode}/master.m3u8", | ||||
|                         "https://lookmovie.io/api/v1/shows/episode-subtitles/?id_episode=${it.idEpisode}", | ||||
|                         false | ||||
|                     ) | ||||
|                 ) | ||||
| 
 | ||||
|                 TvSeriesEpisode( | ||||
|                     it.title, | ||||
|                     it.season.toIntOrNull(), | ||||
|                     it.episode.toIntOrNull(), | ||||
|                     "$mainUrl/manifests/shows/json/$accessToken/\$unixtime/${it.idEpisode}/master.m3u8") | ||||
|                     localData | ||||
|                 ) | ||||
|             }.toList() | ||||
| 
 | ||||
|             return TvSeriesLoadResponse(name, | ||||
|             return TvSeriesLoadResponse( | ||||
|                 title, | ||||
|                 slug, | ||||
|                 this.name, | ||||
|                 TvType.TvSeries, | ||||
|  | @ -224,7 +289,8 @@ class LookMovieProvider : MainAPI() { | |||
|                 descript, | ||||
|                 null, | ||||
|                 null, | ||||
|                 rating) | ||||
|                 rating | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -44,22 +44,30 @@ class MeloMovieProvider : MainAPI() { | |||
|             val currentUrl = "$mainUrl/movie/${i.id}" | ||||
|             val currentPoster = "$mainUrl/assets/images/poster/${i.imdbId}.jpg" | ||||
|             if (i.type == 2) { // TV-SERIES | ||||
|                 returnValue.add(TvSeriesSearchResponse(i.title, | ||||
|                     currentUrl, | ||||
|                     currentUrl, | ||||
|                     this.name, | ||||
|                     TvType.TvSeries, | ||||
|                     currentPoster, | ||||
|                     i.year, | ||||
|                     null)) | ||||
|                 returnValue.add( | ||||
|                     TvSeriesSearchResponse( | ||||
|                         i.title, | ||||
|                         currentUrl, | ||||
|                         currentUrl, | ||||
|                         this.name, | ||||
|                         TvType.TvSeries, | ||||
|                         currentPoster, | ||||
|                         i.year, | ||||
|                         null | ||||
|                     ) | ||||
|                 ) | ||||
|             } else if (i.type == 1) { // MOVIE | ||||
|                 returnValue.add(MovieSearchResponse(i.title, | ||||
|                     currentUrl, | ||||
|                     currentUrl, | ||||
|                     this.name, | ||||
|                     TvType.Movie, | ||||
|                     currentUrl, | ||||
|                     i.year)) | ||||
|                 returnValue.add( | ||||
|                     MovieSearchResponse( | ||||
|                         i.title, | ||||
|                         currentUrl, | ||||
|                         currentUrl, | ||||
|                         this.name, | ||||
|                         TvType.Movie, | ||||
|                         currentUrl, | ||||
|                         i.year | ||||
|                     ) | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
|         return returnValue | ||||
|  | @ -67,7 +75,7 @@ class MeloMovieProvider : MainAPI() { | |||
| 
 | ||||
|     // http not https, the links are not https! | ||||
|     private fun fixUrl(url: String): String { | ||||
|         if(url.isEmpty()) return "" | ||||
|         if (url.isEmpty()) return "" | ||||
| 
 | ||||
|         if (url.startsWith("//")) { | ||||
|             return "http:$url" | ||||
|  | @ -93,7 +101,12 @@ class MeloMovieProvider : MainAPI() { | |||
|         return mapper.writeValueAsString(parsed) | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks(data: String, isCasting: Boolean, callback: (ExtractorLink) -> Unit): Boolean { | ||||
|     override fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|         callback: (ExtractorLink) -> Unit | ||||
|     ): Boolean { | ||||
|         val links = mapper.readValue<List<MeloMovieLink>>(data) | ||||
|         for (link in links) { | ||||
|             callback.invoke(ExtractorLink(this.name, link.name, link.link, "", getQualityFromName(link.name), false)) | ||||
|  | @ -120,7 +133,8 @@ class MeloMovieProvider : MainAPI() { | |||
| 
 | ||||
|         if (type == 1) { // MOVIE | ||||
|             val serialize = document.selectFirst("table.accordion__list") | ||||
|             return MovieLoadResponse(title, | ||||
|             return MovieLoadResponse( | ||||
|                 title, | ||||
|                 slug, | ||||
|                 this.name, | ||||
|                 TvType.Movie, | ||||
|  | @ -128,7 +142,8 @@ class MeloMovieProvider : MainAPI() { | |||
|                 poster, | ||||
|                 year, | ||||
|                 plot, | ||||
|                 imdbUrl) | ||||
|                 imdbUrl | ||||
|             ) | ||||
|         } else if (type == 2) { | ||||
|             val episodes = ArrayList<TvSeriesEpisode>() | ||||
|             val seasons = document.select("div.accordion__card") | ||||
|  | @ -145,7 +160,8 @@ class MeloMovieProvider : MainAPI() { | |||
|                 } | ||||
|             } | ||||
|             episodes.reverse() | ||||
|             return TvSeriesLoadResponse(title, | ||||
|             return TvSeriesLoadResponse( | ||||
|                 title, | ||||
|                 slug, | ||||
|                 this.name, | ||||
|                 TvType.TvSeries, | ||||
|  | @ -154,7 +170,8 @@ class MeloMovieProvider : MainAPI() { | |||
|                 year, | ||||
|                 plot, | ||||
|                 null, | ||||
|                 imdbUrl) | ||||
|                 imdbUrl | ||||
|             ) | ||||
|         } | ||||
|         return null | ||||
|     } | ||||
|  |  | |||
|  | @ -80,7 +80,12 @@ class TrailersToProvider : MainAPI() { | |||
|         return false | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks(data: String, isCasting: Boolean, callback: (ExtractorLink) -> Unit): Boolean { | ||||
|     override fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|         callback: (ExtractorLink) -> Unit | ||||
|     ): Boolean { | ||||
|         if (isCasting) return false | ||||
|         val isMovie = data.contains("/web-sources/") | ||||
|         if (isMovie) { | ||||
|  | @ -142,7 +147,8 @@ class TrailersToProvider : MainAPI() { | |||
|                 val epDescript = main.selectFirst("> p")?.text() | ||||
|                 TvSeriesEpisode(epName, season, episode, href, epPoster, date, epRating, epDescript) | ||||
|             } | ||||
|             return TvSeriesLoadResponse(title, | ||||
|             return TvSeriesLoadResponse( | ||||
|                 title, | ||||
|                 slug, | ||||
|                 this.name, | ||||
|                 TvType.TvSeries, | ||||
|  | @ -155,10 +161,12 @@ class TrailersToProvider : MainAPI() { | |||
|                 rating, | ||||
|                 tags, | ||||
|                 duration, | ||||
|                 trailer) | ||||
|                 trailer | ||||
|             ) | ||||
|         } else { | ||||
|             val data = fixUrl(document.selectFirst("content").attr("data-url") ?: return null) | ||||
|             return MovieLoadResponse(title, | ||||
|             return MovieLoadResponse( | ||||
|                 title, | ||||
|                 slug, | ||||
|                 this.name, | ||||
|                 TvType.Movie, | ||||
|  | @ -170,7 +178,8 @@ class TrailersToProvider : MainAPI() { | |||
|                 rating, | ||||
|                 tags, | ||||
|                 duration, | ||||
|                 trailer) | ||||
|                 trailer | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -128,7 +128,8 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi | |||
|                                 epData, | ||||
|                                 holder, | ||||
|                                 index, | ||||
|                                 remoteMediaClient?.mediaInfo?.customData) | ||||
|                                 remoteMediaClient?.mediaInfo?.customData | ||||
|                             ) | ||||
| 
 | ||||
|                             val startAt = remoteMediaClient?.approximateStreamPosition ?: 0 | ||||
| 
 | ||||
|  | @ -139,12 +140,17 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi | |||
|                                 val nextId = remoteMediaClient.mediaQueue.itemIds?.get(currentIdIndex?.plus(1) ?: 0) | ||||
| 
 | ||||
|                                 if (currentIdIndex == null && nextId != null) { | ||||
|                                     awaitLinks(remoteMediaClient?.queueInsertAndPlayItem(MediaQueueItem.Builder( | ||||
|                                         mediaItem) | ||||
|                                         .build(), | ||||
|                                         nextId, | ||||
|                                         startAt, | ||||
|                                         JSONObject())) { | ||||
|                                     awaitLinks( | ||||
|                                         remoteMediaClient?.queueInsertAndPlayItem( | ||||
|                                             MediaQueueItem.Builder( | ||||
|                                                 mediaItem | ||||
|                                             ) | ||||
|                                                 .build(), | ||||
|                                             nextId, | ||||
|                                             startAt, | ||||
|                                             JSONObject() | ||||
|                                         ) | ||||
|                                     ) { | ||||
|                                         loadMirror(index + 1) | ||||
|                                     } | ||||
|                                 } else { | ||||
|  | @ -204,7 +210,7 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi | |||
|                         val links = ArrayList<ExtractorLink>() | ||||
| 
 | ||||
|                         val res = safeApiCall { | ||||
|                             getApiFromName(meta.apiName).loadLinks(epData.data, true) { | ||||
|                             getApiFromName(meta.apiName).loadLinks(epData.data, true, { subtitleFile ->  }) { | ||||
|                                 for (i in links) { | ||||
|                                     if (i.url == it.url) return@loadLinks | ||||
|                                 } | ||||
|  | @ -225,7 +231,8 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi | |||
|                                     epData, | ||||
|                                     jsonCopy, | ||||
|                                     0, | ||||
|                                     done) | ||||
|                                     done | ||||
|                                 ) | ||||
| 
 | ||||
|                                 /*fun loadIndex(index: Int) { | ||||
|                                     println("LOAD INDEX::::: $index") | ||||
|  | @ -240,8 +247,12 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi | |||
|                                     } | ||||
|                                 }*/ | ||||
| 
 | ||||
|                                 awaitLinks(remoteMediaClient?.queueAppendItem(MediaQueueItem.Builder(mediaInfo).build(), | ||||
|                                     JSONObject())) { | ||||
|                                 awaitLinks( | ||||
|                                     remoteMediaClient?.queueAppendItem( | ||||
|                                         MediaQueueItem.Builder(mediaInfo).build(), | ||||
|                                         JSONObject() | ||||
|                                     ) | ||||
|                                 ) { | ||||
|                                     println("FAILED TO LOAD NEXT ITEM") | ||||
|                                     //  loadIndex(1) | ||||
|                                 } | ||||
|  |  | |||
|  | @ -147,11 +147,11 @@ class EpisodeAdapter( | |||
|                         clickCallback.invoke(EpisodeClickEvent(ACTION_CHROME_CAST_EPISODE, card)) | ||||
|                     } else { | ||||
|                         // clickCallback.invoke(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, card)) | ||||
|                         clickCallback.invoke(EpisodeClickEvent(ACTION_DOWNLOAD_EPISODE, card)) | ||||
|                         clickCallback.invoke(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, card)) | ||||
|                     } | ||||
|                 } else { | ||||
|                     // clickCallback.invoke(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, card)) | ||||
|                     clickCallback.invoke(EpisodeClickEvent(ACTION_DOWNLOAD_EPISODE, card)) | ||||
|                     clickCallback.invoke(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, card)) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  |  | |||
|  | @ -206,7 +206,7 @@ class ResultViewModel : ViewModel() { | |||
|             } | ||||
|             val links = ArrayList<ExtractorLink>() | ||||
|             val localData = safeApiCall { | ||||
|                 getApiFromName(_apiName.value).loadLinks(data, isCasting) { | ||||
|                 getApiFromName(_apiName.value).loadLinks(data, isCasting,  { subtitleFile ->  }) { | ||||
|                     for (i in links) { | ||||
|                         if (i.url == it.url) return@loadLinks | ||||
|                     } | ||||
|  |  | |||
|  | @ -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, | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ object M3u8Manifest { | |||
|         val data: ArrayList<Pair<String, String>> = ArrayList() | ||||
|         "\"(.*?)\":\"(.*?)\"".toRegex().findAll(m3u8Data).forEach { | ||||
|             var quality = it.groupValues[1].replace("auto", "Auto") | ||||
|             if (quality != "Auto") quality += "p" | ||||
|             if (quality != "Auto" && !quality.endsWith('p')) quality += "p" | ||||
|             val url = it.groupValues[2] | ||||
|             data.add(Pair(url, quality)) | ||||
|         } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue