@@ -18,7 +18,7 @@ class Anoboy : MainAPI() {
1818 override var lang = " id"
1919
2020 override val supportedTypes = setOf (
21- TvType .Anime
21+ TvType .Anime , TvType . AnimeMovie , TvType . OVA
2222 )
2323
2424 companion object {
@@ -42,21 +42,25 @@ class Anoboy : MainAPI() {
4242 }
4343
4444 override val mainPage = mainPageOf(
45- " anime/" to " Latest Added" ,
46- " anime/ongoing/" to " Ongoing" ,
47- " anime-movie/" to " Movie"
45+ " " to " New Update" ,
46+ " category/anime" to " Latest Added" ,
47+ " category/live-action-movie" to " Live Action" ,
48+ " category/anime-movie" to " Movie" ,
49+ " category/donghua" to " Donghua"
4850 )
4951
5052 override suspend fun getMainPage (page : Int , request : MainPageRequest ): HomePageResponse {
51- val path = request.data.trimStart (' /' )
53+ val path = request.data.trim (' /' )
5254 val url = if (page <= 1 ) {
53- " $mainUrl /$path "
55+ if (path.isEmpty()) mainUrl else " $mainUrl /$path / "
5456 } else {
55- " $mainUrl /$path " + " page/$page /"
57+ if (path.isEmpty()) " $mainUrl /page/ $page / " else " $mainUrl / $path / page/$page /"
5658 }
5759 val document = app.get(url).document
58- val items = document.select(" div.column-content > a[href]:has(div.amv)" )
60+
61+ val items = document.select(" a[href]:has(div.amv), a[href]:has(div#amv)" )
5962 .mapNotNull { it.toSearchResult() }
63+
6064 return newHomePageResponse(request.name, items)
6165 }
6266
@@ -65,16 +69,21 @@ val path = request.data.trimStart('/')
6569 if (link.isBlank()) return null
6670
6771 val title = attr(" title" ).trim().ifBlank {
68- selectFirst(" h3.ibox1" )?.text()?.trim().orEmpty()
72+ selectFirst(" h3.ibox1, h3.ibox " )?.text()?.trim().orEmpty()
6973 }.ifBlank {
7074 selectFirst(" img" )?.attr(" alt" )?.trim().orEmpty()
7175 }
7276 if (title.isBlank()) return null
7377
74- val isMovie = link.contains(" /anime-movie/" , true ) || title.contains(" movie" , true )
78+ val isMovie = link.contains(" /anime-movie/" , true ) || link.contains( " /live-action-movie/ " , true ) || title.contains(" movie" , true )
7579 val isOva = title.contains(" ova" , true ) || title.contains(" special" , true )
76- if (isMovie || isOva) return null
77- val tvType = if (isMovie) TvType .AnimeMovie else TvType .Anime
80+
81+ val tvType = when {
82+ isMovie -> TvType .AnimeMovie
83+ isOva -> TvType .OVA
84+ else -> TvType .Anime
85+ }
86+
7887 val poster = selectFirst(" img" )?.getImageAttr()?.let { fixUrlNull(it) }
7988
8089 return newAnimeSearchResponse(title, fixUrl(link), tvType) {
@@ -87,18 +96,25 @@ val path = request.data.trimStart('/')
8796 val title = selectFirst(" div.tt" )?.text()?.trim()
8897 ? : selectFirst(" a" )?.attr(" title" )?.trim()
8998 ? : return null
90- val isMovie = link.contains(" /anime-movie/" , true ) || title.contains(" movie" , true )
99+
100+ val isMovie = link.contains(" /anime-movie/" , true ) || link.contains(" /live-action-movie/" , true ) || title.contains(" movie" , true )
91101 val isOva = title.contains(" ova" , true ) || title.contains(" special" , true )
92- if (isMovie || isOva) return null
102+
103+ val tvType = when {
104+ isMovie -> TvType .AnimeMovie
105+ isOva -> TvType .OVA
106+ else -> TvType .Anime
107+ }
108+
93109 val poster = selectFirst(" img" )?.getImageAttr()?.let { fixUrlNull(it) }
94- return newAnimeSearchResponse(title, fixUrl(link), TvType . Anime ) {
110+ return newAnimeSearchResponse(title, fixUrl(link), tvType ) {
95111 posterUrl = poster
96112 }
97113 }
98114
99115 override suspend fun search (query : String ): List <SearchResponse > {
100116 val document = app.get(" $mainUrl /?s=$query " ).document
101- val modernResults = document.select(" div.column-content > a[href]:has(div. amv)" )
117+ val modernResults = document.select(" a[href]:has( div.amv), a[href]:has(div# amv)" )
102118 .mapNotNull { it.toSearchResult() }
103119 if (modernResults.isNotEmpty()) return modernResults
104120 return document.select(" div.listupd article.bs" )
@@ -113,15 +129,20 @@ val path = request.data.trimStart('/')
113129 }
114130 if (href.isBlank()) return null
115131
116- val title = selectFirst(" h3.ibox1" )?.text()?.trim()
132+ val title = selectFirst(" h3.ibox1, h3.ibox " )?.text()?.trim()
117133 ? : selectFirst(" div.tt" )?.text()?.trim()
118134 ? : attr(" title" ).trim().ifBlank { null }
119135 ? : return null
120136
121- val isMovie = href.contains(" /anime-movie/" , true ) || title.contains(" movie" , true )
137+ val isMovie = href.contains(" /anime-movie/" , true ) || href.contains( " /live-action-movie/ " , true ) || title.contains(" movie" , true )
122138 val isOva = title.contains(" ova" , true ) || title.contains(" special" , true )
123- if (isMovie || isOva) return null
124- val tvType = if (isMovie) TvType .AnimeMovie else TvType .Anime
139+
140+ val tvType = when {
141+ isMovie -> TvType .AnimeMovie
142+ isOva -> TvType .OVA
143+ else -> TvType .Anime
144+ }
145+
125146 val posterUrl = selectFirst(" img" )?.getImageAttr()?.let { fixUrlNull(it) }
126147
127148 return newAnimeSearchResponse(title, fixUrl(href), tvType) {
@@ -134,7 +155,7 @@ val path = request.data.trimStart('/')
134155
135156 val title = document.selectFirst(" h1.entry-title, h2.entry-title" )?.text()?.trim().orEmpty()
136157 val poster = document
137- .selectFirst(" div.column-three-fourth > img, div.column-content > img, div.bigcontent img" )
158+ .selectFirst(" div.column-three-fourth > img, div.column-content > img, div.bigcontent img, div.entry-content img " )
138159 ?.getImageAttr()
139160 ?.let { fixUrlNull(it) }
140161
@@ -192,7 +213,7 @@ val path = request.data.trimStart('/')
192213 ?.attr(" src" )
193214 val status = getStatus(getTableValue(" Status" ))
194215
195- val recommendations = document.select(" div.column-content > a[href]:has(div. amv), div.listupd article.bs" )
216+ val recommendations = document.select(" a[href]:has( div.amv), a[href]:has(div# amv), div.listupd article.bs" )
196217 .mapNotNull { it.toRecommendResult() }
197218 .distinctBy { it.url }
198219
@@ -624,7 +645,6 @@ val path = request.data.trimStart('/')
624645 fun resolveUrl (raw : String? , base : String ): String? {
625646 if (! isValidUrl(raw)) return null
626647 var clean = raw!! .trim()
627- // Some legacy Anoboy acbatch pages output broken query values where '+' becomes ' '.
628648 if (clean.contains(" /uploads/stream/" , true ) && clean.contains(" data=" , true )) {
629649 clean = clean.replace(" " , " +" )
630650 }
@@ -746,12 +766,10 @@ val path = request.data.trimStart('/')
746766 val nestedDoc = app.get(next, referer = requestReferer).document
747767 extractFromDoc(next, nestedDoc)
748768 } catch (_: Exception ) {
749- // skip dead mirror page
750769 }
751770 }
752771
753772 if (discoveredUrls.isEmpty() && document != null ) {
754- // fallback for old mirrored options stored as base64 iframe html
755773 val mirrorOptions = document.select(" select.mirror option[value]:not([disabled])" )
756774 for (opt in mirrorOptions) {
757775 val base64 = opt.attr(" value" )
@@ -762,7 +780,6 @@ val path = request.data.trimStart('/')
762780 queueUrl(iframe, requestReferer)
763781 }
764782 } catch (_: Exception ) {
765- // ignore broken base64 mirrors
766783 }
767784 }
768785 }
@@ -1005,7 +1022,6 @@ val path = request.data.trimStart('/')
10051022 }
10061023 .forEach { resolveLegacyMirrorPage(it) }
10071024
1008- // Try Blogger first, then continue with all other mirrors so users can switch sources.
10091025 bloggerLinks.distinct().forEach { link ->
10101026 if (! emitBloggerDirectLinks(link, requestReferer)) {
10111027 bloggerExtractor.getUrl(link, requestReferer, subtitleCallback, callbackWrapper)
0 commit comments