diff --git a/src/de/aniking/build.gradle b/src/de/aniking/build.gradle index 19c20ef90..debde2ed1 100644 --- a/src/de/aniking/build.gradle +++ b/src/de/aniking/build.gradle @@ -6,7 +6,7 @@ ext { extName = 'Aniking' pkgNameSuffix = 'de.aniking' extClass = '.Aniking' - extVersionCode = 1 + extVersionCode = 2 libVersion = '13' } diff --git a/src/de/aniking/src/eu/kanade/tachiyomi/animeextension/de/aniking/Aniking.kt b/src/de/aniking/src/eu/kanade/tachiyomi/animeextension/de/aniking/Aniking.kt index 3ef5ab880..d329dd28b 100644 --- a/src/de/aniking/src/eu/kanade/tachiyomi/animeextension/de/aniking/Aniking.kt +++ b/src/de/aniking/src/eu/kanade/tachiyomi/animeextension/de/aniking/Aniking.kt @@ -65,7 +65,16 @@ class Aniking : ConfigurableAnimeSource, ParsedAnimeHttpSource() { // episodes override fun episodeListRequest(anime: SAnime): Request { - return GET("$baseUrl${anime.url}", headers = Headers.headersOf("if-modified-since", "")) + val interceptor = client.newBuilder().addInterceptor(CloudflareInterceptor()).build() + val headers = interceptor.newCall( + GET( + "$baseUrl${anime.url}", + headers = + Headers.headersOf("user-agent", "Mozilla/5.0 (Linux; Android 12; SM-T870 Build/SP2A.220305.013; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/106.0.5249.126 Safari/537.36") + ) + ) + .execute().request.headers + return GET("$baseUrl${anime.url}", headers = headers) } override fun episodeListSelector() = throw Exception("not used") @@ -268,6 +277,19 @@ class Aniking : ConfigurableAnimeSource, ParsedAnimeHttpSource() { // Details + override fun animeDetailsRequest(anime: SAnime): Request { + val interceptor = client.newBuilder().addInterceptor(CloudflareInterceptor()).build() + val headers = interceptor.newCall( + GET( + "$baseUrl${anime.url}", + headers = + Headers.headersOf("user-agent", "Mozilla/5.0 (Linux; Android 12; SM-T870 Build/SP2A.220305.013; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/106.0.5249.126 Safari/537.36") + ) + ) + .execute().request.headers + return GET("$baseUrl${anime.url}", headers = headers) + } + override fun animeDetailsParse(document: Document): SAnime { val anime = SAnime.create() anime.thumbnail_url = document.select("div.tv-poster img").attr("src") diff --git a/src/de/aniking/src/eu/kanade/tachiyomi/animeextension/de/aniking/CloudflareInterceptor.kt b/src/de/aniking/src/eu/kanade/tachiyomi/animeextension/de/aniking/CloudflareInterceptor.kt index 725c80176..b1651b4a3 100644 --- a/src/de/aniking/src/eu/kanade/tachiyomi/animeextension/de/aniking/CloudflareInterceptor.kt +++ b/src/de/aniking/src/eu/kanade/tachiyomi/animeextension/de/aniking/CloudflareInterceptor.kt @@ -53,8 +53,7 @@ class CloudflareInterceptor() : Interceptor { databaseEnabled = true useWideViewPort = false loadWithOverviewMode = false - userAgentString = request.header("User-Agent") - ?: "\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36 Edg/88.0.705.63\"" + userAgentString = "Mozilla/5.0 (Linux; Android 12; SM-T870 Build/SP2A.220305.013; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/106.0.5249.126 Safari/537.36" } webview.webViewClient = object : WebViewClient() { @@ -62,7 +61,7 @@ class CloudflareInterceptor() : Interceptor { view: WebView, request: WebResourceRequest, ): WebResourceResponse? { - if (request.url.toString().contains("https://aniking.cc")) { + if (request.url.toString().contains("wp-content/themes/moviewp")) { newRequest = GET(request.url.toString(), request.requestHeaders.toHeaders()) latch.countDown() } diff --git a/src/de/animeshitai/res/mipmap-hdpi/ic_launcher.png b/src/de/animeshitai/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 0d2b2076d..000000000 Binary files a/src/de/animeshitai/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src/de/animeshitai/res/mipmap-mdpi/ic_launcher.png b/src/de/animeshitai/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 0d2b2076d..000000000 Binary files a/src/de/animeshitai/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src/de/animeshitai/res/mipmap-xhdpi/ic_launcher.png b/src/de/animeshitai/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 0d2b2076d..000000000 Binary files a/src/de/animeshitai/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src/de/animeshitai/res/mipmap-xxhdpi/ic_launcher.png b/src/de/animeshitai/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 0d2b2076d..000000000 Binary files a/src/de/animeshitai/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/de/animeshitai/res/mipmap-xxxhdpi/ic_launcher.png b/src/de/animeshitai/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 0d2b2076d..000000000 Binary files a/src/de/animeshitai/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/de/animeshitai/src/eu/kanade/tachiyomi/animeextension/de/animeshitai/ASConstants.kt b/src/de/animeshitai/src/eu/kanade/tachiyomi/animeextension/de/animeshitai/ASConstants.kt deleted file mode 100644 index bbf81f881..000000000 --- a/src/de/animeshitai/src/eu/kanade/tachiyomi/animeextension/de/animeshitai/ASConstants.kt +++ /dev/null @@ -1,21 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.de.animeshitai - -object ASConstants { - const val NAME_DOOD = "Doodstream" - const val NAME_STAPE = "Streamtape" - - const val URL_DOOD = "https://dood" - const val URL_STAPE = "https://streamtape.com" - - val HOSTER_NAMES = arrayOf(NAME_DOOD, NAME_STAPE) - val HOSTER_URLS = arrayOf(URL_DOOD, URL_STAPE) - - const val LANG_SUB = "Sub" - const val LANG_DUB = "Dub" - - val LANGS = arrayOf(LANG_SUB, LANG_DUB) - - const val PREFERRED_HOSTER = "preferred_hoster" - const val PREFERRED_LANG = "preferred_sub" - const val HOSTER_SELECTION = "hoster_selection" -} diff --git a/src/de/animeshitai/src/eu/kanade/tachiyomi/animeextension/de/animeshitai/ASFilters.kt b/src/de/animeshitai/src/eu/kanade/tachiyomi/animeextension/de/animeshitai/ASFilters.kt deleted file mode 100644 index dd3329d32..000000000 --- a/src/de/animeshitai/src/eu/kanade/tachiyomi/animeextension/de/animeshitai/ASFilters.kt +++ /dev/null @@ -1,204 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.de.animeshitai - -import eu.kanade.tachiyomi.animeextension.de.animeshitai.model.ASAnime -import eu.kanade.tachiyomi.animesource.model.AnimeFilter -import eu.kanade.tachiyomi.animesource.model.AnimeFilterList -import java.util.Calendar - -object ASFilters { - open class CheckBoxFilterList(name: String, values: List) : AnimeFilter.Group(name, values) - private class CheckBoxVal(name: String, state: Boolean = false) : AnimeFilter.CheckBox(name, state) - - open class TriStateFilterList(name: String, values: List) : AnimeFilter.Group(name, values) - private class TriStateVal(name: String) : AnimeFilter.TriState(name) - - class SortFilter : AnimeFilter.Sort( - "Sortieren", - ASFilterData.sortables.map { it.first }.toTypedArray(), - Selection(0, true) - ) - - class FormatFilter : CheckBoxFilterList( - "Format", - ASFilterData.formats.map { CheckBoxVal(it.first, true) } - ) - - class LanguageFilter : CheckBoxFilterList( - "Sprache", - ASFilterData.languages.map { CheckBoxVal(it.first, true) } - ) - - class GenreFilter : TriStateFilterList( - "Genres", - ASFilterData.genres.map { TriStateVal(it) } - ) - - class YearsFilter : CheckBoxFilterList( - "Jahre", - ASFilterData.years.map { CheckBoxVal(it.toString()) } - ) - - class ABCFilter : CheckBoxFilterList( - "ABC", - ASFilterData.abc.map { CheckBoxVal(it.toString()) } - ) - - val filterList = AnimeFilterList( - SortFilter(), - FormatFilter(), - LanguageFilter(), - GenreFilter(), - YearsFilter(), - ABCFilter(), - ) - - data class FilterSearchParams( - var orderBy: String = "az", - var orderAscending: Boolean = true, - val includedFormats: ArrayList = ArrayList(), - val includedLangs: ArrayList = ArrayList(), - val includedGenres: ArrayList = ArrayList(), - val blackListedGenres: ArrayList = ArrayList(), - val includedYears: ArrayList = ArrayList(), - val includedLetters: ArrayList = ArrayList(), - ) - - internal fun getSearchParameters(filters: AnimeFilterList): FilterSearchParams { - val params = FilterSearchParams() - filters.forEach { filter -> - when (filter) { - is SortFilter -> { - if (filter.state != null) { - val query = ASFilterData.sortables[filter.state!!.index].second - params.orderAscending = filter.state!!.ascending - params.orderBy = query - } - } - is FormatFilter -> { - filter.state.forEach { format -> - if (format.state) { - val query = ASFilterData.formats.find { it.first == format.name }!!.second - params.includedFormats.add(query) - } - } - } - is LanguageFilter -> { - filter.state.forEach { lang -> - if (lang.state) { - val query = ASFilterData.languages.find { it.first == lang.name }!!.second - params.includedLangs.add(query) - } - } - } - is GenreFilter -> { - filter.state.forEach { genre -> - if (genre.isIncluded()) { - params.includedGenres.add(genre.name) - } else if (genre.isExcluded()) { - params.blackListedGenres.add(genre.name) - } - } - } - is YearsFilter -> { - filter.state.forEach { year -> - if (year.state) - params.includedYears.add(year.name) - } - } - is ABCFilter -> { - filter.state.forEach { letter -> - if (letter.state) - params.includedLetters.add(letter.name) - } - } - else -> {} - } - } - return params - } - - fun MutableList.applyFilterParams(params: FilterSearchParams) { - // Remove all entries with blacklisted genres - this.removeAll { anime -> params.blackListedGenres.any { it in anime.genre ?: "" } } - - // Sort animes - when (params.orderBy) { - // Sort animes alphabetically - "az" -> { - if (!params.orderAscending) - this.reverse() - } - // Sort animes by year - "year" -> { - if (params.orderAscending) - this.sortBy { it.year } - else - this.sortByDescending { it.year } - } - } - } -} - -private object ASFilterData { - // (1990..(Year.now().value)).reversed() - val years = (1990..(Calendar.getInstance().get(Calendar.YEAR))).reversed() - - val abc = 'A'..'Z' - - val sortables = arrayOf( - Pair("Alphabetisch", "az"), - Pair("Jahr", "year"), - ) - - val formats = arrayOf( - Pair("\uD83D\uDCFA Serien", "Serien"), - Pair("\uD83C\uDF10 OVAs", "OVAs"), - Pair("\uD83C\uDFAC Filme", "Filme") - ) - - val languages = arrayOf( - Pair("\uD83C\uDDE9\uD83C\uDDEA Ger Dub", "Ger Dub"), - Pair("\uD83C\uDDEF\uD83C\uDDF5 Ger Sub", "Ger Sub"), - Pair("\uD83C\uDDEC\uD83C\uDDE7 Eng Dub & Ger Sub", "Eng Dub") - ) - - val genres = listOf( - "Abenteuer", - "Action", - "Alltagsleben", - "Alternative Welt", - "Drama", - "Ecchi", - "Erotik", - "Fantasy", - "Fighting-Shounen", - "Ganbatte", - "Geistergeschichten", - "Harem", - "Historisch", - "Horror", - "Komödie", - "Krimi", - "Liebesdrama", - "Magical Girl", - "Magie", - "Mecha", - "Mystery", - "Nonsense-Komödie", - "Psychodrama", - "Romantische Komödie", - "Romanze", - "Schule", - "Sci-Fi", - "Sentimentales Drama", - "Shoujou", - "Shounen", - "Sport", - "Superpower", - "Thriller", - "Übermäßige Gewaltdarstellung", - "Unbestimmt", - "Yaoi", - "Yuri" - ) -} diff --git a/src/de/animeshitai/src/eu/kanade/tachiyomi/animeextension/de/animeshitai/AnimeShitai.kt b/src/de/animeshitai/src/eu/kanade/tachiyomi/animeextension/de/animeshitai/AnimeShitai.kt deleted file mode 100644 index fdf9bf1c2..000000000 --- a/src/de/animeshitai/src/eu/kanade/tachiyomi/animeextension/de/animeshitai/AnimeShitai.kt +++ /dev/null @@ -1,356 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.de.animeshitai - -import android.app.Application -import android.content.SharedPreferences -import android.util.Base64 -import androidx.preference.ListPreference -import androidx.preference.MultiSelectListPreference -import androidx.preference.PreferenceScreen -import eu.kanade.tachiyomi.animeextension.de.animeshitai.ASFilters.applyFilterParams -import eu.kanade.tachiyomi.animeextension.de.animeshitai.model.ASAnime -import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource -import eu.kanade.tachiyomi.animesource.model.AnimeFilterList -import eu.kanade.tachiyomi.animesource.model.AnimesPage -import eu.kanade.tachiyomi.animesource.model.SAnime -import eu.kanade.tachiyomi.animesource.model.SEpisode -import eu.kanade.tachiyomi.animesource.model.Video -import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource -import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor -import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.network.POST -import eu.kanade.tachiyomi.network.asObservableSuccess -import eu.kanade.tachiyomi.util.asJsoup -import okhttp3.FormBody -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.Response -import org.jsoup.Jsoup -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import rx.Observable -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get -import kotlin.collections.ArrayList - -class AnimeShitai : ConfigurableAnimeSource, ParsedAnimeHttpSource() { - - override val name = "Anime Shitai" - - override val baseUrl = "https://anime-shitai.com" - - override val lang = "de" - - override val supportsLatest = true - - override val client: OkHttpClient = network.cloudflareClient - - private val preferences: SharedPreferences by lazy { - Injekt.get().getSharedPreferences("source_$id", 0x0000) - } - - // ===== POPULAR ANIME ===== - override fun popularAnimeSelector(): String = ".newanimes .newbox" - - override fun popularAnimeNextPageSelector(): String? = null - - override fun popularAnimeRequest(page: Int): Request = GET(baseUrl) - - override fun popularAnimeFromElement(element: Element): SAnime { - val anime = SAnime.create() - val linkElement = element.selectFirst("a") - anime.url = linkElement.attr("href") - anime.thumbnail_url = linkElement.selectFirst("img").attr("src") - anime.title = element.selectFirst(".ntitel").text() - return anime - } - - // ===== LATEST ANIME ===== - override fun latestUpdatesSelector(): String = "a" - - override fun latestUpdatesNextPageSelector(): String? = null - - override fun latestUpdatesRequest(page: Int): Request = POST("$baseUrl/ichigo/indexep.php?option=1") - - override fun latestUpdatesParse(response: Response): AnimesPage { - val document = Jsoup.parseBodyFragment(response.body?.string()) - val animeList = mutableSetOf() - val animes = document.select(latestUpdatesSelector()).mapNotNull { element -> - val animeName = element.selectFirst("span.t").text().substringBefore("...") - // Check if any anime is multiple times in the list - if (!animeList.contains(animeName)) { - animeList.add(animeName) - latestUpdatesFromElement(element) - } else - null - } - - return AnimesPage(animes, false) - } - - override fun latestUpdatesFromElement(element: Element): SAnime { - val anime = SAnime.create() - val animeId = element.attr("href").substringAfter("/anschauen/").substringBefore('/') - anime.url = "/anime/$animeId/" - anime.thumbnail_url = element.selectFirst("div.c").attr("style").substringAfter("background:url('").substringBefore("');") - anime.title = anime.thumbnail_url!!.substringAfter("/cover/").substringBefore(".jpg").replace("__", ": ").replace('_', ' ') - return anime - } - - // ===== ANIME SEARCH ===== - override fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable { - val params = ASFilters.getSearchParameters(filters) - return client.newCall(searchAnimeRequest(page, query, params)) - .asObservableSuccess() - .map { response -> - searchAnimeParse(response, params) - } - } - - override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request = throw UnsupportedOperationException("Not used.") - - private fun searchAnimeRequest(page: Int, query: String, params: ASFilters.FilterSearchParams): Request { - fun listToFormStr(list: ArrayList): String { - if (list.size > 0) - return list.joinToString(" - ", " - ") - return "" - } - val body = FormBody.Builder() - .add("p", page.toString()) - .add("get_val", query) - .add("genre", listToFormStr(params.includedGenres)) - .add("jahr", listToFormStr(params.includedYears)) - .add("format", listToFormStr(params.includedFormats)) - .add("omu", listToFormStr(params.includedLangs)) - .add("abc", listToFormStr(params.includedLetters)) - .build() - - return POST("$baseUrl/ichigo/get_anilist.php", headers, body) - } - - override fun searchAnimeSelector(): String = ".listinganime" - - override fun searchAnimeNextPageSelector(): String? = ".nav" - - override fun searchAnimeParse(response: Response): AnimesPage = throw UnsupportedOperationException("Not used.") - - private fun searchAnimeParse(response: Response, params: ASFilters.FilterSearchParams): AnimesPage { - val document = Jsoup.parseBodyFragment(response.body?.string()) - - val animeTrackList = mutableSetOf() - val animes = document.select(searchAnimeSelector()).mapNotNull { element -> - val anime = searchAnimeFromElement(element) - // Shows with sub and dub have two separate entries, exclude the second entry - if (!animeTrackList.contains(anime.thumbnail_url)) { - animeTrackList.add(anime.thumbnail_url!!) - anime - } else - null - }.toMutableList() - - // Apply client-side filters - animes.applyFilterParams(params) - - val hasNextPage = searchAnimeNextPageSelector()?.let { selector -> - document.select(selector).first() - } != null - - return AnimesPage(animes, hasNextPage) - } - - override fun searchAnimeFromElement(element: Element): ASAnime { - val anime = ASAnime.create() - anime.url = element.selectFirst("a").attr("href") - anime.thumbnail_url = element.selectFirst(".listinganicover").attr("style").substringAfter("url('").substringBefore("')") - anime.title = element.selectFirst(".listingtitle").text().replaceAfterLast(' ', "").trimStart() - // Get genres for client-side genre filtering - anime.genre = element.select(".listingdesc .alternativ").mapNotNull { - if (it.text().startsWith("Hauptgenre") || it.text().startsWith("Genres")) - it.text().substringAfter(':') - else - null - }.joinToString(", ") - - anime.year = element.selectFirst(".listingtitle").text().substringAfterLast('(').substringBefore(')').toInt() - return anime - } - - override fun getFilterList(): AnimeFilterList = ASFilters.filterList - - // ===== ANIME DETAILS ===== - override fun animeDetailsParse(document: Document): SAnime { - val anime = SAnime.create() - val content = document.selectFirst("#ani .body") - anime.title = content.selectFirst("animename").ownText().trim() - anime.thumbnail_url = document.selectFirst("#ani .pic").attr("data-src") - anime.genre = content.select("div:eq(1) .hg, a").joinToString(", ") { it.text() } - anime.description = content.selectFirst(".br").ownText() - anime.status = SAnime.UNKNOWN - return anime - } - - // ===== EPISODE ===== - override fun episodeListSelector(): String = ".ep_table tbody tr" - - override fun episodeListParse(response: Response): List { - val document = response.asJsoup() - return document.select(episodeListSelector()).reversed().map { episodeFromElement(it) } - } - - override fun episodeFromElement(element: Element): SEpisode { - val episode = SEpisode.create() - episode.setUrlWithoutDomain(baseUrl + element.attr("onclick").substringAfter("window.location.href='").substringBefore('#')) - val ep = element.child(0).text() - episode.episode_number = ep.toFloat() - episode.name = "Episode $ep" - return episode - } - - // ===== VIDEO SOURCES ===== - override fun videoListSelector(): String = "center a" - - override fun videoListParse(response: Response): List