@@ -11,20 +11,25 @@ import okhttp3.MediaType.Companion.toMediaTypeOrNull
1111import okhttp3.RequestBody.Companion.toRequestBody
1212
1313class MovieboxProvider : MainAPI () {
14-
1514 override var mainUrl = " https://moviebox.ph"
16- private val apiUrl = " https://fmoviesunblocked.net"
15+ private val mainAPIUrl = " https://h5-api.aoneroom.com"
16+ private val secondAPIUrl = " https://filmboom.top"
1717 override val instantLinkLoading = true
1818 override var name = " Moviebox"
1919 override val hasMainPage = true
2020 override val hasQuickSearch = true
2121 override var lang = " id"
22- override val supportedTypes = setOf (TvType .Movie , TvType .TvSeries , TvType .Anime , TvType .AsianDrama )
22+ override val supportedTypes = setOf (
23+ TvType .Movie ,
24+ TvType .TvSeries ,
25+ TvType .Anime ,
26+ TvType .AsianDrama
27+ )
2328
24- override val mainPage = mainPageOf(
29+ override val mainPage: List < MainPageData > = mainPageOf(
2530 " 872031290915189720" to " Trending Now" ,
2631 " 997144265920760504" to " Popular Movie" ,
27- " 5283462032510044280" to " Drama Indonesia Terkini " ,
32+ " 5283462032510044280" to " Latest Indonesian Drama " ,
2833 " 6528093688173053896" to " Trending Indonesian Movies" ,
2934 " 4380734070238626200" to " K-Drama" ,
3035 " 7736026911486755336" to " Western TV" ,
@@ -33,120 +38,247 @@ class MovieboxProvider : MainAPI() {
3338 " 5848753831881965888" to " Indonesian Horror Stories" ,
3439 " 1164329479448281992" to " Thai-Drama" ,
3540 " 7132534597631837112" to " Animated Film" ,
41+ " 1,ForYou" to " Movie ForYou" ,
42+ " 1,Hottest" to " Movie Hottest" ,
43+ " 1,Latest" to " Movie Latest" ,
44+ " 1,Rating" to " Movie Rating" ,
45+ " 2,ForYou" to " TVShow ForYou" ,
46+ " 2,Hottest" to " TVShow Hottest" ,
47+ " 2,Latest" to " TVShow Latest" ,
48+ " 2,Rating" to " TVShow Rating" ,
49+ " 1006,ForYou" to " Animation ForYou" ,
50+ " 1006,Hottest" to " Animation Hottest" ,
51+ " 1006,Latest" to " Animation Latest" ,
52+ " 1006,Rating" to " Animation Rating" ,
3653 )
3754
38- override suspend fun getMainPage (page : Int , request : MainPageRequest ): HomePageResponse {
39- val url = " $mainUrl /wefeed-h5-bff/web/ranking-list/content?id=${request.data} &page=$page &perPage=12"
40- val home = app.get(url).parsedSafe<Media >()?.data?.subjectList?.map { it.toSearchResponse(this ) }
41- ? : throw ErrorLoadingException (" No Data Found" )
55+ override suspend fun getMainPage (
56+ page : Int ,
57+ request : MainPageRequest ,
58+ ): HomePageResponse {
59+
60+ val home = mutableListOf<SearchResponse >()
61+
62+ if (! request.data.contains(" ," )) {
63+ val url = " $mainAPIUrl /wefeed-h5api-bff/ranking-list/content?id=${request.data} &page=$page &perPage=12"
64+
65+ val index = app.get(url).parsedSafe<Media >()?.data?.subjectList?.map {
66+ it.toSearchResponse(this )
67+ } ? : throw ErrorLoadingException (" No Data Found" )
68+
69+ home.addAll(index)
70+ } else {
71+ val params = request.data.split(" ," )
72+ val body = mapOf (
73+ " channelId" to params.first(),
74+ " page" to page,
75+ " perPage" to " 28" ,
76+ " sort" to params.last()
77+ ).toJson().toRequestBody(RequestBodyTypes .JSON .toMediaTypeOrNull())
78+
79+ val index = app.post(" $mainAPIUrl /wefeed-h5api-bff/subject/filter" , requestBody = body)
80+ .parsedSafe<Media >()?.data?.items?.map {
81+ it.toSearchResponse(this )
82+ } ? : throw ErrorLoadingException (" No Data Found" )
83+
84+ home.addAll(index)
85+ }
86+
87+
4288 return newHomePageResponse(request.name, home)
4389 }
4490
4591 override suspend fun quickSearch (query : String ): List <SearchResponse > = search(query)
4692
4793 override suspend fun search (query : String ): List <SearchResponse > {
48- val body = mapOf (" keyword" to query, " page" to " 1" , " perPage" to " 0" , " subjectType" to " 0" )
49- .toJson().toRequestBody(RequestBodyTypes .JSON .toMediaTypeOrNull())
50- return app.post(" $mainUrl /wefeed-h5-bff/web/subject/search" , requestBody = body)
51- .parsedSafe<Media >()?.data?.items?.map { it.toSearchResponse(this ) } ? : throw ErrorLoadingException ()
94+ return app.post(
95+ " $secondAPIUrl /wefeed-h5-bff/web/subject/search" , requestBody = mapOf (
96+ " keyword" to query,
97+ " page" to " 1" ,
98+ " perPage" to " 0" ,
99+ " subjectType" to " 0" ,
100+ ).toJson().toRequestBody(RequestBodyTypes .JSON .toMediaTypeOrNull())
101+ ).parsedSafe<Media >()?.data?.items?.map { it.toSearchResponse(this ) }
102+ ? : throw ErrorLoadingException ()
52103 }
53104
54105 override suspend fun load (url : String ): LoadResponse {
55106 val id = url.substringAfterLast(" /" )
56- val doc = app.get(" $mainUrl /wefeed-h5-bff/web/subject/detail?subjectId=$id " ).parsedSafe<MediaDetail >()?.data
57- val subject = doc?.subject
107+ val document = app.get(" $secondAPIUrl /wefeed-h5-bff/web/subject/detail?subjectId=$id " )
108+ .parsedSafe<MediaDetail >()?.data
109+ val subject = document?.subject
58110 val title = subject?.title ? : " "
59111 val poster = subject?.cover?.url
60112 val tags = subject?.genre?.split(" ," )?.map { it.trim() }
113+
61114 val year = subject?.releaseDate?.substringBefore(" -" )?.toIntOrNull()
62115 val tvType = if (subject?.subjectType == 2 ) TvType .TvSeries else TvType .Movie
63116 val description = subject?.description
64117 val trailer = subject?.trailer?.videoAddress?.url
65- val mediaScore = subject?.imdbRatingValue?.toDoubleOrNull()?.let { Score .from10(it) }
66- val actors = doc?.stars?.mapNotNull { cast ->
67- ActorData (Actor (cast.name ? : return @mapNotNull null , cast.avatarUrl), roleString = cast.character)
118+ val rating = subject?.imdbRatingValue?.toIntOrNull()
119+ val actors = document?.stars?.mapNotNull { cast ->
120+ ActorData (
121+ Actor (
122+ cast.name ? : return @mapNotNull null ,
123+ cast.avatarUrl
124+ ),
125+ roleString = cast.character
126+ )
68127 }?.distinctBy { it.actor }
69- val recommendations = app.get(" $mainUrl /wefeed-h5-bff/web/subject/detail-rec?subjectId=$id &page=1&perPage=12" )
70- .parsedSafe<Media >()?.data?.items?.map { it.toSearchResponse(this ) }
128+
129+ val recommendations =
130+ app.get(" $mainUrl /wefeed-h5-bff/web/subject/detail-rec?subjectId=$id &page=1&perPage=12" )
131+ .parsedSafe<Media >()?.data?.items?.map {
132+ it.toSearchResponse(this )
133+ }
71134
72135 return if (tvType == TvType .TvSeries ) {
73- val episodes = doc?.resource?.seasons?.map { seasons ->
74- (if (seasons.allEp.isNullOrEmpty()) (1 .. seasons.maxEp!! ) else seasons.allEp.split(" ," ).map { it.toInt() })
75- .map { episode -> newEpisode(LoadData (id, seasons.se, episode, subject?.detailPath).toJson()) {
76- this .season = seasons.se
77- this .episode = episode
78- }}
136+ val episode = document?.resource?.seasons?.map { seasons ->
137+ (if (seasons.allEp.isNullOrEmpty()) (1 .. seasons.maxEp!! ) else seasons.allEp.split(" ," )
138+ .map { it.toInt() })
139+ .map { episode ->
140+ newEpisode(
141+ LoadData (
142+ id,
143+ seasons.se,
144+ episode,
145+ subject?.detailPath
146+ ).toJson()
147+ ) {
148+ this .season = seasons.se
149+ this .episode = episode
150+ }
151+ }
79152 }?.flatten() ? : emptyList()
80- newTvSeriesLoadResponse(title, url, TvType .TvSeries , episodes ) {
153+ newTvSeriesLoadResponse(title, url, TvType .TvSeries , episode ) {
81154 this .posterUrl = poster
82155 this .year = year
83156 this .plot = description
84157 this .tags = tags
85- this .score = mediaScore
158+ this .score = Score .from10(rating)
86159 this .actors = actors
87160 this .recommendations = recommendations
88161 addTrailer(trailer, addRaw = true )
89162 }
90163 } else {
91- newMovieLoadResponse(title, url, TvType .Movie , LoadData (id, detailPath = subject?.detailPath).toJson()) {
164+ newMovieLoadResponse(
165+ title,
166+ url,
167+ TvType .Movie ,
168+ LoadData (id, detailPath = subject?.detailPath).toJson()
169+ ) {
92170 this .posterUrl = poster
93171 this .year = year
94172 this .plot = description
95173 this .tags = tags
96- this .score = mediaScore
174+ this .score = Score .from10(rating)
97175 this .actors = actors
98176 this .recommendations = recommendations
99177 addTrailer(trailer, addRaw = true )
100178 }
101179 }
102180 }
103181
104- override suspend fun loadLinks (data : String , isCasting : Boolean , subtitleCallback : (SubtitleFile ) -> Unit , callback : (ExtractorLink ) -> Unit ): Boolean {
182+ override suspend fun loadLinks (
183+ data : String ,
184+ isCasting : Boolean ,
185+ subtitleCallback : (SubtitleFile ) -> Unit ,
186+ callback : (ExtractorLink ) -> Unit
187+ ): Boolean {
188+
105189 val media = parseJson<LoadData >(data)
106- val referer = " $apiUrl /spa/videoPlayPage/movies/${media.detailPath} ?id=${media.id} &type=/movie/detail&lang=en"
107- val streams = app.get(" $apiUrl /wefeed-h5-bff/web/subject/play?subjectId=${media.id} &se=${media.season ? : 0 } &ep=${media.episode ? : 0 } " , referer = referer)
108- .parsedSafe<Media >()?.data?.streams
109-
110- streams?.reversed()?.distinctBy { it.url }?.forEach { source ->
111- callback(newExtractorLink(this .name, this .name, source.url ? : return @forEach, INFER_TYPE ) {
112- this .referer = " $apiUrl /"
113- this .quality = getQualityFromName(source.resolutions)
114- })
190+ val referer = " $secondAPIUrl /spa/videoPlayPage/movies/${media.detailPath} ?id=${media.id} &type=/movie/detail&lang=en"
191+
192+ val streams = app.get(
193+ " $secondAPIUrl /wefeed-h5-bff/web/subject/play?subjectId=${media.id} &se=${media.season ? : 0 } &ep=${media.episode ? : 0 } " ,
194+ referer = referer
195+ ).parsedSafe<Media >()?.data?.streams
196+
197+ streams?.reversed()?.distinctBy { it.url }?.map { source ->
198+ callback.invoke(
199+ newExtractorLink(
200+ this .name,
201+ this .name,
202+ source.url ? : return @map,
203+ INFER_TYPE
204+ ) {
205+ this .referer = " $secondAPIUrl /"
206+ this .quality = getQualityFromName(source.resolutions)
207+ }
208+ )
115209 }
116210
117211 val id = streams?.first()?.id
118212 val format = streams?.first()?.format
119- app.get(" $apiUrl /wefeed-h5-bff/web/subject/caption?format=$format &id=$id &subjectId=${media.id} " , referer = referer)
120- .parsedSafe<Media >()?.data?.captions?.forEach { subtitle ->
121- subtitleCallback(SubtitleFile (subtitle.lanName ? : " " , subtitle.url ? : return @forEach))
122- }
213+
214+ app.get(
215+ " $secondAPIUrl /wefeed-h5-bff/web/subject/caption?format=$format &id=$id &subjectId=${media.id} " ,
216+ referer = referer
217+ ).parsedSafe<Media >()?.data?.captions?.map { subtitle ->
218+ subtitleCallback.invoke(
219+ newSubtitleFile(
220+ subtitle.lanName ? : " " ,
221+ subtitle.url ? : return @map
222+ )
223+ )
224+ }
123225
124226 return true
125227 }
126228
127- data class LoadData (val id : String? = null , val season : Int? = null , val episode : Int? = null , val detailPath : String? = null )
229+ data class LoadData (
230+ val id : String? = null ,
231+ val season : Int? = null ,
232+ val episode : Int? = null ,
233+ val detailPath : String? = null ,
234+ )
128235
129- data class Media (@JsonProperty(" data" ) val data : Data ? = null ) {
236+ data class Media (
237+ @JsonProperty(" data" ) val data : Data ? = null ,
238+ ) {
130239 data class Data (
131240 @JsonProperty(" subjectList" ) val subjectList : ArrayList <Items >? = arrayListOf(),
132241 @JsonProperty(" items" ) val items : ArrayList <Items >? = arrayListOf(),
133242 @JsonProperty(" streams" ) val streams : ArrayList <Streams >? = arrayListOf(),
134- @JsonProperty(" captions" ) val captions : ArrayList <Captions >? = arrayListOf()
243+ @JsonProperty(" captions" ) val captions : ArrayList <Captions >? = arrayListOf(),
135244 ) {
136- data class Streams (@JsonProperty(" id" ) val id : String? = null , @JsonProperty(" format" ) val format : String? = null , @JsonProperty(" url" ) val url : String? = null , @JsonProperty(" resolutions" ) val resolutions : String? = null )
137- data class Captions (@JsonProperty(" lan" ) val lan : String? = null , @JsonProperty(" lanName" ) val lanName : String? = null , @JsonProperty(" url" ) val url : String? = null )
245+ data class Streams (
246+ @JsonProperty(" id" ) val id : String? = null ,
247+ @JsonProperty(" format" ) val format : String? = null ,
248+ @JsonProperty(" url" ) val url : String? = null ,
249+ @JsonProperty(" resolutions" ) val resolutions : String? = null ,
250+ )
251+
252+ data class Captions (
253+ @JsonProperty(" lan" ) val lan : String? = null ,
254+ @JsonProperty(" lanName" ) val lanName : String? = null ,
255+ @JsonProperty(" url" ) val url : String? = null ,
256+ )
138257 }
139258 }
140259
141- data class MediaDetail (@JsonProperty(" data" ) val data : Data ? = null ) {
260+ data class MediaDetail (
261+ @JsonProperty(" data" ) val data : Data ? = null ,
262+ ) {
142263 data class Data (
143264 @JsonProperty(" subject" ) val subject : Items ? = null ,
144265 @JsonProperty(" stars" ) val stars : ArrayList <Stars >? = arrayListOf(),
145- @JsonProperty(" resource" ) val resource : Resource ? = null
266+ @JsonProperty(" resource" ) val resource : Resource ? = null ,
146267 ) {
147- data class Stars (@JsonProperty(" name" ) val name : String? = null , @JsonProperty(" character" ) val character : String? = null , @JsonProperty(" avatarUrl" ) val avatarUrl : String? = null )
148- data class Resource (@JsonProperty(" seasons" ) val seasons : ArrayList <Seasons >? = arrayListOf()) {
149- data class Seasons (@JsonProperty(" se" ) val se : Int? = null , @JsonProperty(" maxEp" ) val maxEp : Int? = null , @JsonProperty(" allEp" ) val allEp : String? = null )
268+ data class Stars (
269+ @JsonProperty(" name" ) val name : String? = null ,
270+ @JsonProperty(" character" ) val character : String? = null ,
271+ @JsonProperty(" avatarUrl" ) val avatarUrl : String? = null ,
272+ )
273+
274+ data class Resource (
275+ @JsonProperty(" seasons" ) val seasons : ArrayList <Seasons >? = arrayListOf(),
276+ ) {
277+ data class Seasons (
278+ @JsonProperty(" se" ) val se : Int? = null ,
279+ @JsonProperty(" maxEp" ) val maxEp : Int? = null ,
280+ @JsonProperty(" allEp" ) val allEp : String? = null ,
281+ )
150282 }
151283 }
152284 }
@@ -163,16 +295,31 @@ class MovieboxProvider : MainAPI() {
163295 @JsonProperty(" imdbRatingValue" ) val imdbRatingValue : String? = null ,
164296 @JsonProperty(" countryName" ) val countryName : String? = null ,
165297 @JsonProperty(" trailer" ) val trailer : Trailer ? = null ,
166- @JsonProperty(" detailPath" ) val detailPath : String? = null
298+ @JsonProperty(" detailPath" ) val detailPath : String? = null ,
167299 ) {
300+
168301 fun toSearchResponse (provider : MovieboxProvider ): SearchResponse {
169- return provider.newMovieSearchResponse(title ? : " " , subjectId!! , if (subjectType == 1 ) TvType .Movie else TvType .TvSeries , false ) {
302+ return provider.newMovieSearchResponse(
303+ title ? : " " ,
304+ subjectId ? : " " ,
305+ if (subjectType == 1 ) TvType .Movie else TvType .TvSeries ,
306+ false
307+ ) {
170308 this .posterUrl = cover?.url
171309 }
172310 }
173- data class Cover (@JsonProperty(" url" ) val url : String? = null )
174- data class Trailer (@JsonProperty(" videoAddress" ) val videoAddress : VideoAddress ? = null ) {
175- data class VideoAddress (@JsonProperty(" url" ) val url : String? = null )
311+
312+ data class Cover (
313+ @JsonProperty(" url" ) val url : String? = null ,
314+ )
315+
316+ data class Trailer (
317+ @JsonProperty(" videoAddress" ) val videoAddress : VideoAddress ? = null ,
318+ ) {
319+ data class VideoAddress (
320+ @JsonProperty(" url" ) val url : String? = null ,
321+ )
176322 }
177323 }
178- }
324+
325+ }
0 commit comments