diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt index cb30f6da..1282625f 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt @@ -7,7 +7,8 @@ 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.HDMMoveProvider +import com.lagradost.cloudstream3.movieproviders.HDMProvider +import com.lagradost.cloudstream3.movieproviders.LookMovieProvider import com.lagradost.cloudstream3.movieproviders.MeloMovieProvider import com.lagradost.cloudstream3.utils.ExtractorLink import java.util.* @@ -30,7 +31,8 @@ object APIHolder { ShiroProvider(), MeloMovieProvider(), DubbedAnimeProvider(), - HDMMoveProvider(), + HDMProvider(), + LookMovieProvider(), ) 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 { if(url.startsWith("http")) { return url @@ -168,6 +176,7 @@ interface LoadResponse { val posterUrl: String? val year: Int? val plot: String? + val rating : Int? // 0-100 } fun LoadResponse?.isEpisodeBased(): Boolean { @@ -203,6 +212,7 @@ data class AnimeLoadResponse( val malId: Int? = null, val anilistId: Int? = null, + override val rating: Int? = null, ) : LoadResponse data class MovieLoadResponse( @@ -217,6 +227,7 @@ data class MovieLoadResponse( override val plot: String?, val imdbId: Int?, + override val rating: Int? = null, ) : LoadResponse 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 imdbId: Int?, + override val rating: Int? = null, ) : LoadResponse \ 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 c7a9a79f..47de0223 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ShiroProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ShiroProvider.kt @@ -174,10 +174,8 @@ class ShiroProvider : MainAPI() { ) }?token=$token".replace("+", "%20")) if (response.text == "{\"status\":\"Found\",\"data\":[]}") return returnValue // OR ELSE WILL CAUSE WEIRD ERROR - println("QUICK: " + response.text) + val mapped = response.let { mapper.readValue(it.text) } - println("SIZE: " + mapped.data.size) - println("TOTAL: " + mapped) for (i in mapped.data) { returnValue.add(turnSearchIntoResponse(i)) } diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/HDMMoveProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/HDMProvider.kt similarity index 98% rename from app/src/main/java/com/lagradost/cloudstream3/movieproviders/HDMMoveProvider.kt rename to app/src/main/java/com/lagradost/cloudstream3/movieproviders/HDMProvider.kt index 63c1a3e4..90511ec1 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/HDMMoveProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/HDMProvider.kt @@ -5,7 +5,7 @@ import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.Qualities import org.jsoup.Jsoup -class HDMMoveProvider : MainAPI() { +class HDMProvider : MainAPI() { override val name: String get() = "HD Movies" override val mainUrl: String diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/LookMovieProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/LookMovieProvider.kt new file mode 100644 index 00000000..e6745faa --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/LookMovieProvider.kt @@ -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?, + ) + + 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? { + val movieUrl = "$mainUrl/api/v1/movies/search/?q=$query" + val movieResponse = khttp.get(movieUrl) + val movies = mapper.readValue(movieResponse.text).result + + val showsUrl = "$mainUrl/api/v1/shows/search/?q=$query" + val showsResponse = khttp.get(showsUrl) + val shows = mapper.readValue(showsResponse.text).result + + val returnValue = ArrayList() + 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 { + fun search(query: String, isMovie: Boolean): ArrayList { + 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() + 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>(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 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchAdaptor.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchAdaptor.kt index 5cd47546..d383c0cc 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchAdaptor.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchAdaptor.kt @@ -94,13 +94,15 @@ class SearchAdapter( cardText.text = card.name //imageTextProvider.text = card.apiName + if (!card.posterUrl.isNullOrEmpty()) { - val glideUrl = - GlideUrl(card.posterUrl) - activity.let { - Glide.with(it) - .load(glideUrl) - .into(cardView) + val glideUrl = + GlideUrl(card.posterUrl) + activity.let { + Glide.with(it) + .load(glideUrl) + .into(cardView) + } } bg.setOnClickListener {