forked from recloudstream/cloudstream
		
	lookmovie almost done
This commit is contained in:
		
							parent
							
								
									7060843ebc
								
							
						
					
					
						commit
						5c3691ee2e
					
				
					 5 changed files with 211 additions and 12 deletions
				
			
		|  | @ -7,7 +7,8 @@ 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.DubbedAnimeProvider | ||||||
| import com.lagradost.cloudstream3.animeproviders.ShiroProvider | import com.lagradost.cloudstream3.animeproviders.ShiroProvider | ||||||
| import com.lagradost.cloudstream3.movieproviders.HDMMoveProvider | import com.lagradost.cloudstream3.movieproviders.HDMProvider | ||||||
|  | import com.lagradost.cloudstream3.movieproviders.LookMovieProvider | ||||||
| import com.lagradost.cloudstream3.movieproviders.MeloMovieProvider | import com.lagradost.cloudstream3.movieproviders.MeloMovieProvider | ||||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
| import java.util.* | import java.util.* | ||||||
|  | @ -30,7 +31,8 @@ object APIHolder { | ||||||
|         ShiroProvider(), |         ShiroProvider(), | ||||||
|         MeloMovieProvider(), |         MeloMovieProvider(), | ||||||
|         DubbedAnimeProvider(), |         DubbedAnimeProvider(), | ||||||
|         HDMMoveProvider(), |         HDMProvider(), | ||||||
|  |         LookMovieProvider(), | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     fun getApiFromName(apiName: String?): MainAPI { |     fun getApiFromName(apiName: String?): MainAPI { | ||||||
|  | @ -73,6 +75,12 @@ abstract class MainAPI { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | fun parseRating(ratingString : String?) : Int? { | ||||||
|  |     if(ratingString == null) return null | ||||||
|  |     val floatRating = ratingString.toFloatOrNull() ?: return null | ||||||
|  |     return (floatRating * 10).toInt() | ||||||
|  | } | ||||||
|  | 
 | ||||||
| fun MainAPI.fixUrl(url: String): String { | fun MainAPI.fixUrl(url: String): String { | ||||||
|     if(url.startsWith("http")) { |     if(url.startsWith("http")) { | ||||||
|         return url |         return url | ||||||
|  | @ -168,6 +176,7 @@ interface LoadResponse { | ||||||
|     val posterUrl: String? |     val posterUrl: String? | ||||||
|     val year: Int? |     val year: Int? | ||||||
|     val plot: String? |     val plot: String? | ||||||
|  |     val rating : Int? // 0-100 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fun LoadResponse?.isEpisodeBased(): Boolean { | fun LoadResponse?.isEpisodeBased(): Boolean { | ||||||
|  | @ -203,6 +212,7 @@ data class AnimeLoadResponse( | ||||||
| 
 | 
 | ||||||
|     val malId: Int? = null, |     val malId: Int? = null, | ||||||
|     val anilistId: Int? = null, |     val anilistId: Int? = null, | ||||||
|  |     override val rating: Int? = null, | ||||||
| ) : LoadResponse | ) : LoadResponse | ||||||
| 
 | 
 | ||||||
| data class MovieLoadResponse( | data class MovieLoadResponse( | ||||||
|  | @ -217,6 +227,7 @@ data class MovieLoadResponse( | ||||||
|     override val plot: String?, |     override val plot: String?, | ||||||
| 
 | 
 | ||||||
|     val imdbId: Int?, |     val imdbId: Int?, | ||||||
|  |     override val rating: Int? = null, | ||||||
| ) : LoadResponse | ) : LoadResponse | ||||||
| 
 | 
 | ||||||
| data class TvSeriesEpisode(val name: String?, val season: Int?, val episode: Int?, val data: String) | data class TvSeriesEpisode(val name: String?, val season: Int?, val episode: Int?, val data: String) | ||||||
|  | @ -234,4 +245,5 @@ data class TvSeriesLoadResponse( | ||||||
| 
 | 
 | ||||||
|     val showStatus: ShowStatus?, |     val showStatus: ShowStatus?, | ||||||
|     val imdbId: Int?, |     val imdbId: Int?, | ||||||
|  |     override val rating: Int? = null, | ||||||
| ) : LoadResponse | ) : LoadResponse | ||||||
|  | @ -174,10 +174,8 @@ class ShiroProvider : MainAPI() { | ||||||
|             ) |             ) | ||||||
|         }?token=$token".replace("+", "%20")) |         }?token=$token".replace("+", "%20")) | ||||||
|         if (response.text == "{\"status\":\"Found\",\"data\":[]}") return returnValue // OR ELSE WILL CAUSE WEIRD ERROR |         if (response.text == "{\"status\":\"Found\",\"data\":[]}") return returnValue // OR ELSE WILL CAUSE WEIRD ERROR | ||||||
|         println("QUICK: " + response.text) | 
 | ||||||
|         val mapped = response.let { mapper.readValue<ShiroSearchResponse>(it.text) } |         val mapped = response.let { mapper.readValue<ShiroSearchResponse>(it.text) } | ||||||
|         println("SIZE: " + mapped.data.size) |  | ||||||
|         println("TOTAL: " + mapped) |  | ||||||
|         for (i in mapped.data) { |         for (i in mapped.data) { | ||||||
|             returnValue.add(turnSearchIntoResponse(i)) |             returnValue.add(turnSearchIntoResponse(i)) | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -5,7 +5,7 @@ import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
| import com.lagradost.cloudstream3.utils.Qualities | import com.lagradost.cloudstream3.utils.Qualities | ||||||
| import org.jsoup.Jsoup | import org.jsoup.Jsoup | ||||||
| 
 | 
 | ||||||
| class HDMMoveProvider : MainAPI() { | class HDMProvider : MainAPI() { | ||||||
|     override val name: String |     override val name: String | ||||||
|         get() = "HD Movies" |         get() = "HD Movies" | ||||||
|     override val mainUrl: String |     override val mainUrl: String | ||||||
|  | @ -0,0 +1,187 @@ | ||||||
|  | package com.lagradost.cloudstream3.movieproviders | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.annotation.JsonProperty | ||||||
|  | import com.fasterxml.jackson.module.kotlin.readValue | ||||||
|  | import com.lagradost.cloudstream3.* | ||||||
|  | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
|  | import org.jsoup.Jsoup | ||||||
|  | 
 | ||||||
|  | class LookMovieProvider : MainAPI() { | ||||||
|  |     override val hasQuickSearch: Boolean | ||||||
|  |         get() = true | ||||||
|  | 
 | ||||||
|  |     override val name: String | ||||||
|  |         get() = "LookMovie" | ||||||
|  | 
 | ||||||
|  |     override val mainUrl: String | ||||||
|  |         get() = "https://lookmovie.io" | ||||||
|  | 
 | ||||||
|  |     data class LookMovieSearchResult( | ||||||
|  |         @JsonProperty("backdrop") val backdrop: String?, | ||||||
|  |         @JsonProperty("imdb_rating") val imdb_rating: String, | ||||||
|  |         @JsonProperty("poster") val poster: String?, | ||||||
|  |         @JsonProperty("slug") val slug: String, | ||||||
|  |         @JsonProperty("title") val title: String, | ||||||
|  |         @JsonProperty("year") val year: String?, | ||||||
|  |         //  @JsonProperty("flag_quality") val flag_quality: Int?, | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     data class LookMovieSearchResultRoot( | ||||||
|  |         // @JsonProperty("per_page") val per_page: Int?, | ||||||
|  |         // @JsonProperty("total") val total: Int?, | ||||||
|  |         @JsonProperty("result") val result: List<LookMovieSearchResult>?, | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     data class LookMovieEpisode( | ||||||
|  |         @JsonProperty("title") var title: String, | ||||||
|  |         @JsonProperty("index") var index: String, | ||||||
|  |         @JsonProperty("episode") var episode: String, | ||||||
|  |         @JsonProperty("id_episode") var idEpisode: Int, | ||||||
|  |         @JsonProperty("season") var season: String, | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     override fun quickSearch(query: String): ArrayList<SearchResponse>? { | ||||||
|  |         val movieUrl = "$mainUrl/api/v1/movies/search/?q=$query" | ||||||
|  |         val movieResponse = khttp.get(movieUrl) | ||||||
|  |         val movies = mapper.readValue<LookMovieSearchResultRoot>(movieResponse.text).result | ||||||
|  | 
 | ||||||
|  |         val showsUrl = "$mainUrl/api/v1/shows/search/?q=$query" | ||||||
|  |         val showsResponse = khttp.get(showsUrl) | ||||||
|  |         val shows = mapper.readValue<LookMovieSearchResultRoot>(showsResponse.text).result | ||||||
|  | 
 | ||||||
|  |         val returnValue = ArrayList<SearchResponse>() | ||||||
|  |         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())) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         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())) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return returnValue | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun search(query: String): ArrayList<SearchResponse> { | ||||||
|  |         fun search(query: String, isMovie: Boolean): ArrayList<SearchResponse> { | ||||||
|  |             val url = "$mainUrl/${if (isMovie) "movies" else "shows"}/search/?q=$query" | ||||||
|  |             val response = khttp.get(url) | ||||||
|  |             val document = Jsoup.parse(response.text) | ||||||
|  | 
 | ||||||
|  |             val items = document.select("div.flex-wrap-movielist > div.movie-item-style-1") | ||||||
|  |             val returnValue = ArrayList<SearchResponse>() | ||||||
|  |             items.forEach { item -> | ||||||
|  |                 val titleHolder = item.selectFirst("> div.mv-item-infor > h6 > a") | ||||||
|  |                 val href = fixUrl(titleHolder.attr("href")) | ||||||
|  |                 val name = titleHolder.text() | ||||||
|  |                 val posterHolder = item.selectFirst("> div.image__placeholder > a") | ||||||
|  |                 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 | ||||||
|  |                     ) | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |             return returnValue | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         val movieList = search(query, true) | ||||||
|  |         val seriesList = search(query, false) | ||||||
|  |         movieList.addAll(seriesList) | ||||||
|  |         return movieList | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun loadLinks(data: String, isCasting: Boolean, callback: (ExtractorLink) -> Unit): Boolean { | ||||||
|  |         return super.loadLinks(data, isCasting, callback) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun load(slug: String): LoadResponse? { | ||||||
|  |         val response = khttp.get(slug) | ||||||
|  |         val document = Jsoup.parse(response.text) | ||||||
|  |         val isMovie = slug.contains("/movies/") | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         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 rating = parseRating(watchHeader.selectFirst("> div.movie-rate > div.rate > p > span").text()) | ||||||
|  |         val img = document.selectFirst("div.movie-img > p.movie__poster")?.attr("style") | ||||||
|  |         val poster = if (img.isNullOrEmpty()) null else "url\\((.*?)\\)".toRegex().find(img)?.groupValues?.get(1) | ||||||
|  |         val descript = document.selectFirst("p.description-short").text() | ||||||
|  |         val id = "${if (isMovie) "id_movie" else "id_show"}:(.*?),".toRegex().find(response.text)?.groupValues?.get(1)?.replace(" ", "") | ||||||
|  |             ?: return null | ||||||
|  |         val realSlug = slug.replace("$mainUrl/${if (isMovie) "movies" else "shows"}/view/", "") | ||||||
|  |         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" | ||||||
|  |         println("URLLLL:::: " + realUrl) | ||||||
|  |         //https://lookmovie.io/api/v1/security/show-access?slug=9140554-loki-2021&token=&sk=null&step=1 | ||||||
|  |         //https://lookmovie.io/api/v1/security/movie-access?id_movie=11582&token=1&sk=&step=1 | ||||||
|  | 
 | ||||||
|  |         if (isMovie) { | ||||||
|  |             return MovieLoadResponse(name, slug, this.name, TvType.Movie, id, poster, year, descript, null, rating) | ||||||
|  |         } else { | ||||||
|  |             val window = | ||||||
|  |                 "window\\[\\'show_storage\\'\\] =((.|\\n)*?\\<)".toRegex().find(response.text)?.groupValues?.get(1) | ||||||
|  |                     ?: return null | ||||||
|  |             // val id = "id_show:(.*?),".toRegex().find(response.text)?.groupValues?.get(1) ?: return null | ||||||
|  |             val season = "seasons:.*\\[((.|\\n)*?)]".toRegex().find(window)?.groupValues?.get(1) ?: return null | ||||||
|  |             fun String.fixSeasonJson(replace: String): String { | ||||||
|  |                 return this.replace("$replace:", "\"$replace\":") | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             //https://lookmovie.io/api/v1/security/show-access?slug=9140554-loki-2021&token=&sk=null&step=1 | ||||||
|  |             //https://lookmovie.io/manifests/shows/json/TGv3dO0pcwomftMrywOnmw/1624571222/128848/master.m3u8 | ||||||
|  |             //https://lookmovie.io/api/v1/shows/episode-subtitles/?id_episode=128848 | ||||||
|  | 
 | ||||||
|  |             val json =  season | ||||||
|  |                 .replace("\'", "\"") | ||||||
|  |                 .fixSeasonJson("title") | ||||||
|  |                 .fixSeasonJson("id_episode") | ||||||
|  |                 .fixSeasonJson("episode") | ||||||
|  |                 .fixSeasonJson("index") | ||||||
|  |                 .fixSeasonJson("season") | ||||||
|  |             val realJson = "[" + json.substring(0,json.lastIndexOf(',')) + "]" | ||||||
|  | 
 | ||||||
|  |             val episodes = mapper.readValue<List<LookMovieEpisode>>(realJson).map { | ||||||
|  |                 TvSeriesEpisode(it.title, it.season.toIntOrNull(), it.episode.toIntOrNull(), it.idEpisode.toString()) | ||||||
|  |             }.toList() | ||||||
|  | 
 | ||||||
|  |             return TvSeriesLoadResponse(name, | ||||||
|  |                 slug, | ||||||
|  |                 this.name, | ||||||
|  |                 TvType.TvSeries, | ||||||
|  |                 ArrayList(episodes), | ||||||
|  |                 poster, | ||||||
|  |                 year, | ||||||
|  |                 descript, | ||||||
|  |                 null, | ||||||
|  |                 null, | ||||||
|  |                 rating) | ||||||
|  |         } | ||||||
|  |         //watch-heading | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -94,13 +94,15 @@ class SearchAdapter( | ||||||
|                 cardText.text = card.name |                 cardText.text = card.name | ||||||
| 
 | 
 | ||||||
|                 //imageTextProvider.text = card.apiName |                 //imageTextProvider.text = card.apiName | ||||||
|  |                 if (!card.posterUrl.isNullOrEmpty()) { | ||||||
| 
 | 
 | ||||||
|                 val glideUrl = |                     val glideUrl = | ||||||
|                     GlideUrl(card.posterUrl) |                         GlideUrl(card.posterUrl) | ||||||
|                 activity.let { |                     activity.let { | ||||||
|                     Glide.with(it) |                         Glide.with(it) | ||||||
|                         .load(glideUrl) |                             .load(glideUrl) | ||||||
|                         .into(cardView) |                             .into(cardView) | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 bg.setOnClickListener { |                 bg.setOnClickListener { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue