Skip to content

Commit 8ddc9a8

Browse files
test
1 parent d923c16 commit 8ddc9a8

1 file changed

Lines changed: 51 additions & 51 deletions

File tree

  • DubbindoProvider/src/main/kotlin/com/dubbindo

DubbindoProvider/src/main/kotlin/com/dubbindo/Dubbindo.kt

Lines changed: 51 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -25,45 +25,68 @@ class Dubbindo : MainAPI() {
2525
)
2626

2727
override val mainPage = mainPageOf(
28-
"$mainUrl/videos/category/1" to "Movie",
29-
"$mainUrl/videos/category/3" to "TV Series",
30-
"$mainUrl/videos/category/5" to "Anime Series",
31-
"$mainUrl/videos/category/4" to "Anime Movie",
28+
"$mainUrl/videos/category/1" to "Movie",
29+
"$mainUrl/videos/category/3" to "TV Series",
30+
"$mainUrl/videos/category/5" to "Anime Series",
31+
"$mainUrl/videos/category/4" to "Anime Movie",
3232
"$mainUrl/videos/category/other" to "Other",
3333
)
3434

3535
override suspend fun getMainPage(
3636
page: Int,
3737
request: MainPageRequest
3838
): HomePageResponse {
39+
// Pagination menggunakan ?page_id= (konfirmasi dari HTML)
3940
val document = app.get("${request.data}?page_id=$page").document
4041

41-
// FIX: Selector diperbarui sesuai struktur HTML aktual website.
42-
// Website menggunakan div.video-list sebagai container kartu video,
43-
// bukan div.video-wrapper seperti sebelumnya.
44-
val home = document.select("div.video-list")
45-
.mapNotNull {
46-
it.toSearchResult()
47-
}
42+
// FIX: Halaman category menggunakan "div.video-wrapper" bukan "div.video-list"
43+
val home = document.select("div.video-wrapper")
44+
.mapNotNull { it.toCategoryResult() }
45+
4846
return newHomePageResponse(
4947
list = HomePageList(
5048
name = request.name,
5149
list = home,
5250
isHorizontalImages = true
5351
),
54-
hasNext = true
52+
hasNext = home.isNotEmpty()
5553
)
5654
}
5755

