diff --git a/src/tr/hdfilmcehennemi/AndroidManifest.xml b/src/tr/hdfilmcehennemi/AndroidManifest.xml index 06e3c8fbc6..0b937f4f7c 100644 --- a/src/tr/hdfilmcehennemi/AndroidManifest.xml +++ b/src/tr/hdfilmcehennemi/AndroidManifest.xml @@ -13,7 +13,7 @@ diff --git a/src/tr/hdfilmcehennemi/build.gradle b/src/tr/hdfilmcehennemi/build.gradle index 2ceb8bd3a9..eb61b91f04 100644 --- a/src/tr/hdfilmcehennemi/build.gradle +++ b/src/tr/hdfilmcehennemi/build.gradle @@ -1,7 +1,7 @@ ext { extName = 'HDFilmCehennemi' extClass = '.HDFilmCehennemi' - extVersionCode = 18 + extVersionCode = 19 isNsfw = true } diff --git a/src/tr/hdfilmcehennemi/src/eu/kanade/tachiyomi/animeextension/tr/hdfilmcehennemi/HDFilmCehennemi.kt b/src/tr/hdfilmcehennemi/src/eu/kanade/tachiyomi/animeextension/tr/hdfilmcehennemi/HDFilmCehennemi.kt index f37e51ba4e..4d0cd18c2e 100644 --- a/src/tr/hdfilmcehennemi/src/eu/kanade/tachiyomi/animeextension/tr/hdfilmcehennemi/HDFilmCehennemi.kt +++ b/src/tr/hdfilmcehennemi/src/eu/kanade/tachiyomi/animeextension/tr/hdfilmcehennemi/HDFilmCehennemi.kt @@ -4,6 +4,7 @@ import android.app.Application import androidx.preference.ListPreference import androidx.preference.PreferenceScreen import eu.kanade.tachiyomi.animeextension.tr.hdfilmcehennemi.extractors.CloseloadExtractor +import eu.kanade.tachiyomi.animeextension.tr.hdfilmcehennemi.extractors.RapidrameExtractor import eu.kanade.tachiyomi.animeextension.tr.hdfilmcehennemi.extractors.VidmolyExtractor import eu.kanade.tachiyomi.animeextension.tr.hdfilmcehennemi.extractors.XBetExtractor import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource @@ -19,13 +20,13 @@ import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.network.awaitSuccess import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking -import eu.kanade.tachiyomi.util.parallelMapBlocking import eu.kanade.tachiyomi.util.parseAs import kotlinx.serialization.Serializable import okhttp3.FormBody import okhttp3.MultipartBody import okhttp3.Request import okhttp3.Response +import org.jsoup.Jsoup import org.jsoup.nodes.Document import org.jsoup.nodes.Element import uy.kohesive.injekt.Injekt @@ -33,11 +34,10 @@ import uy.kohesive.injekt.api.get import java.text.SimpleDateFormat import java.util.Locale -class HDFilmCehennemi : ConfigurableAnimeSource, ParsedAnimeHttpSource() { - +class HDFilmCehennemi : ParsedAnimeHttpSource(), ConfigurableAnimeSource { override val name = "HDFilmCehennemi" - override val baseUrl = "https://www.hdfilmcehennemi.us" + override val baseUrl = "https://www.hdfilmcehennemi.nl" override val lang = "tr" @@ -47,25 +47,40 @@ class HDFilmCehennemi : ConfigurableAnimeSource, ParsedAnimeHttpSource() { .add("Referer", "$baseUrl/") .add("Origin", baseUrl) + private val apiHeaders = headersBuilder().add("X-Requested-With", "fetch").build() + private val preferences by lazy { Injekt.get().getSharedPreferences("source_$id", 0x0000) } // ============================== Popular =============================== - override fun popularAnimeRequest(page: Int) = GET("$baseUrl/en-cok-begenilen-filmleri-izle/page/$page/") + override fun popularAnimeRequest(page: Int) = + GET("$baseUrl/load/page/$page/mostLiked/", apiHeaders) + + override fun popularAnimeParse(response: Response): AnimesPage { + val data = response.parseAs() + val doc = Jsoup.parse(data.html) + val itens = doc.select(popularAnimeSelector()).map(::popularAnimeFromElement) + + return AnimesPage(itens, itens.size >= 28) + } - override fun popularAnimeSelector() = "div.row div.poster > a" + override fun popularAnimeSelector() = "a.poster" override fun popularAnimeFromElement(element: Element) = SAnime.create().apply { setUrlWithoutDomain(element.attr("href")) - title = element.selectFirst("h2.title")!!.text() - thumbnail_url = element.selectFirst("img")?.absUrl("data-src") + title = element.selectFirst("strong.poster-title, h4.title")!!.text() + thumbnail_url = element.selectFirst("img")?.run { + absUrl("data-src").ifBlank { absUrl("src") } + } } override fun popularAnimeNextPageSelector() = "ul.pagination > li > a[rel=next]" // =============================== Latest =============================== - override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/page/$page/") + override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/load/page/$page/home/", apiHeaders) + + override fun latestUpdatesParse(response: Response) = popularAnimeParse(response) override fun latestUpdatesSelector() = popularAnimeSelector() @@ -76,15 +91,17 @@ class HDFilmCehennemi : ConfigurableAnimeSource, ParsedAnimeHttpSource() { // =============================== Search =============================== override fun getFilterList() = HDFilmCehennemiFilters.FILTER_LIST - override suspend fun getSearchAnime(page: Int, query: String, filters: AnimeFilterList): AnimesPage { - return if (query.startsWith(PREFIX_SEARCH)) { // URL intent handler - val id = query.removePrefix(PREFIX_SEARCH) - client.newCall(GET("$baseUrl/$id")) - .awaitSuccess() - .use(::searchAnimeByIdParse) - } else { - super.getSearchAnime(page, query, filters) - } + override suspend fun getSearchAnime( + page: Int, + query: String, + filters: AnimeFilterList, + ): AnimesPage = if (query.startsWith(PREFIX_SEARCH)) { // URL intent handler + val id = query.removePrefix(PREFIX_SEARCH) + client.newCall(GET("$baseUrl/$id")) + .awaitSuccess() + .use(::searchAnimeByIdParse) + } else { + super.getSearchAnime(page, query, filters) } private fun searchAnimeByIdParse(response: Response): AnimesPage { @@ -96,17 +113,14 @@ class HDFilmCehennemi : ConfigurableAnimeSource, ParsedAnimeHttpSource() { return AnimesPage(listOf(details), false) } - override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request { - val headers = headersBuilder() - .add("X-Requested-With", "XMLHttpRequest") - .build() - - return when { + override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request = + when { query.isNotBlank() -> { val body = FormBody.Builder().add("query", query).build() - POST("$baseUrl/search/", headers, body) + POST("$baseUrl/search", apiHeaders, body) } + else -> { val params = HDFilmCehennemiFilters.getSearchParameters(filters) @@ -123,28 +137,26 @@ class HDFilmCehennemi : ConfigurableAnimeSource, ParsedAnimeHttpSource() { POST("$baseUrl/movies/load/", headers, form) } } - } @Serializable - data class SearchResponse(val result: List) + data class SearchResponse( + val results: List, + ) @Serializable - data class ItemDto(val title: String, val poster: String, val slug: String, val slug_prefix: String) - - @Serializable - data class FilterSearchResponse(val html: String, val showMore: Boolean, val status: Int) + data class FilterSearchResponse( + val html: String, + val showMore: Boolean, + val status: Int, + ) override fun searchAnimeParse(response: Response): AnimesPage { return when { - response.request.url.toString().contains("/search/") -> { // Text search + response.request.url.toString().contains("/search") -> { // Text search val data = response.parseAs() - val items = data.result.map { - SAnime.create().apply { - title = it.title - thumbnail_url = "$baseUrl/uploads/poster/" + it.poster - url = "/" + it.slug_prefix + it.slug - } - } + val items = data.results.mapNotNull { + Jsoup.parse(it).selectFirst("a[href]") + }.map(::popularAnimeFromElement) AnimesPage(items, false) } @@ -165,9 +177,7 @@ class HDFilmCehennemi : ConfigurableAnimeSource, ParsedAnimeHttpSource() { override fun searchAnimeFromElement(element: Element) = popularAnimeFromElement(element) - override fun searchAnimeNextPageSelector(): String? { - throw UnsupportedOperationException() - } + override fun searchAnimeNextPageSelector(): String? = throw UnsupportedOperationException() // =========================== Anime Details ============================ override fun animeDetailsParse(document: Document) = SAnime.create().apply { @@ -176,17 +186,23 @@ class HDFilmCehennemi : ConfigurableAnimeSource, ParsedAnimeHttpSource() { else -> SAnime.COMPLETED // movie } - val div = document.selectFirst("div.card-body > div.row")!! - - div.selectFirst("img")!!.run { - thumbnail_url = absUrl("src") - title = attr("alt") - } - - genre = div.select("div > a[href*=tur/]").eachText().joinToString().takeIf(String::isNotEmpty) - artist = div.select("a.chip[href*=oyuncu/]").eachText().joinToString().takeIf(String::isNotEmpty) - - description = div.selectFirst("article > p")?.text() + title = document.selectFirst(".section-title")!! + .ownText() + .substringBefore(" Filminin Bilgileri") + .substringBefore(" izle") + val div = document.selectFirst("div.section-content div.post-info")!! + thumbnail_url = div.selectFirst("img")!!.absUrl("data-src") + + genre = div.select("div.post-info-genres > a") + .eachText() + .joinToString() + .takeIf(String::isNotEmpty) + artist = div.select("div.post-info-cast > a") + .eachText() + .joinToString() + .takeIf(String::isNotEmpty) + + description = div.selectFirst("div.post-info-content > p")?.text() } // ============================== Episodes ============================== @@ -207,14 +223,14 @@ class HDFilmCehennemi : ConfigurableAnimeSource, ParsedAnimeHttpSource() { override fun episodeListParse(response: Response) = super.episodeListParse(response).sortedByDescending { it.episode_number } - override fun episodeListSelector() = "div#seasonsTabs-tabContent div.card-list-item > a" + override fun episodeListSelector() = "div.seasons-tabs-wrapper > div.seasons-tab-content > a" private val numberRegex by lazy { Regex("(\\d+)\\.") } override fun episodeFromElement(element: Element) = SEpisode.create().apply { setUrlWithoutDomain(element.attr("href")) - name = element.selectFirst("h3")!!.text() + name = element.selectFirst("h3, h4")!!.text() date_upload = element.selectFirst("date")?.attr("datetime")?.toDate() ?: 0L @@ -226,39 +242,47 @@ class HDFilmCehennemi : ConfigurableAnimeSource, ParsedAnimeHttpSource() { // ============================ Video Links ============================= private val vidmolyExtractor by lazy { VidmolyExtractor(client, headers) } private val closeloadExtractor by lazy { CloseloadExtractor(client, headers) } + private val rapidrameExtractor by lazy { RapidrameExtractor(client, headers) } private val xbetExtractor by lazy { XBetExtractor(client, headers) } override fun videoListParse(response: Response): List