56+
// Untuk kartu di halaman category: div.video-wrapper
57+
// Struktur: div.video-thumb > a[href] + img[src]
58+
// div.video-title > a > h4
59+
private fun Element.toCategoryResult(): TvSeriesSearchResponse? {
60+
val title = this.selectFirst("div.video-title h4")?.text()?.trim()
61+
?: return null
62+
if (title.isEmpty()) return null
63+
64+
val href = this.selectFirst("div.video-thumb a")?.attr("href")
65+
?: this.selectFirst("a")?.attr("href")
66+
?: return null
67+
68+
val posterUrl = fixUrlNull(
69+
this.selectFirst("div.video-thumb img")?.attr("src")
70+
)
71+
72+
return newTvSeriesSearchResponse(title, href, TvType.TvSeries) {
73+
this.posterUrl = posterUrl
74+
}
75+
}
76+
77+
// Untuk kartu di hasil search: div.video-list
5878
private fun Element.toSearchResult(): TvSeriesSearchResponse? {
59-
// FIX: Selector title disesuaikan dengan struktur HTML baru.
60-
// Judul ada di dalam div.video-list-title > a > h4
61-
val title = this.selectFirst("div.video-list-title h4, h4")?.text()?.trim() ?: return null
62-
// Ambil href dari link gambar/thumbnail (link pertama di dalam div.video-list-image)
79+
val title = this.selectFirst("div.video-list-title h4")?.text()?.trim()
80+
?: this.selectFirst("h4")?.text()?.trim()
81+
?: return null
82+
if (title.isEmpty()) return null
83+
6384
val href = this.selectFirst("div.video-list-image a")?.attr("href")
6485
?: this.selectFirst("a")?.attr("href")
6586
?: return null
87+
6688
val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src"))
89+
6790
return newTvSeriesSearchResponse(title, href, TvType.TvSeries) {
6891
this.posterUrl = posterUrl
6992
}
@@ -72,16 +95,9 @@ class Dubbindo : MainAPI() {
7295
override suspend fun search(query: String): List<SearchResponse> {
7396
val searchResponse = mutableListOf<SearchResponse>()
7497
for (i in 1..10) {
75-
val document =
76-
app.get(
77-
"$mainUrl/search?keyword=$query&page_id=$i",
78-
).document
79-
80-
// FIX: Selector search juga diperbarui ke div.video-list
98+
val document = app.get("$mainUrl/search?keyword=$query&page_id=$i").document
8199
val results = document.select("div.video-list")
82-
.mapNotNull {
83-
it.toSearchResult()
84-
}
100+
.mapNotNull { it.toSearchResult() }
85101
searchResponse.addAll(results)
86102
if (results.isEmpty()) break
87103
}
@@ -91,8 +107,6 @@ class Dubbindo : MainAPI() {
91107
override suspend fun load(url: String): LoadResponse? {
92108
val document = app.get(url).document
93109

94-
// FIX: Ambil title dari meta tag agar bisa dipakai di kedua jenis halaman,
95-
// lalu bersihkan nama site-nya.
96110
val title = (document.selectFirst("meta[name=title]")?.attr("content")
97111
?: document.title())
98112
.replace(" | UVideo", "").trim()
@@ -101,22 +115,14 @@ class Dubbindo : MainAPI() {
101115
val poster = document.selectFirst("meta[property=og:image]")?.attr("content")
102116
val tags = document.select("div.pt_categories li a").map { it.text() }
103117

104-
// FIX: Tangani dua jenis halaman detail:
105-
// 1. /articles/read/... → link video ada di div.read-article-text a
106-
// 2. /watch/... → sumber video ada di video#my-video source
107118
return if (url.contains("/articles/read/")) {
108119
// --- Halaman Artikel ---
109120
val description = document.selectFirst("div.read-article-description article")?.text()
110-
111-
// Kumpulkan semua link video/extractor dari body artikel
112121
val videoLinks = document.select("div.read-article-text a")
113122
.map { it.attr("href") }
114123
.filter { it.isNotBlank() }
115-
116-
// Related videos di artikel menggunakan div.related-video-wrapper
117-
val recommendations = document.select("div.related-video-wrapper").mapNotNull {
118-
it.toRelatedResult()
119-
}
124+
val recommendations = document.select("div.related-video-wrapper")
125+
.mapNotNull { it.toRelatedResult() }
120126

121127
newMovieLoadResponse(title, url, TvType.Movie, videoLinks.toJson()) {
122128
posterUrl = poster
@@ -126,16 +132,14 @@ class Dubbindo : MainAPI() {
126132
}
127133
} else {
128134
// --- Halaman Watch ---
129-
val description = document.select("div.watch-video-description p").text().replace("\u2063", "").trim()
130-
131-
val recommendations = document.select("div.related-video-wrapper").mapNotNull {
132-
it.toRelatedResult()
133-
}
134-
135+
val description = document.select("div.watch-video-description p")
136+
.text().replace("\u2063", "").trim()
137+
val recommendations = document.select("div.related-video-wrapper")
138+
.mapNotNull { it.toRelatedResult() }
135139
val video = document.select("video#my-video source").map {
136140
Video(
137141
it.attr("src"),
138-
it.attr("res"), // FIX: was "size" — atribut di HTML adalah "res"
142+
it.attr("res"), // atribut resolusi di HTML adalah "res"
139143
it.attr("type"),
140144
)
141145
}
@@ -149,8 +153,7 @@ class Dubbindo : MainAPI() {
149153
}
150154
}
151155

152-
// FIX: Fungsi khusus untuk mengambil related video dari div.related-video-wrapper
153-
// (struktur berbeda dari div.video-list di halaman utama)
156+
// Related video di sidebar: div.related-video-wrapper
154157
private fun Element.toRelatedResult(): TvSeriesSearchResponse? {
155158
val title = this.selectFirst("div.video-title a")?.text()?.trim()
156159
?: this.selectFirst("a")?.text()?.trim()
@@ -170,8 +173,7 @@ class Dubbindo : MainAPI() {
170173
subtitleCallback: (SubtitleFile) -> Unit,
171174
callback: (ExtractorLink) -> Unit
172175
): Boolean {
173-
174-
// FIX: Coba parse sebagai List<Video> dulu (halaman watch)
176+
// Parse sebagai List<Video> → halaman watch (mp4 langsung)
175177
val videos = tryParseJson<List<Video>>(data)
176178
if (videos != null) {
177179
videos.map { video ->
@@ -193,8 +195,7 @@ class Dubbindo : MainAPI() {
193195
return true
194196
}
195197

196-
// FIX: Jika bukan List<Video>, coba parse sebagai List<String>
197-
// (halaman artikel dengan link extractor langsung)
198+
// Parse sebagai List<String> → halaman artikel (link extractor)
198199
val urls = tryParseJson<List<String>>(data)
199200
if (urls != null) {
200201
urls.forEach { videoUrl ->
@@ -213,5 +214,4 @@ class Dubbindo : MainAPI() {
213214
val res: String? = null,
214215
val type: String? = null,
215216
)
216-
217217
}

0 commit comments

Comments
 (0)