diff --git a/.github/workflows/build_push.yml b/.github/workflows/build_push.yml index 346eb44e..43101393 100644 --- a/.github/workflows/build_push.yml +++ b/.github/workflows/build_push.yml @@ -31,14 +31,15 @@ jobs: ref: main token: ${{ secrets.BOT_PAT }} - - name: Find lib changes - id: modified-libs - uses: tj-actions/changed-files@90a06d6ba9543371ab4df8eeca0be07ca6054959 #v42 - with: - files: lib/ - files_ignore: lib/**.md - files_separator: " " - safe_output: false + # Temporary pause because of leak of tj-actions/changed-files + # - name: Find lib changes + # id: modified-libs + # uses: tj-actions/changed-files@90a06d6ba9543371ab4df8eeca0be07ca6054959 #v42 + # with: + # files: lib/ + # files_ignore: lib/**.md + # files_separator: " " + # safe_output: false - name: Import GPG key uses: crazy-max/ghaction-import-gpg@v6 # v6.1.0 @@ -48,12 +49,12 @@ jobs: git_user_signingkey: true git_commit_gpgsign: true - # This step is going to commit, but this will not trigger another workflow. - - name: Bump extensions that uses a modified lib - if: steps.modified-libs.outputs.any_changed == 'true' - run: | - chmod +x ./.github/scripts/bump-versions.py - ./.github/scripts/bump-versions.py ${{ steps.modified-libs.outputs.all_changed_files }} + # # This step is going to commit, but this will not trigger another workflow. + # - name: Bump extensions that uses a modified lib + # if: steps.modified-libs.outputs.any_changed == 'true' + # run: | + # chmod +x ./.github/scripts/bump-versions.py + # ./.github/scripts/bump-versions.py ${{ steps.modified-libs.outputs.all_changed_files }} - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@a494d935f4b56874c4a5a87d19af7afcf3a163d0 # v2 diff --git a/lib/amazon-extractor/build.gradle.kts b/lib/amazon-extractor/build.gradle.kts new file mode 100644 index 00000000..a503203d --- /dev/null +++ b/lib/amazon-extractor/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + id("lib-android") +} + +dependencies { + implementation(project(":lib:playlist-utils")) +} \ No newline at end of file diff --git a/lib/amazon-extractor/src/main/java/eu/kanade/tachiyomi/lib/amazonextractor/AmazonExtractor.kt b/lib/amazon-extractor/src/main/java/eu/kanade/tachiyomi/lib/amazonextractor/AmazonExtractor.kt new file mode 100644 index 00000000..3402cb9e --- /dev/null +++ b/lib/amazon-extractor/src/main/java/eu/kanade/tachiyomi/lib/amazonextractor/AmazonExtractor.kt @@ -0,0 +1,41 @@ +package eu.kanade.tachiyomi.lib.amazonextractor + +import eu.kanade.tachiyomi.animesource.model.Video +import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.util.asJsoup +import okhttp3.OkHttpClient + +class AmazonExtractor(private val client: OkHttpClient) { + + private val playlistUtils by lazy { PlaylistUtils(client) } + + fun videosFromUrl(url: String, prefix: String = ""): List<Video> { + if (url.contains("disable", true)) return emptyList() + + val document = client.newCall(GET(url)).execute().asJsoup() + + val shareIdScript = document.select("script:containsData(var shareId)").firstOrNull()?.data() + if (shareIdScript.isNullOrBlank()) return emptyList() + + val shareId = shareIdScript.substringAfter("shareId = \"").substringBefore("\"") + val amazonApiJsonUrl = "https://www.amazon.com/drive/v1/shares/$shareId?resourceVersion=V2&ContentType=JSON&asset=ALL" + + val amazonApiJson = client.newCall(GET(amazonApiJsonUrl)).execute().asJsoup() + + val epId = amazonApiJson.toString().substringAfter("\"id\":\"").substringBefore("\"") + val amazonApiUrl = "https://www.amazon.com/drive/v1/nodes/$epId/children?resourceVersion=V2&ContentType=JSON&limit=200&sort=%5B%22kind+DESC%22%2C+%22modifiedDate+DESC%22%5D&asset=ALL&tempLink=true&shareId=$shareId" + + val amazonApi = client.newCall(GET(amazonApiUrl)).execute().asJsoup() + + val videoUrl = amazonApi.toString().substringAfter("\"FOLDER\":").substringAfter("tempLink\":\"").substringBefore("\"") + + val serverName = if (videoUrl.contains("&ext=es")) "AmazonES" else "Amazon" + + return if (videoUrl.contains(".m3u8")) { + playlistUtils.extractFromHls(videoUrl, videoNameGen = { "${prefix}$serverName:$it" }) + } else { + listOf(Video(videoUrl, "${prefix}$serverName", videoUrl)) + } + } +} diff --git a/src/all/animeonsen/res/web_hi_res_512.png b/src/all/animeonsen/res/web_hi_res_512.png deleted file mode 100644 index 2ca8cc98..00000000 Binary files a/src/all/animeonsen/res/web_hi_res_512.png and /dev/null differ diff --git a/src/all/animeworldindia/build.gradle b/src/all/animeworldindia/build.gradle index 2e6be89d..0c887191 100644 --- a/src/all/animeworldindia/build.gradle +++ b/src/all/animeworldindia/build.gradle @@ -1,11 +1,11 @@ ext { extName = 'AnimeWorld India' extClass = '.AnimeWorldIndiaFactory' - extVersionCode = 14 + extVersionCode = 15 } apply from: "$rootDir/common.gradle" dependencies { implementation(project(":lib:playlist-utils")) -} \ No newline at end of file +} diff --git a/src/all/animeworldindia/src/eu/kanade/tachiyomi/animeextension/all/animeworldindia/AnimeWorldIndia.kt b/src/all/animeworldindia/src/eu/kanade/tachiyomi/animeextension/all/animeworldindia/AnimeWorldIndia.kt index 4ab6cd81..5fbe3c37 100644 --- a/src/all/animeworldindia/src/eu/kanade/tachiyomi/animeextension/all/animeworldindia/AnimeWorldIndia.kt +++ b/src/all/animeworldindia/src/eu/kanade/tachiyomi/animeextension/all/animeworldindia/AnimeWorldIndia.kt @@ -29,7 +29,7 @@ class AnimeWorldIndia( override val name = "AnimeWorld India" - override val baseUrl = "https://anime-world.in" + override val baseUrl = "https://anime-world.co" override val supportsLatest = true diff --git a/src/all/animeworldindia/src/eu/kanade/tachiyomi/animeextension/all/animeworldindia/AnimeWorldIndiaFilters.kt b/src/all/animeworldindia/src/eu/kanade/tachiyomi/animeextension/all/animeworldindia/AnimeWorldIndiaFilters.kt index 5baf4062..a55518bd 100644 --- a/src/all/animeworldindia/src/eu/kanade/tachiyomi/animeextension/all/animeworldindia/AnimeWorldIndiaFilters.kt +++ b/src/all/animeworldindia/src/eu/kanade/tachiyomi/animeextension/all/animeworldindia/AnimeWorldIndiaFilters.kt @@ -47,6 +47,7 @@ class AnimeWorldIndiaFilters { private fun getYearList() = listOf( StringQuery("Any", "all"), + StringQuery("2025", "2025"), StringQuery("2024", "2024"), StringQuery("2023", "2023"), StringQuery("2022", "2022"), diff --git a/src/all/chineseanime/res/web_hi_res_512.png b/src/all/chineseanime/res/web_hi_res_512.png deleted file mode 100644 index d8572ff1..00000000 Binary files a/src/all/chineseanime/res/web_hi_res_512.png and /dev/null differ diff --git a/src/all/javguru/res/web_hi_res_512.png b/src/all/javguru/res/web_hi_res_512.png deleted file mode 100644 index 1e1e735b..00000000 Binary files a/src/all/javguru/res/web_hi_res_512.png and /dev/null differ diff --git a/src/all/missav/res/web_hi_res_512.png b/src/all/missav/res/web_hi_res_512.png deleted file mode 100644 index 2b9568fd..00000000 Binary files a/src/all/missav/res/web_hi_res_512.png and /dev/null differ diff --git a/src/ar/akwam/res/play_store_512.png b/src/ar/akwam/res/play_store_512.png deleted file mode 100644 index 17a4ebb9..00000000 Binary files a/src/ar/akwam/res/play_store_512.png and /dev/null differ diff --git a/src/ar/anime4up/res/play_store_512.png b/src/ar/anime4up/res/play_store_512.png deleted file mode 100644 index 9bfe8e48..00000000 Binary files a/src/ar/anime4up/res/play_store_512.png and /dev/null differ diff --git a/src/ar/animeblkom/res/web_hi_res_512.png b/src/ar/animeblkom/res/web_hi_res_512.png deleted file mode 100644 index b47c05e9..00000000 Binary files a/src/ar/animeblkom/res/web_hi_res_512.png and /dev/null differ diff --git a/src/ar/animeiat/res/web_hi_res_512.png b/src/ar/animeiat/res/web_hi_res_512.png deleted file mode 100644 index 06a6eece..00000000 Binary files a/src/ar/animeiat/res/web_hi_res_512.png and /dev/null differ diff --git a/src/ar/animelek/res/play_store_512.png b/src/ar/animelek/res/play_store_512.png deleted file mode 100644 index 13283b86..00000000 Binary files a/src/ar/animelek/res/play_store_512.png and /dev/null differ diff --git a/src/ar/animerco/res/play_store_512.png b/src/ar/animerco/res/play_store_512.png deleted file mode 100644 index fbf8380e..00000000 Binary files a/src/ar/animerco/res/play_store_512.png and /dev/null differ diff --git a/src/ar/arabanime/res/web_hi_res_512.png b/src/ar/arabanime/res/web_hi_res_512.png deleted file mode 100644 index 684ce74b..00000000 Binary files a/src/ar/arabanime/res/web_hi_res_512.png and /dev/null differ diff --git a/src/ar/arabseed/res/web_hi_res_512.png b/src/ar/arabseed/res/web_hi_res_512.png deleted file mode 100644 index 42b8ffbf..00000000 Binary files a/src/ar/arabseed/res/web_hi_res_512.png and /dev/null differ diff --git a/src/ar/asia2tv/res/play_store_512.png b/src/ar/asia2tv/res/play_store_512.png deleted file mode 100644 index 644679a6..00000000 Binary files a/src/ar/asia2tv/res/play_store_512.png and /dev/null differ diff --git a/src/ar/egydead/res/web_hi_res_512.png b/src/ar/egydead/res/web_hi_res_512.png deleted file mode 100644 index bcff8301..00000000 Binary files a/src/ar/egydead/res/web_hi_res_512.png and /dev/null differ diff --git a/src/ar/faselhd/res/web_hi_res_512.png b/src/ar/faselhd/res/web_hi_res_512.png deleted file mode 100644 index bbe17f6d..00000000 Binary files a/src/ar/faselhd/res/web_hi_res_512.png and /dev/null differ diff --git a/src/ar/mycima/res/web_hi_res_512.png b/src/ar/mycima/res/web_hi_res_512.png deleted file mode 100644 index b3d75682..00000000 Binary files a/src/ar/mycima/res/web_hi_res_512.png and /dev/null differ diff --git a/src/ar/tuktukcinema/res/web_hi_res_512.png b/src/ar/tuktukcinema/res/web_hi_res_512.png deleted file mode 100644 index 55c57feb..00000000 Binary files a/src/ar/tuktukcinema/res/web_hi_res_512.png and /dev/null differ diff --git a/src/ar/witanime/res/web_hi_res_512.png b/src/ar/witanime/res/web_hi_res_512.png deleted file mode 100644 index e9de882c..00000000 Binary files a/src/ar/witanime/res/web_hi_res_512.png and /dev/null differ diff --git a/src/ar/xsanime/res/web_hi_res_512.png b/src/ar/xsanime/res/web_hi_res_512.png deleted file mode 100644 index b7ecb5f2..00000000 Binary files a/src/ar/xsanime/res/web_hi_res_512.png and /dev/null differ diff --git a/src/ar/xsmovie/res/web_hi_res_512.png b/src/ar/xsmovie/res/web_hi_res_512.png deleted file mode 100644 index 4ac97393..00000000 Binary files a/src/ar/xsmovie/res/web_hi_res_512.png and /dev/null differ diff --git a/src/de/animeloads/res/mipmap-hdpi/ic_launcher_adaptive_back.png b/src/de/animeloads/res/mipmap-hdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 8dc560dd..00000000 Binary files a/src/de/animeloads/res/mipmap-hdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/animeloads/res/mipmap-hdpi/ic_launcher_adaptive_fore.png b/src/de/animeloads/res/mipmap-hdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 03d51624..00000000 Binary files a/src/de/animeloads/res/mipmap-hdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/animeloads/res/mipmap-mdpi/ic_launcher_adaptive_back.png b/src/de/animeloads/res/mipmap-mdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index f8feb6e5..00000000 Binary files a/src/de/animeloads/res/mipmap-mdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/animeloads/res/mipmap-mdpi/ic_launcher_adaptive_fore.png b/src/de/animeloads/res/mipmap-mdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 3eaed0fb..00000000 Binary files a/src/de/animeloads/res/mipmap-mdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/animeloads/res/mipmap-xhdpi/ic_launcher_adaptive_back.png b/src/de/animeloads/res/mipmap-xhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 1b560124..00000000 Binary files a/src/de/animeloads/res/mipmap-xhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/animeloads/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png b/src/de/animeloads/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index da274ed6..00000000 Binary files a/src/de/animeloads/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/animeloads/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png b/src/de/animeloads/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 369383ac..00000000 Binary files a/src/de/animeloads/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/animeloads/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png b/src/de/animeloads/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index ec6a2ff3..00000000 Binary files a/src/de/animeloads/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/animeloads/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png b/src/de/animeloads/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index de26e98f..00000000 Binary files a/src/de/animeloads/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/animeloads/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png b/src/de/animeloads/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 050b46e2..00000000 Binary files a/src/de/animeloads/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/aniworld/res/mipmap-hdpi/ic_launcher_adaptive_back.png b/src/de/aniworld/res/mipmap-hdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 8dc560dd..00000000 Binary files a/src/de/aniworld/res/mipmap-hdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/aniworld/res/mipmap-hdpi/ic_launcher_adaptive_fore.png b/src/de/aniworld/res/mipmap-hdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 9ec03535..00000000 Binary files a/src/de/aniworld/res/mipmap-hdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/aniworld/res/mipmap-mdpi/ic_launcher_adaptive_back.png b/src/de/aniworld/res/mipmap-mdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index f8feb6e5..00000000 Binary files a/src/de/aniworld/res/mipmap-mdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/aniworld/res/mipmap-mdpi/ic_launcher_adaptive_fore.png b/src/de/aniworld/res/mipmap-mdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 86df8abd..00000000 Binary files a/src/de/aniworld/res/mipmap-mdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/aniworld/res/mipmap-xhdpi/ic_launcher_adaptive_back.png b/src/de/aniworld/res/mipmap-xhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 1b560124..00000000 Binary files a/src/de/aniworld/res/mipmap-xhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/aniworld/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png b/src/de/aniworld/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 3cb79f27..00000000 Binary files a/src/de/aniworld/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/aniworld/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png b/src/de/aniworld/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 369383ac..00000000 Binary files a/src/de/aniworld/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/aniworld/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png b/src/de/aniworld/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 366f1f42..00000000 Binary files a/src/de/aniworld/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/aniworld/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png b/src/de/aniworld/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index de26e98f..00000000 Binary files a/src/de/aniworld/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/aniworld/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png b/src/de/aniworld/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index aaad5a4c..00000000 Binary files a/src/de/aniworld/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/cineclix/res/mipmap-hdpi/ic_launcher_background.png b/src/de/cineclix/res/mipmap-hdpi/ic_launcher_background.png deleted file mode 100644 index 2d07511b..00000000 Binary files a/src/de/cineclix/res/mipmap-hdpi/ic_launcher_background.png and /dev/null differ diff --git a/src/de/cineclix/res/mipmap-hdpi/ic_launcher_foreground.png b/src/de/cineclix/res/mipmap-hdpi/ic_launcher_foreground.png deleted file mode 100644 index bde37154..00000000 Binary files a/src/de/cineclix/res/mipmap-hdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src/de/cineclix/res/mipmap-hdpi/ic_launcher_monochrome.png b/src/de/cineclix/res/mipmap-hdpi/ic_launcher_monochrome.png deleted file mode 100644 index bde37154..00000000 Binary files a/src/de/cineclix/res/mipmap-hdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/src/de/cineclix/res/mipmap-mdpi/ic_launcher_background.png b/src/de/cineclix/res/mipmap-mdpi/ic_launcher_background.png deleted file mode 100644 index 09b41700..00000000 Binary files a/src/de/cineclix/res/mipmap-mdpi/ic_launcher_background.png and /dev/null differ diff --git a/src/de/cineclix/res/mipmap-mdpi/ic_launcher_foreground.png b/src/de/cineclix/res/mipmap-mdpi/ic_launcher_foreground.png deleted file mode 100644 index 017b0039..00000000 Binary files a/src/de/cineclix/res/mipmap-mdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src/de/cineclix/res/mipmap-mdpi/ic_launcher_monochrome.png b/src/de/cineclix/res/mipmap-mdpi/ic_launcher_monochrome.png deleted file mode 100644 index 017b0039..00000000 Binary files a/src/de/cineclix/res/mipmap-mdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/src/de/cineclix/res/mipmap-xhdpi/ic_launcher_background.png b/src/de/cineclix/res/mipmap-xhdpi/ic_launcher_background.png deleted file mode 100644 index ea00baaf..00000000 Binary files a/src/de/cineclix/res/mipmap-xhdpi/ic_launcher_background.png and /dev/null differ diff --git a/src/de/cineclix/res/mipmap-xhdpi/ic_launcher_foreground.png b/src/de/cineclix/res/mipmap-xhdpi/ic_launcher_foreground.png deleted file mode 100644 index cc83ed87..00000000 Binary files a/src/de/cineclix/res/mipmap-xhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src/de/cineclix/res/mipmap-xhdpi/ic_launcher_monochrome.png b/src/de/cineclix/res/mipmap-xhdpi/ic_launcher_monochrome.png deleted file mode 100644 index cc83ed87..00000000 Binary files a/src/de/cineclix/res/mipmap-xhdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/src/de/cineclix/res/mipmap-xxhdpi/ic_launcher_background.png b/src/de/cineclix/res/mipmap-xxhdpi/ic_launcher_background.png deleted file mode 100644 index adcd3c25..00000000 Binary files a/src/de/cineclix/res/mipmap-xxhdpi/ic_launcher_background.png and /dev/null differ diff --git a/src/de/cineclix/res/mipmap-xxhdpi/ic_launcher_foreground.png b/src/de/cineclix/res/mipmap-xxhdpi/ic_launcher_foreground.png deleted file mode 100644 index bb12091e..00000000 Binary files a/src/de/cineclix/res/mipmap-xxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src/de/cineclix/res/mipmap-xxhdpi/ic_launcher_monochrome.png b/src/de/cineclix/res/mipmap-xxhdpi/ic_launcher_monochrome.png deleted file mode 100644 index bb12091e..00000000 Binary files a/src/de/cineclix/res/mipmap-xxhdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/src/de/cineclix/res/mipmap-xxxhdpi/ic_launcher_background.png b/src/de/cineclix/res/mipmap-xxxhdpi/ic_launcher_background.png deleted file mode 100644 index 08eb24e0..00000000 Binary files a/src/de/cineclix/res/mipmap-xxxhdpi/ic_launcher_background.png and /dev/null differ diff --git a/src/de/cineclix/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/src/de/cineclix/res/mipmap-xxxhdpi/ic_launcher_foreground.png deleted file mode 100644 index e82ff961..00000000 Binary files a/src/de/cineclix/res/mipmap-xxxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src/de/cineclix/res/mipmap-xxxhdpi/ic_launcher_monochrome.png b/src/de/cineclix/res/mipmap-xxxhdpi/ic_launcher_monochrome.png deleted file mode 100644 index e82ff961..00000000 Binary files a/src/de/cineclix/res/mipmap-xxxhdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/src/de/cinemathek/res/mipmap-hdpi/ic_launcher_adaptive_back.png b/src/de/cinemathek/res/mipmap-hdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 8dc560dd..00000000 Binary files a/src/de/cinemathek/res/mipmap-hdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/cinemathek/res/mipmap-hdpi/ic_launcher_adaptive_fore.png b/src/de/cinemathek/res/mipmap-hdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index fe053c9f..00000000 Binary files a/src/de/cinemathek/res/mipmap-hdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/cinemathek/res/mipmap-mdpi/ic_launcher_adaptive_back.png b/src/de/cinemathek/res/mipmap-mdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index f8feb6e5..00000000 Binary files a/src/de/cinemathek/res/mipmap-mdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/cinemathek/res/mipmap-mdpi/ic_launcher_adaptive_fore.png b/src/de/cinemathek/res/mipmap-mdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index bde9fb29..00000000 Binary files a/src/de/cinemathek/res/mipmap-mdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/cinemathek/res/mipmap-xhdpi/ic_launcher_adaptive_back.png b/src/de/cinemathek/res/mipmap-xhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 1b560124..00000000 Binary files a/src/de/cinemathek/res/mipmap-xhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/cinemathek/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png b/src/de/cinemathek/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index a3747f4b..00000000 Binary files a/src/de/cinemathek/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/cinemathek/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png b/src/de/cinemathek/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 369383ac..00000000 Binary files a/src/de/cinemathek/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/cinemathek/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png b/src/de/cinemathek/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index e26743f1..00000000 Binary files a/src/de/cinemathek/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/cinemathek/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png b/src/de/cinemathek/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index de26e98f..00000000 Binary files a/src/de/cinemathek/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/cinemathek/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png b/src/de/cinemathek/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 6b899ae7..00000000 Binary files a/src/de/cinemathek/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/filmpalast/res/mipmap-hdpi/ic_launcher_adaptive_back.png b/src/de/filmpalast/res/mipmap-hdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 8dc560dd..00000000 Binary files a/src/de/filmpalast/res/mipmap-hdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/filmpalast/res/mipmap-hdpi/ic_launcher_adaptive_fore.png b/src/de/filmpalast/res/mipmap-hdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 4c5d378f..00000000 Binary files a/src/de/filmpalast/res/mipmap-hdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/filmpalast/res/mipmap-mdpi/ic_launcher_adaptive_back.png b/src/de/filmpalast/res/mipmap-mdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index f8feb6e5..00000000 Binary files a/src/de/filmpalast/res/mipmap-mdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/filmpalast/res/mipmap-mdpi/ic_launcher_adaptive_fore.png b/src/de/filmpalast/res/mipmap-mdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 095e31f4..00000000 Binary files a/src/de/filmpalast/res/mipmap-mdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/filmpalast/res/mipmap-xhdpi/ic_launcher_adaptive_back.png b/src/de/filmpalast/res/mipmap-xhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 1b560124..00000000 Binary files a/src/de/filmpalast/res/mipmap-xhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/filmpalast/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png b/src/de/filmpalast/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 8787a0af..00000000 Binary files a/src/de/filmpalast/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/filmpalast/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png b/src/de/filmpalast/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 369383ac..00000000 Binary files a/src/de/filmpalast/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/filmpalast/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png b/src/de/filmpalast/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 6da85ba0..00000000 Binary files a/src/de/filmpalast/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/filmpalast/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png b/src/de/filmpalast/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index de26e98f..00000000 Binary files a/src/de/filmpalast/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/filmpalast/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png b/src/de/filmpalast/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 36f49fd3..00000000 Binary files a/src/de/filmpalast/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/kinoking/res/mipmap-hdpi/ic_launcher_adaptive_back.png b/src/de/kinoking/res/mipmap-hdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 8dc560dd..00000000 Binary files a/src/de/kinoking/res/mipmap-hdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/kinoking/res/mipmap-hdpi/ic_launcher_adaptive_fore.png b/src/de/kinoking/res/mipmap-hdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 5acc8ad2..00000000 Binary files a/src/de/kinoking/res/mipmap-hdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/kinoking/res/mipmap-mdpi/ic_launcher_adaptive_back.png b/src/de/kinoking/res/mipmap-mdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index f8feb6e5..00000000 Binary files a/src/de/kinoking/res/mipmap-mdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/kinoking/res/mipmap-mdpi/ic_launcher_adaptive_fore.png b/src/de/kinoking/res/mipmap-mdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 32a719b7..00000000 Binary files a/src/de/kinoking/res/mipmap-mdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/kinoking/res/mipmap-xhdpi/ic_launcher_adaptive_back.png b/src/de/kinoking/res/mipmap-xhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 1b560124..00000000 Binary files a/src/de/kinoking/res/mipmap-xhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/kinoking/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png b/src/de/kinoking/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index c303b600..00000000 Binary files a/src/de/kinoking/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/kinoking/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png b/src/de/kinoking/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 369383ac..00000000 Binary files a/src/de/kinoking/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/kinoking/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png b/src/de/kinoking/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 53bb9806..00000000 Binary files a/src/de/kinoking/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/kinoking/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png b/src/de/kinoking/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index de26e98f..00000000 Binary files a/src/de/kinoking/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/kinoking/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png b/src/de/kinoking/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 8e72d520..00000000 Binary files a/src/de/kinoking/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/kool/res/mipmap-hdpi/ic_launcher_background.png b/src/de/kool/res/mipmap-hdpi/ic_launcher_background.png deleted file mode 100644 index 2d07511b..00000000 Binary files a/src/de/kool/res/mipmap-hdpi/ic_launcher_background.png and /dev/null differ diff --git a/src/de/kool/res/mipmap-hdpi/ic_launcher_foreground.png b/src/de/kool/res/mipmap-hdpi/ic_launcher_foreground.png deleted file mode 100644 index 259233d7..00000000 Binary files a/src/de/kool/res/mipmap-hdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src/de/kool/res/mipmap-hdpi/ic_launcher_monochrome.png b/src/de/kool/res/mipmap-hdpi/ic_launcher_monochrome.png deleted file mode 100644 index 259233d7..00000000 Binary files a/src/de/kool/res/mipmap-hdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/src/de/kool/res/mipmap-mdpi/ic_launcher_background.png b/src/de/kool/res/mipmap-mdpi/ic_launcher_background.png deleted file mode 100644 index 09b41700..00000000 Binary files a/src/de/kool/res/mipmap-mdpi/ic_launcher_background.png and /dev/null differ diff --git a/src/de/kool/res/mipmap-mdpi/ic_launcher_foreground.png b/src/de/kool/res/mipmap-mdpi/ic_launcher_foreground.png deleted file mode 100644 index 360f5be2..00000000 Binary files a/src/de/kool/res/mipmap-mdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src/de/kool/res/mipmap-mdpi/ic_launcher_monochrome.png b/src/de/kool/res/mipmap-mdpi/ic_launcher_monochrome.png deleted file mode 100644 index 360f5be2..00000000 Binary files a/src/de/kool/res/mipmap-mdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/src/de/kool/res/mipmap-xhdpi/ic_launcher_background.png b/src/de/kool/res/mipmap-xhdpi/ic_launcher_background.png deleted file mode 100644 index ea00baaf..00000000 Binary files a/src/de/kool/res/mipmap-xhdpi/ic_launcher_background.png and /dev/null differ diff --git a/src/de/kool/res/mipmap-xhdpi/ic_launcher_foreground.png b/src/de/kool/res/mipmap-xhdpi/ic_launcher_foreground.png deleted file mode 100644 index de15043d..00000000 Binary files a/src/de/kool/res/mipmap-xhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src/de/kool/res/mipmap-xhdpi/ic_launcher_monochrome.png b/src/de/kool/res/mipmap-xhdpi/ic_launcher_monochrome.png deleted file mode 100644 index de15043d..00000000 Binary files a/src/de/kool/res/mipmap-xhdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/src/de/kool/res/mipmap-xxhdpi/ic_launcher_background.png b/src/de/kool/res/mipmap-xxhdpi/ic_launcher_background.png deleted file mode 100644 index adcd3c25..00000000 Binary files a/src/de/kool/res/mipmap-xxhdpi/ic_launcher_background.png and /dev/null differ diff --git a/src/de/kool/res/mipmap-xxhdpi/ic_launcher_foreground.png b/src/de/kool/res/mipmap-xxhdpi/ic_launcher_foreground.png deleted file mode 100644 index 902dd5b9..00000000 Binary files a/src/de/kool/res/mipmap-xxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src/de/kool/res/mipmap-xxhdpi/ic_launcher_monochrome.png b/src/de/kool/res/mipmap-xxhdpi/ic_launcher_monochrome.png deleted file mode 100644 index 902dd5b9..00000000 Binary files a/src/de/kool/res/mipmap-xxhdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/src/de/kool/res/mipmap-xxxhdpi/ic_launcher_background.png b/src/de/kool/res/mipmap-xxxhdpi/ic_launcher_background.png deleted file mode 100644 index 08eb24e0..00000000 Binary files a/src/de/kool/res/mipmap-xxxhdpi/ic_launcher_background.png and /dev/null differ diff --git a/src/de/kool/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/src/de/kool/res/mipmap-xxxhdpi/ic_launcher_foreground.png deleted file mode 100644 index 7046d799..00000000 Binary files a/src/de/kool/res/mipmap-xxxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src/de/kool/res/mipmap-xxxhdpi/ic_launcher_monochrome.png b/src/de/kool/res/mipmap-xxxhdpi/ic_launcher_monochrome.png deleted file mode 100644 index 7046d799..00000000 Binary files a/src/de/kool/res/mipmap-xxxhdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/src/de/movie2k/res/mipmap-hdpi/ic_launcher_background.png b/src/de/movie2k/res/mipmap-hdpi/ic_launcher_background.png deleted file mode 100644 index 2d07511b..00000000 Binary files a/src/de/movie2k/res/mipmap-hdpi/ic_launcher_background.png and /dev/null differ diff --git a/src/de/movie2k/res/mipmap-hdpi/ic_launcher_foreground.png b/src/de/movie2k/res/mipmap-hdpi/ic_launcher_foreground.png deleted file mode 100644 index cf49c890..00000000 Binary files a/src/de/movie2k/res/mipmap-hdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src/de/movie2k/res/mipmap-hdpi/ic_launcher_monochrome.png b/src/de/movie2k/res/mipmap-hdpi/ic_launcher_monochrome.png deleted file mode 100644 index cf49c890..00000000 Binary files a/src/de/movie2k/res/mipmap-hdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/src/de/movie2k/res/mipmap-mdpi/ic_launcher_background.png b/src/de/movie2k/res/mipmap-mdpi/ic_launcher_background.png deleted file mode 100644 index 09b41700..00000000 Binary files a/src/de/movie2k/res/mipmap-mdpi/ic_launcher_background.png and /dev/null differ diff --git a/src/de/movie2k/res/mipmap-mdpi/ic_launcher_foreground.png b/src/de/movie2k/res/mipmap-mdpi/ic_launcher_foreground.png deleted file mode 100644 index d4276e61..00000000 Binary files a/src/de/movie2k/res/mipmap-mdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src/de/movie2k/res/mipmap-mdpi/ic_launcher_monochrome.png b/src/de/movie2k/res/mipmap-mdpi/ic_launcher_monochrome.png deleted file mode 100644 index d4276e61..00000000 Binary files a/src/de/movie2k/res/mipmap-mdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/src/de/movie2k/res/mipmap-xhdpi/ic_launcher_background.png b/src/de/movie2k/res/mipmap-xhdpi/ic_launcher_background.png deleted file mode 100644 index ea00baaf..00000000 Binary files a/src/de/movie2k/res/mipmap-xhdpi/ic_launcher_background.png and /dev/null differ diff --git a/src/de/movie2k/res/mipmap-xhdpi/ic_launcher_foreground.png b/src/de/movie2k/res/mipmap-xhdpi/ic_launcher_foreground.png deleted file mode 100644 index 6474e13c..00000000 Binary files a/src/de/movie2k/res/mipmap-xhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src/de/movie2k/res/mipmap-xhdpi/ic_launcher_monochrome.png b/src/de/movie2k/res/mipmap-xhdpi/ic_launcher_monochrome.png deleted file mode 100644 index 6474e13c..00000000 Binary files a/src/de/movie2k/res/mipmap-xhdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/src/de/movie2k/res/mipmap-xxhdpi/ic_launcher_background.png b/src/de/movie2k/res/mipmap-xxhdpi/ic_launcher_background.png deleted file mode 100644 index adcd3c25..00000000 Binary files a/src/de/movie2k/res/mipmap-xxhdpi/ic_launcher_background.png and /dev/null differ diff --git a/src/de/movie2k/res/mipmap-xxhdpi/ic_launcher_foreground.png b/src/de/movie2k/res/mipmap-xxhdpi/ic_launcher_foreground.png deleted file mode 100644 index 3777ec91..00000000 Binary files a/src/de/movie2k/res/mipmap-xxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src/de/movie2k/res/mipmap-xxhdpi/ic_launcher_monochrome.png b/src/de/movie2k/res/mipmap-xxhdpi/ic_launcher_monochrome.png deleted file mode 100644 index 3777ec91..00000000 Binary files a/src/de/movie2k/res/mipmap-xxhdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/src/de/movie2k/res/mipmap-xxxhdpi/ic_launcher_background.png b/src/de/movie2k/res/mipmap-xxxhdpi/ic_launcher_background.png deleted file mode 100644 index 08eb24e0..00000000 Binary files a/src/de/movie2k/res/mipmap-xxxhdpi/ic_launcher_background.png and /dev/null differ diff --git a/src/de/movie2k/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/src/de/movie2k/res/mipmap-xxxhdpi/ic_launcher_foreground.png deleted file mode 100644 index bbeb49b6..00000000 Binary files a/src/de/movie2k/res/mipmap-xxxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src/de/movie2k/res/mipmap-xxxhdpi/ic_launcher_monochrome.png b/src/de/movie2k/res/mipmap-xxxhdpi/ic_launcher_monochrome.png deleted file mode 100644 index bbeb49b6..00000000 Binary files a/src/de/movie2k/res/mipmap-xxxhdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/src/de/movie4k/res/mipmap-hdpi/ic_launcher_adaptive_back.png b/src/de/movie4k/res/mipmap-hdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 8dc560dd..00000000 Binary files a/src/de/movie4k/res/mipmap-hdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/movie4k/res/mipmap-hdpi/ic_launcher_adaptive_fore.png b/src/de/movie4k/res/mipmap-hdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 55c43ca1..00000000 Binary files a/src/de/movie4k/res/mipmap-hdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/movie4k/res/mipmap-mdpi/ic_launcher_adaptive_back.png b/src/de/movie4k/res/mipmap-mdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index f8feb6e5..00000000 Binary files a/src/de/movie4k/res/mipmap-mdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/movie4k/res/mipmap-mdpi/ic_launcher_adaptive_fore.png b/src/de/movie4k/res/mipmap-mdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 44113ef3..00000000 Binary files a/src/de/movie4k/res/mipmap-mdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/movie4k/res/mipmap-xhdpi/ic_launcher_adaptive_back.png b/src/de/movie4k/res/mipmap-xhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 1b560124..00000000 Binary files a/src/de/movie4k/res/mipmap-xhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/movie4k/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png b/src/de/movie4k/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 61101bff..00000000 Binary files a/src/de/movie4k/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/movie4k/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png b/src/de/movie4k/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 369383ac..00000000 Binary files a/src/de/movie4k/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/movie4k/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png b/src/de/movie4k/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index ee622825..00000000 Binary files a/src/de/movie4k/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/movie4k/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png b/src/de/movie4k/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index de26e98f..00000000 Binary files a/src/de/movie4k/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/movie4k/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png b/src/de/movie4k/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 3e20bba5..00000000 Binary files a/src/de/movie4k/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/serienstream/res/mipmap-hdpi/ic_launcher_adaptive_back.png b/src/de/serienstream/res/mipmap-hdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 8c5bf007..00000000 Binary files a/src/de/serienstream/res/mipmap-hdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/serienstream/res/mipmap-hdpi/ic_launcher_adaptive_fore.png b/src/de/serienstream/res/mipmap-hdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 8dd53660..00000000 Binary files a/src/de/serienstream/res/mipmap-hdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/serienstream/res/mipmap-mdpi/ic_launcher_adaptive_back.png b/src/de/serienstream/res/mipmap-mdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 11c72b22..00000000 Binary files a/src/de/serienstream/res/mipmap-mdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/serienstream/res/mipmap-mdpi/ic_launcher_adaptive_fore.png b/src/de/serienstream/res/mipmap-mdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index f5c1856c..00000000 Binary files a/src/de/serienstream/res/mipmap-mdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/serienstream/res/mipmap-xhdpi/ic_launcher_adaptive_back.png b/src/de/serienstream/res/mipmap-xhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 0f790191..00000000 Binary files a/src/de/serienstream/res/mipmap-xhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/serienstream/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png b/src/de/serienstream/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 25655d87..00000000 Binary files a/src/de/serienstream/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/serienstream/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png b/src/de/serienstream/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index e598be57..00000000 Binary files a/src/de/serienstream/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/serienstream/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png b/src/de/serienstream/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 50887149..00000000 Binary files a/src/de/serienstream/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/serienstream/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png b/src/de/serienstream/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 9ad66cf9..00000000 Binary files a/src/de/serienstream/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/serienstream/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png b/src/de/serienstream/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 846822fa..00000000 Binary files a/src/de/serienstream/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/streamcloud/res/mipmap-hdpi/ic_launcher_adaptive_back.png b/src/de/streamcloud/res/mipmap-hdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 8c5bf007..00000000 Binary files a/src/de/streamcloud/res/mipmap-hdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/streamcloud/res/mipmap-hdpi/ic_launcher_adaptive_fore.png b/src/de/streamcloud/res/mipmap-hdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 68d25f33..00000000 Binary files a/src/de/streamcloud/res/mipmap-hdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/streamcloud/res/mipmap-mdpi/ic_launcher_adaptive_back.png b/src/de/streamcloud/res/mipmap-mdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 11c72b22..00000000 Binary files a/src/de/streamcloud/res/mipmap-mdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/streamcloud/res/mipmap-mdpi/ic_launcher_adaptive_fore.png b/src/de/streamcloud/res/mipmap-mdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index e4635082..00000000 Binary files a/src/de/streamcloud/res/mipmap-mdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/streamcloud/res/mipmap-xhdpi/ic_launcher_adaptive_back.png b/src/de/streamcloud/res/mipmap-xhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 0f790191..00000000 Binary files a/src/de/streamcloud/res/mipmap-xhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/streamcloud/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png b/src/de/streamcloud/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index c935b1e2..00000000 Binary files a/src/de/streamcloud/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/streamcloud/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png b/src/de/streamcloud/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index e598be57..00000000 Binary files a/src/de/streamcloud/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/streamcloud/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png b/src/de/streamcloud/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index c7e083ea..00000000 Binary files a/src/de/streamcloud/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/de/streamcloud/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png b/src/de/streamcloud/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 9ad66cf9..00000000 Binary files a/src/de/streamcloud/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/de/streamcloud/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png b/src/de/streamcloud/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index d0da73c8..00000000 Binary files a/src/de/streamcloud/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/en/allanime/res/web_hi_res_512.png b/src/en/allanime/res/web_hi_res_512.png deleted file mode 100644 index 77e5e5ca..00000000 Binary files a/src/en/allanime/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/allanimechi/res/web_hi_res_512.png b/src/en/allanimechi/res/web_hi_res_512.png deleted file mode 100644 index 337bc317..00000000 Binary files a/src/en/allanimechi/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/animeowl/build.gradle b/src/en/animeowl/build.gradle index a03357bc..e5849d46 100644 --- a/src/en/animeowl/build.gradle +++ b/src/en/animeowl/build.gradle @@ -1,7 +1,7 @@ ext { extName = 'AnimeOwl' extClass = '.AnimeOwl' - extVersionCode = 21 + extVersionCode = 22 } apply from: "$rootDir/common.gradle" @@ -9,4 +9,4 @@ apply from: "$rootDir/common.gradle" dependencies { implementation(project(":lib:synchrony")) implementation(project(":lib:playlist-utils")) -} \ No newline at end of file +} diff --git a/src/en/animeowl/res/web_hi_res_512.png b/src/en/animeowl/res/web_hi_res_512.png deleted file mode 100644 index 8305be17..00000000 Binary files a/src/en/animeowl/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/animeowl/src/eu/kanade/tachiyomi/animeextension/en/animeowl/AnimeOwl.kt b/src/en/animeowl/src/eu/kanade/tachiyomi/animeextension/en/animeowl/AnimeOwl.kt index dee4ddad..b53606e8 100644 --- a/src/en/animeowl/src/eu/kanade/tachiyomi/animeextension/en/animeowl/AnimeOwl.kt +++ b/src/en/animeowl/src/eu/kanade/tachiyomi/animeextension/en/animeowl/AnimeOwl.kt @@ -38,7 +38,7 @@ class AnimeOwl : ConfigurableAnimeSource, ParsedAnimeHttpSource() { override val name = "AnimeOwl" - override val baseUrl = "https://animeowl.live" + override val baseUrl = "https://animeowl.me" override val lang = "en" diff --git a/src/en/animepahe/res/web_hi_res_512.png b/src/en/animepahe/res/web_hi_res_512.png deleted file mode 100644 index 84c0ab15..00000000 Binary files a/src/en/animepahe/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/animeparadise/res/web_hi_res_512.png b/src/en/animeparadise/res/web_hi_res_512.png deleted file mode 100644 index 1927b8de..00000000 Binary files a/src/en/animeparadise/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/animetake/res/web_hi_res_512.png b/src/en/animetake/res/web_hi_res_512.png deleted file mode 100644 index 5741c7d1..00000000 Binary files a/src/en/animetake/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/aniplay/ic_launcher-playstore.png b/src/en/aniplay/ic_launcher-playstore.png deleted file mode 100644 index 7e70c67f..00000000 Binary files a/src/en/aniplay/ic_launcher-playstore.png and /dev/null differ diff --git a/src/en/aniplay/res/web_hi_res_512.png b/src/en/aniplay/res/web_hi_res_512.png deleted file mode 100644 index f56e465f..00000000 Binary files a/src/en/aniplay/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/asiaflix/res/web_hi_res_512.png b/src/en/asiaflix/res/web_hi_res_512.png deleted file mode 100644 index a7cebae2..00000000 Binary files a/src/en/asiaflix/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/bestdubbedanime/res/web_hi_res_512.png b/src/en/bestdubbedanime/res/web_hi_res_512.png deleted file mode 100644 index 6a31bcaa..00000000 Binary files a/src/en/bestdubbedanime/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/dopebox/res/play_store_512.png b/src/en/dopebox/res/play_store_512.png deleted file mode 100644 index c67510b7..00000000 Binary files a/src/en/dopebox/res/play_store_512.png and /dev/null differ diff --git a/src/en/dramacool/res/play_store_512.png b/src/en/dramacool/res/play_store_512.png deleted file mode 100644 index 6b1a72a2..00000000 Binary files a/src/en/dramacool/res/play_store_512.png and /dev/null differ diff --git a/src/en/edytjedhgmdhm/res/web_hi_res_512.png b/src/en/edytjedhgmdhm/res/web_hi_res_512.png deleted file mode 100644 index 5c314e3c..00000000 Binary files a/src/en/edytjedhgmdhm/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/fmovies/res/web_hi_res_512.png b/src/en/fmovies/res/web_hi_res_512.png deleted file mode 100644 index 116e1e1c..00000000 Binary files a/src/en/fmovies/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/gogoanime/res/web_hi_res_512.png b/src/en/gogoanime/res/web_hi_res_512.png deleted file mode 100644 index a681ed1f..00000000 Binary files a/src/en/gogoanime/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/hahomoe/res/web_hi_res_512.png b/src/en/hahomoe/res/web_hi_res_512.png deleted file mode 100644 index 0fe6a622..00000000 Binary files a/src/en/hahomoe/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/hanime/res/web_hi_res_500.png b/src/en/hanime/res/web_hi_res_500.png deleted file mode 100644 index d80d06d9..00000000 Binary files a/src/en/hanime/res/web_hi_res_500.png and /dev/null differ diff --git a/src/en/hentaimama/ic_launcher-playstore.png b/src/en/hentaimama/ic_launcher-playstore.png deleted file mode 100644 index a3de5ca0..00000000 Binary files a/src/en/hentaimama/ic_launcher-playstore.png and /dev/null differ diff --git a/src/en/hentaimama/res/web_hi_res_500.png b/src/en/hentaimama/res/web_hi_res_500.png deleted file mode 100644 index a3de5ca0..00000000 Binary files a/src/en/hentaimama/res/web_hi_res_500.png and /dev/null differ diff --git a/src/en/kaido/res/play_store_512.png b/src/en/kaido/res/play_store_512.png deleted file mode 100644 index 4115b0c6..00000000 Binary files a/src/en/kaido/res/play_store_512.png and /dev/null differ diff --git a/src/en/kawaiifu/res/web_hi_res_512.png b/src/en/kawaiifu/res/web_hi_res_512.png deleted file mode 100644 index 40e21f8c..00000000 Binary files a/src/en/kawaiifu/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/kayoanime/res/web_hi_res_512.png b/src/en/kayoanime/res/web_hi_res_512.png deleted file mode 100644 index 6931c263..00000000 Binary files a/src/en/kayoanime/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/kickassanime/res/web_hi_res_512.png b/src/en/kickassanime/res/web_hi_res_512.png deleted file mode 100644 index 01378e9b..00000000 Binary files a/src/en/kickassanime/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/kimoitv/res/web_hi_res_512.png b/src/en/kimoitv/res/web_hi_res_512.png deleted file mode 100644 index 9ee07beb..00000000 Binary files a/src/en/kimoitv/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/kissanime/res/web_hi_res_512.png b/src/en/kissanime/res/web_hi_res_512.png deleted file mode 100644 index 582bb486..00000000 Binary files a/src/en/kissanime/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/kisskh/res/mipmap-hdpi/ic_launcher_background.png b/src/en/kisskh/res/mipmap-hdpi/ic_launcher_background.png deleted file mode 100644 index ec6292a2..00000000 Binary files a/src/en/kisskh/res/mipmap-hdpi/ic_launcher_background.png and /dev/null differ diff --git a/src/en/kisskh/res/mipmap-hdpi/ic_launcher_foreground.png b/src/en/kisskh/res/mipmap-hdpi/ic_launcher_foreground.png deleted file mode 100644 index 071fd1db..00000000 Binary files a/src/en/kisskh/res/mipmap-hdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src/en/kisskh/res/mipmap-hdpi/ic_launcher_monochrome.png b/src/en/kisskh/res/mipmap-hdpi/ic_launcher_monochrome.png deleted file mode 100644 index 071fd1db..00000000 Binary files a/src/en/kisskh/res/mipmap-hdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/src/en/kisskh/res/mipmap-mdpi/ic_launcher_background.png b/src/en/kisskh/res/mipmap-mdpi/ic_launcher_background.png deleted file mode 100644 index df2d7e08..00000000 Binary files a/src/en/kisskh/res/mipmap-mdpi/ic_launcher_background.png and /dev/null differ diff --git a/src/en/kisskh/res/mipmap-mdpi/ic_launcher_foreground.png b/src/en/kisskh/res/mipmap-mdpi/ic_launcher_foreground.png deleted file mode 100644 index 1050e1ca..00000000 Binary files a/src/en/kisskh/res/mipmap-mdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src/en/kisskh/res/mipmap-mdpi/ic_launcher_monochrome.png b/src/en/kisskh/res/mipmap-mdpi/ic_launcher_monochrome.png deleted file mode 100644 index 1050e1ca..00000000 Binary files a/src/en/kisskh/res/mipmap-mdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/src/en/kisskh/res/mipmap-xhdpi/ic_launcher_background.png b/src/en/kisskh/res/mipmap-xhdpi/ic_launcher_background.png deleted file mode 100644 index 08c6199c..00000000 Binary files a/src/en/kisskh/res/mipmap-xhdpi/ic_launcher_background.png and /dev/null differ diff --git a/src/en/kisskh/res/mipmap-xhdpi/ic_launcher_foreground.png b/src/en/kisskh/res/mipmap-xhdpi/ic_launcher_foreground.png deleted file mode 100644 index 8593420b..00000000 Binary files a/src/en/kisskh/res/mipmap-xhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src/en/kisskh/res/mipmap-xhdpi/ic_launcher_monochrome.png b/src/en/kisskh/res/mipmap-xhdpi/ic_launcher_monochrome.png deleted file mode 100644 index 8593420b..00000000 Binary files a/src/en/kisskh/res/mipmap-xhdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/src/en/kisskh/res/mipmap-xxhdpi/ic_launcher_background.png b/src/en/kisskh/res/mipmap-xxhdpi/ic_launcher_background.png deleted file mode 100644 index 8b158f91..00000000 Binary files a/src/en/kisskh/res/mipmap-xxhdpi/ic_launcher_background.png and /dev/null differ diff --git a/src/en/kisskh/res/mipmap-xxhdpi/ic_launcher_foreground.png b/src/en/kisskh/res/mipmap-xxhdpi/ic_launcher_foreground.png deleted file mode 100644 index 1d3082f7..00000000 Binary files a/src/en/kisskh/res/mipmap-xxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src/en/kisskh/res/mipmap-xxhdpi/ic_launcher_monochrome.png b/src/en/kisskh/res/mipmap-xxhdpi/ic_launcher_monochrome.png deleted file mode 100644 index 1d3082f7..00000000 Binary files a/src/en/kisskh/res/mipmap-xxhdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/src/en/kisskh/res/mipmap-xxxhdpi/ic_launcher_background.png b/src/en/kisskh/res/mipmap-xxxhdpi/ic_launcher_background.png deleted file mode 100644 index a1092411..00000000 Binary files a/src/en/kisskh/res/mipmap-xxxhdpi/ic_launcher_background.png and /dev/null differ diff --git a/src/en/kisskh/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/src/en/kisskh/res/mipmap-xxxhdpi/ic_launcher_foreground.png deleted file mode 100644 index 9def206c..00000000 Binary files a/src/en/kisskh/res/mipmap-xxxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src/en/kisskh/res/mipmap-xxxhdpi/ic_launcher_monochrome.png b/src/en/kisskh/res/mipmap-xxxhdpi/ic_launcher_monochrome.png deleted file mode 100644 index 9def206c..00000000 Binary files a/src/en/kisskh/res/mipmap-xxxhdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/src/en/myanime/res/web_hi_res_512.png b/src/en/myanime/res/web_hi_res_512.png deleted file mode 100644 index abee430c..00000000 Binary files a/src/en/myanime/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/noobsubs/res/web_hi_res_512.png b/src/en/noobsubs/res/web_hi_res_512.png deleted file mode 100644 index 0e2027a2..00000000 Binary files a/src/en/noobsubs/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/putlocker/res/web_hi_res_512.png b/src/en/putlocker/res/web_hi_res_512.png deleted file mode 100644 index c0b04c76..00000000 Binary files a/src/en/putlocker/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/rule34video/res/web_hi_res_500.png b/src/en/rule34video/res/web_hi_res_500.png deleted file mode 100644 index 7457e072..00000000 Binary files a/src/en/rule34video/res/web_hi_res_500.png and /dev/null differ diff --git a/src/en/sflix/res/play_store_512.png b/src/en/sflix/res/play_store_512.png deleted file mode 100644 index 6e157d8a..00000000 Binary files a/src/en/sflix/res/play_store_512.png and /dev/null differ diff --git a/src/en/superstream/res/web_hi_res_512.png b/src/en/superstream/res/web_hi_res_512.png deleted file mode 100644 index bd2158b7..00000000 Binary files a/src/en/superstream/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/uhdmovies/res/web_hi_res_512.png b/src/en/uhdmovies/res/web_hi_res_512.png deleted file mode 100644 index 42b1f7c6..00000000 Binary files a/src/en/uhdmovies/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/uniquestream/res/web_hi_res_512.png b/src/en/uniquestream/res/web_hi_res_512.png deleted file mode 100644 index 73a3a7b0..00000000 Binary files a/src/en/uniquestream/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/wcofun/res/web_hi_res_512.png b/src/en/wcofun/res/web_hi_res_512.png deleted file mode 100644 index fe248b2d..00000000 Binary files a/src/en/wcofun/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/wcostream/res/play_store_512.png b/src/en/wcostream/res/play_store_512.png deleted file mode 100644 index b2e10c2a..00000000 Binary files a/src/en/wcostream/res/play_store_512.png and /dev/null differ diff --git a/src/es/animefenix/build.gradle b/src/es/animefenix/build.gradle index be565367..38c7f15a 100644 --- a/src/es/animefenix/build.gradle +++ b/src/es/animefenix/build.gradle @@ -1,7 +1,7 @@ ext { extName = 'Animefenix' extClass = '.Animefenix' - extVersionCode = 55 + extVersionCode = 57 } apply from: "$rootDir/common.gradle" @@ -17,9 +17,9 @@ dependencies { implementation(project(':lib:filemoon-extractor')) implementation(project(':lib:voe-extractor')) implementation(project(':lib:streamlare-extractor')) - implementation(project(':lib:fastream-extractor')) implementation(project(':lib:dood-extractor')) implementation(project(':lib:upstream-extractor')) implementation(project(':lib:streamhidevid-extractor')) implementation(project(':lib:universal-extractor')) + implementation(project(':lib:amazon-extractor')) } diff --git a/src/es/animefenix/src/eu/kanade/tachiyomi/animeextension/es/animefenix/AnimeFenixFilters.kt b/src/es/animefenix/src/eu/kanade/tachiyomi/animeextension/es/animefenix/AnimeFenixFilters.kt index eaab6fbf..5bdebcd9 100644 --- a/src/es/animefenix/src/eu/kanade/tachiyomi/animeextension/es/animefenix/AnimeFenixFilters.kt +++ b/src/es/animefenix/src/eu/kanade/tachiyomi/animeextension/es/animefenix/AnimeFenixFilters.kt @@ -12,30 +12,6 @@ object AnimeFenixFilters { fun toQueryPart(name: String) = vals[state].second.takeIf { it.isNotEmpty() }?.let { "&$name=${vals[state].second}" } ?: run { "" } } - open class CheckBoxFilterList(name: String, values: List<CheckBox>) : AnimeFilter.Group<AnimeFilter.CheckBox>(name, values) - - private class CheckBoxVal(name: String, state: Boolean = false) : AnimeFilter.CheckBox(name, state) - - private inline fun <reified R> AnimeFilterList.parseCheckbox( - options: Array<Pair<String, String>>, - name: String, - ): String { - return (this.getFirst<R>() as CheckBoxFilterList).state - .mapNotNull { checkbox -> - if (checkbox.state) { - options.find { it.first == checkbox.name }!!.second - } else { - null - } - }.joinToString("&$name[]=").let { - if (it.isBlank()) { - "" - } else { - "&$name[]=$it" - } - } - } - private inline fun <reified R> AnimeFilterList.asQueryPart(name: String): String { return (this.getFirst<R>() as QueryPartFilter).toQueryPart(name) } @@ -51,111 +27,118 @@ object AnimeFenixFilters { internal fun getSearchParameters(filters: AnimeFilterList): FilterSearchParams { if (filters.isEmpty()) return FilterSearchParams() return FilterSearchParams( - filters.parseCheckbox<GenresFilter>(AnimeFenixFiltersData.GENRES, "genero") + - filters.parseCheckbox<YearsFilter>(AnimeFenixFiltersData.YEARS, "year") + - filters.parseCheckbox<TypesFilter>(AnimeFenixFiltersData.TYPES, "type") + - filters.parseCheckbox<StateFilter>(AnimeFenixFiltersData.STATE, "estado") + - filters.asQueryPart<SortFilter>("order"), + filters.asQueryPart<StateFilter>("estado") + + filters.asQueryPart<TypesFilter>("tipo") + + filters.asQueryPart<GenresFilter>("genero") + + filters.asQueryPart<YearsFilter>("estreno") + + filters.asQueryPart<LangFilter>("idioma"), ) } val FILTER_LIST get() = AnimeFilterList( AnimeFilter.Header("La busqueda por texto ignora el filtro"), + StateFilter(), + TypesFilter(), GenresFilter(), YearsFilter(), - TypesFilter(), - StateFilter(), - SortFilter(), + LangFilter(), ) - class GenresFilter : CheckBoxFilterList("Género", AnimeFenixFiltersData.GENRES.map { CheckBoxVal(it.first, false) }) - - class YearsFilter : CheckBoxFilterList("Año", AnimeFenixFiltersData.YEARS.map { CheckBoxVal(it.first, false) }) - - class TypesFilter : CheckBoxFilterList("Tipo", AnimeFenixFiltersData.TYPES.map { CheckBoxVal(it.first, false) }) - - class StateFilter : CheckBoxFilterList("Estado", AnimeFenixFiltersData.STATE.map { CheckBoxVal(it.first, false) }) - - class SortFilter : QueryPartFilter("Orden", AnimeFenixFiltersData.SORT) + class StateFilter : QueryPartFilter("Estado", AnimeFenixFiltersData.STATE) + class TypesFilter : QueryPartFilter("Tipo", AnimeFenixFiltersData.TYPES) + class GenresFilter : QueryPartFilter("Género", AnimeFenixFiltersData.GENRES) + class YearsFilter : QueryPartFilter("Año", AnimeFenixFiltersData.YEARS) + class LangFilter : QueryPartFilter("Idioma", AnimeFenixFiltersData.LANGUAGE) private object AnimeFenixFiltersData { - val YEARS = (1990..Calendar.getInstance().get(Calendar.YEAR)).map { Pair("$it", "$it") }.reversed().toTypedArray() + val STATE = arrayOf( + Pair("Todos", ""), + Pair("Emisión", "2"), + Pair("Finalizado", "1"), + Pair("Próximamente", "3"), + ) val TYPES = arrayOf( - Pair("TV", "tv"), - Pair("Película", "movie"), - Pair("Especial", "special"), - Pair("OVA", "ova"), - Pair("DONGHUA", "donghua"), - ) - - val STATE = arrayOf( - Pair("Emisión", "1"), - Pair("Finalizado", "2"), - Pair("Próximamente", "3"), - Pair("En Cuarentena", "4"), - ) - - val SORT = arrayOf( - Pair("Por Defecto", "default"), - Pair("Recientemente Actualizados", "updated"), - Pair("Recientemente Agregados", "added"), - Pair("Nombre A-Z", "title"), - Pair("Calificación", "likes"), - Pair("Más Vistos", "visits"), + Pair("Todos", ""), + Pair("TV", "1"), + Pair("Película", "2"), + Pair("OVA", "3"), + Pair("Especial", "4"), + Pair("Serie", "9"), + Pair("Dorama", "11"), + Pair("Corto", "14"), + Pair("Donghua", "15"), + Pair("ONA", "16"), + Pair("Live Action", "17"), + Pair("Manhwa", "18"), + Pair("Teatral", "19"), ) val GENRES = arrayOf( - Pair("Acción", "accion"), - Pair("Ángeles", "angeles"), - Pair("Artes Marciales", "artes-marciales"), - Pair("Aventura", "aventura"), - Pair("Ciencia Ficción", "Ciencia Ficción"), - Pair("Comedia", "comedia"), - Pair("Cyberpunk", "cyberpunk"), - Pair("Demonios", "demonios"), - Pair("Deportes", "deportes"), - Pair("Dragones", "dragones"), - Pair("Drama", "drama"), - Pair("Ecchi", "ecchi"), - Pair("Escolares", "escolares"), - Pair("Fantasía", "fantasia"), - Pair("Gore", "gore"), - Pair("Harem", "harem"), - Pair("Histórico", "historico"), - Pair("Horror", "horror"), - Pair("Infantil", "infantil"), - Pair("Isekai", "isekai"), - Pair("Josei", "josei"), - Pair("Juegos", "juegos"), - Pair("Magia", "magia"), - Pair("Mecha", "mecha"), - Pair("Militar", "militar"), - Pair("Misterio", "misterio"), - Pair("Música", "Musica"), - Pair("Ninjas", "ninjas"), - Pair("Parodia", "parodia"), - Pair("Policía", "policia"), - Pair("Psicológico", "psicologico"), - Pair("Recuerdos de la vida", "Recuerdos de la vida"), - Pair("Romance", "romance"), - Pair("Samurai", "samurai"), - Pair("Sci-Fi", "sci-fi"), - Pair("Seinen", "seinen"), - Pair("Shoujo", "shoujo"), - Pair("Shoujo Ai", "shoujo-ai"), - Pair("Shounen", "shounen"), - Pair("Slice of life", "slice-of-life"), - Pair("Sobrenatural", "sobrenatural"), - Pair("Space", "space"), - Pair("Spokon", "spokon"), - Pair("Steampunk", "steampunk"), - Pair("Superpoder", "superpoder"), - Pair("Thriller", "thriller"), - Pair("Vampiro", "vampiro"), - Pair("Yaoi", "yaoi"), - Pair("Yuri", "yuri"), - Pair("Zombies", "zombies"), + Pair("Todos", ""), + Pair("Acción", "1"), + Pair("Escolares", "2"), + Pair("Romance", "3"), + Pair("Shoujo", "4"), + Pair("Comedia", "5"), + Pair("Drama", "6"), + Pair("Seinen", "7"), + Pair("Deportes", "8"), + Pair("Shounen", "9"), + Pair("Recuentos de la vida", "10"), + Pair("Ecchi", "11"), + Pair("Sobrenatural", "12"), + Pair("Fantasía", "13"), + Pair("Magia", "14"), + Pair("Superpoderes", "15"), + Pair("Demencia", "16"), + Pair("Misterio", "17"), + Pair("Psicológico", "18"), + Pair("Suspenso", "19"), + Pair("Ciencia Ficción", "20"), + Pair("Mecha", "21"), + Pair("Militar", "22"), + Pair("Aventuras", "23"), + Pair("Historico", "24"), + Pair("Infantil", "25"), + Pair("Artes Marciales", "26"), + Pair("Terror", "27"), + Pair("Harem", "28"), + Pair("Josei", "29"), + Pair("Parodia", "30"), + Pair("Policía", "31"), + Pair("Juegos", "32"), + Pair("Carreras", "33"), + Pair("Samurai", "34"), + Pair("Espacial", "35"), + Pair("Música", "36"), + Pair("Yuri", "37"), + Pair("Demonios", "38"), + Pair("Vampiros", "39"), + Pair("Yaoi", "40"), + Pair("Humor Negro", "41"), + Pair("Crimen", "42"), + Pair("Hentai", "43"), + Pair("Youtuber", "44"), + Pair("MaiNess Random", "45"), + Pair("Donghua", "46"), + Pair("Horror", "47"), + Pair("Sin Censura", "48"), + Pair("Gore", "49"), + Pair("Live Action", "50"), + Pair("Isekai", "51"), + Pair("Gourmet", "52"), + Pair("spokon", "53"), + Pair("Zombies", "54"), + Pair("Idols", "55"), ) + + val LANGUAGE = arrayOf( + Pair("Todos", ""), + Pair("Japonés", "1"), + Pair("Latino", "2"), + ) + + val YEARS = arrayOf(Pair("Todos", "")) + (1967..Calendar.getInstance().get(Calendar.YEAR)).map { Pair("$it", "$it") }.reversed().toTypedArray() } } diff --git a/src/es/animefenix/src/eu/kanade/tachiyomi/animeextension/es/animefenix/Animefenix.kt b/src/es/animefenix/src/eu/kanade/tachiyomi/animeextension/es/animefenix/Animefenix.kt index dc1487bd..adb7fef5 100644 --- a/src/es/animefenix/src/eu/kanade/tachiyomi/animeextension/es/animefenix/Animefenix.kt +++ b/src/es/animefenix/src/eu/kanade/tachiyomi/animeextension/es/animefenix/Animefenix.kt @@ -11,9 +11,9 @@ 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.AnimeHttpSource +import eu.kanade.tachiyomi.lib.amazonextractor.AmazonExtractor import eu.kanade.tachiyomi.lib.burstcloudextractor.BurstCloudExtractor import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor -import eu.kanade.tachiyomi.lib.fastreamextractor.FastreamExtractor import eu.kanade.tachiyomi.lib.filemoonextractor.FilemoonExtractor import eu.kanade.tachiyomi.lib.mp4uploadextractor.Mp4uploadExtractor import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor @@ -28,37 +28,35 @@ import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor import eu.kanade.tachiyomi.lib.youruploadextractor.YourUploadExtractor import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.util.asJsoup -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import okhttp3.HttpUrl.Companion.toHttpUrl +import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking import okhttp3.Request import okhttp3.Response +import org.jsoup.nodes.Element +import org.jsoup.select.Elements import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get -import java.net.URLDecoder class Animefenix : ConfigurableAnimeSource, AnimeHttpSource() { override val name = "AnimeFenix" - override val baseUrl = "https://www3.animefenix.tv" + override val baseUrl = "https://animefenix2.tv" override val lang = "es" - override val supportsLatest = true + override val supportsLatest = false - private val preferences: SharedPreferences by lazy { Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) } + private val preferences: SharedPreferences by lazy { + Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) + } companion object { - private val SERVER_REGEX = """tabsArray\['?\d+'?]\s*=\s*['\"](https[^'\"]+)['\"]""".toRegex() private const val PREF_QUALITY_KEY = "preferred_quality" private const val PREF_QUALITY_DEFAULT = "1080" private val QUALITY_LIST = arrayOf("1080", "720", "480", "360") private const val PREF_SERVER_KEY = "preferred_server" - private const val PREF_SERVER_DEFAULT = "Amazon" + private const val PREF_SERVER_DEFAULT = "Mp4Upload" private val SERVER_LIST = arrayOf( "YourUpload", "Voe", "Mp4Upload", "Doodstream", "Upload", "BurstCloud", "Upstream", "StreamTape", @@ -67,33 +65,45 @@ class Animefenix : ConfigurableAnimeSource, AnimeHttpSource() { ) } - override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/animes?order=likes&page=$page") + override fun animeDetailsParse(response: Response): SAnime { + val document = response.asJsoup() + val animeDetails = SAnime.create().apply { + title = document.selectFirst("h1.text-4xl")?.ownText() ?: "" + status = document.select(".relative .rounded").getStatus() + description = document.selectFirst(".mb-6 p.text-gray-300")?.text() + genre = document.select(".flex-wrap a").joinToString { it.text().trim() } + thumbnail_url = document.selectFirst("#anime_image")?.getImageUrl() + } + return animeDetails + } + + override fun popularAnimeRequest(page: Int) = GET("$baseUrl/directorio/anime?p=$page&estado=2", headers) override fun popularAnimeParse(response: Response): AnimesPage { val document = response.asJsoup() - val elements = document.select("div.container .grid.gap-4 a[href]") - val nextPage = document.select("nav[aria-label=Pagination] span:containsOwn(Next)").any() + val elements = document.select(".grid-animes li article a") + val nextPage = document.select(".right:not(.disabledd)").any() val animeList = elements.map { element -> SAnime.create().apply { - setUrlWithoutDomain(element.selectFirst("a")!!.attr("abs:href")) - title = element.selectFirst("div h3.text-primary")!!.ownText() - thumbnail_url = element.selectFirst("img.object-cover")?.attr("abs:src") + setUrlWithoutDomain(element.attr("abs:href")) + title = element.selectFirst("p:not(.gray)")?.text() ?: "" + thumbnail_url = element.selectFirst(".main-img img")?.getImageUrl() } } return AnimesPage(animeList, nextPage) } - override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/animes?order=added&page=$page") + override fun latestUpdatesParse(response: Response) = throw UnsupportedOperationException() - override fun latestUpdatesParse(response: Response) = popularAnimeParse(response) + override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException() override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request { val params = AnimeFenixFilters.getSearchParameters(filters) return when { - query.isNotBlank() -> GET("$baseUrl/animes?q=$query&page=$page", headers) - params.filter.isNotBlank() -> GET("$baseUrl/animes${params.getQuery()}&page=$page", headers) - else -> GET("$baseUrl/animes?order=likes&page=$page") + query.isNotBlank() -> GET("$baseUrl/directorio/anime?q=$query&p=$page", headers) + params.filter.isNotBlank() -> GET("$baseUrl/directorio/anime${params.getQuery()}&page=$page", headers) + else -> popularAnimeRequest(page) } } @@ -101,115 +111,77 @@ class Animefenix : ConfigurableAnimeSource, AnimeHttpSource() { override fun episodeListParse(response: Response): List<SEpisode> { val document = response.asJsoup() - return document.select("div.container > div > ul > li").map { element -> + return document.select(".divide-y li > a").map { + val title = it.select(".font-semibold").text() SEpisode.create().apply { - name = element.selectFirst("span > span")!!.ownText() - setUrlWithoutDomain(element.selectFirst("a")!!.attr("abs:href")) + name = title + episode_number = title.substringAfter("Episodio").toFloatOrNull() ?: 0F + setUrlWithoutDomain(it.attr("abs:href")) } } } override fun videoListParse(response: Response): List<Video> { val document = response.asJsoup() - val videoList = mutableListOf<Video>() - val serversData = document.selectFirst("script:containsData(var tabsArray)")?.data() ?: throw Exception("No se encontraron servidores") - val servers = SERVER_REGEX.findAll(serversData).map { it.groupValues[1] }.toList() - - servers.parallelForEachBlocking { server -> - val decodedUrl = URLDecoder.decode(server, "UTF-8") - val realUrl = try { - client.newCall(GET(decodedUrl)).execute().asJsoup().selectFirst("script")!! - .data().substringAfter("src=\"").substringBefore("\"") - } catch (e: Exception) { "" } - - try { - serverVideoResolver(realUrl).let { videoList.addAll(it) } - } catch (_: Exception) { } - } - return videoList.filter { it.url.contains("https") || it.url.contains("http") } + val script = document.selectFirst("script:containsData(var tabsArray)") ?: return emptyList() + return script.data().substringAfter("<iframe").split("src='") + .map { it.substringBefore("'").substringAfter("redirect.php?id=").trim() } + .parallelCatchingFlatMapBlocking { url -> + serverVideoResolver(url) + } } + /*-------------------------------- Video extractors ------------------------------------*/ + private val universalExtractor by lazy { UniversalExtractor(client) } + private val voeExtractor by lazy { VoeExtractor(client) } + private val okruExtractor by lazy { OkruExtractor(client) } + private val filemoonExtractor by lazy { FilemoonExtractor(client) } + private val uqloadExtractor by lazy { UqloadExtractor(client) } + private val mp4uploadExtractor by lazy { Mp4uploadExtractor(client) } + private val streamwishExtractor by lazy { StreamWishExtractor(client, headers) } + private val doodExtractor by lazy { DoodExtractor(client) } + private val streamlareExtractor by lazy { StreamlareExtractor(client) } + private val yourUploadExtractor by lazy { YourUploadExtractor(client) } + private val burstcloudExtractor by lazy { BurstCloudExtractor(client) } + private val upstreamExtractor by lazy { UpstreamExtractor(client) } + private val streamTapeExtractor by lazy { StreamTapeExtractor(client) } + private val streamHideVidExtractor by lazy { StreamHideVidExtractor(client, headers) } + private val filelionsExtractor by lazy { StreamWishExtractor(client, headers) } + private val amazonExtractor by lazy { AmazonExtractor(client) } + private fun serverVideoResolver(url: String): List<Video> { - val videoList = mutableListOf<Video>() - val embedUrl = url.lowercase() - try { + return runCatching { when { - embedUrl.contains("voe") -> { - VoeExtractor(client).videosFromUrl(url).also(videoList::addAll) - } - (embedUrl.contains("amazon") || embedUrl.contains("amz")) && !embedUrl.contains("disable") -> { - val video = amazonExtractor(baseUrl + url.substringAfter("..")) - if (video.isNotBlank()) { - if (url.contains("&ext=es")) { - videoList.add(Video(video, "AmazonES", video)) - } else { - videoList.add(Video(video, "Amazon", video)) - } - } - } - embedUrl.contains("ok.ru") || embedUrl.contains("okru") -> { - OkruExtractor(client).videosFromUrl(url).also(videoList::addAll) - } - embedUrl.contains("filemoon") || embedUrl.contains("moonplayer") -> { - val vidHeaders = headers.newBuilder() - .add("Origin", "https://${url.toHttpUrl().host}") - .add("Referer", "https://${url.toHttpUrl().host}/") - .build() - FilemoonExtractor(client).videosFromUrl(url, prefix = "Filemoon:", headers = vidHeaders).also(videoList::addAll) - } - embedUrl.contains("uqload") -> { - UqloadExtractor(client).videosFromUrl(url).also(videoList::addAll) - } - embedUrl.contains("mp4upload") -> { - Mp4uploadExtractor(client).videosFromUrl(url, headers).let { videoList.addAll(it) } - } - embedUrl.contains("wishembed") || embedUrl.contains("embedwish") || embedUrl.contains("streamwish") || embedUrl.contains("strwish") || embedUrl.contains("wish") -> { - val docHeaders = headers.newBuilder() - .add("Origin", "https://streamwish.to") - .add("Referer", "https://streamwish.to/") - .build() - StreamWishExtractor(client, docHeaders).videosFromUrl(url, videoNameGen = { "StreamWish:$it" }).also(videoList::addAll) - } - embedUrl.contains("doodstream") || embedUrl.contains("dood.") -> { - DoodExtractor(client).videoFromUrl(url, "DoodStream")?.let { videoList.add(it) } - } - embedUrl.contains("streamlare") -> { - StreamlareExtractor(client).videosFromUrl(url).let { videoList.addAll(it) } - } - embedUrl.contains("yourupload") || embedUrl.contains("upload") -> { - YourUploadExtractor(client).videoFromUrl(url, headers = headers).let { videoList.addAll(it) } - } - embedUrl.contains("burstcloud") || embedUrl.contains("burst") -> { - BurstCloudExtractor(client).videoFromUrl(url, headers = headers).let { videoList.addAll(it) } - } - embedUrl.contains("fastream") -> { - FastreamExtractor(client, headers).videosFromUrl(url).also(videoList::addAll) - } - embedUrl.contains("upstream") -> { - UpstreamExtractor(client).videosFromUrl(url).let { videoList.addAll(it) } - } - embedUrl.contains("streamtape") || embedUrl.contains("stp") || embedUrl.contains("stape") -> { - StreamTapeExtractor(client).videoFromUrl(url)?.let { videoList.add(it) } - } - embedUrl.contains("ahvsh") || embedUrl.contains("streamhide") -> { - StreamHideVidExtractor(client, headers).videosFromUrl(url).let { videoList.addAll(it) } - } - embedUrl.contains("/stream/fl.php") -> { + arrayOf("voe", "robertordercharacter", "donaldlineelse").any(url) -> voeExtractor.videosFromUrl(url) + arrayOf("amazon", "amz").any(url) -> amazonExtractor.videosFromUrl(url) + arrayOf("ok.ru", "okru").any(url) -> okruExtractor.videosFromUrl(url) + arrayOf("moon").any(url) -> filemoonExtractor.videosFromUrl(url, prefix = "Filemoon:") + arrayOf("uqload").any(url) -> uqloadExtractor.videosFromUrl(url) + arrayOf("mp4upload").any(url) -> mp4uploadExtractor.videosFromUrl(url, headers) + arrayOf("wish").any(url) -> streamwishExtractor.videosFromUrl(url, videoNameGen = { "StreamWish:$it" }) + arrayOf("doodstream", "dood.").any(url) -> doodExtractor.videosFromUrl(url, "DoodStream") + arrayOf("streamlare").any(url) -> streamlareExtractor.videosFromUrl(url) + arrayOf("yourupload", "upload").any(url) -> yourUploadExtractor.videoFromUrl(url, headers = headers) + arrayOf("burstcloud", "burst").any(url) -> burstcloudExtractor.videoFromUrl(url, headers = headers) + arrayOf("upstream").any(url) -> upstreamExtractor.videosFromUrl(url) + arrayOf("streamtape", "stp", "stape").any(url) -> streamTapeExtractor.videosFromUrl(url) + arrayOf("ahvsh", "streamhide").any(url) -> streamHideVidExtractor.videosFromUrl(url) + arrayOf("/stream/fl.php").any(url) -> { val video = url.substringAfter("/stream/fl.php?v=") if (client.newCall(GET(video)).execute().code == 200) { - videoList.add(Video(video, "FireLoad", video)) + listOf(Video(video, "FireLoad", video)) + } else { + emptyList() } } - embedUrl.contains("filelions") || embedUrl.contains("lion") -> { - StreamWishExtractor(client, headers).videosFromUrl(url, videoNameGen = { "FileLions:$it" }).also(videoList::addAll) - } - else -> - UniversalExtractor(client).videosFromUrl(url, headers).let { videoList.addAll(it) } + arrayOf("lion").any(url) -> filelionsExtractor.videosFromUrl(url, videoNameGen = { "FileLions:$it" }) + else -> universalExtractor.videosFromUrl(url, headers) } - } catch (_: Exception) { } - return videoList + }.getOrElse { emptyList() } } + private fun Array<String>.any(url: String): Boolean = this.any { url.contains(it, ignoreCase = true) } + override fun List<Video>.sort(): List<Video> { val quality = preferences.getString(PREF_QUALITY_KEY, PREF_QUALITY_DEFAULT)!! val server = preferences.getString(PREF_SERVER_KEY, PREF_SERVER_DEFAULT)!! @@ -222,56 +194,32 @@ class Animefenix : ConfigurableAnimeSource, AnimeHttpSource() { ).reversed() } - override fun animeDetailsParse(response: Response) = SAnime.create().apply { - val document = response.asJsoup() - with(document.selectFirst("main > div.relative > div.container > div.flex")!!) { - title = selectFirst("h1.font-bold")!!.ownText() - genre = select("div:has(h2:containsOwn(Géneros)) > div.flex > a").joinToString { it.text() } - status = parseStatus(selectFirst("li:has(> span:containsOwn(Estado))")!!.ownText()) - description = select("div:has(h2:containsOwn(Sinopsis)) > p").text() - } - } - - private fun parseStatus(statusString: String): Int { + private fun Elements.getStatus(): Int { return when { - statusString.contains("Emisión") -> SAnime.ONGOING - statusString.contains("Finalizado") -> SAnime.COMPLETED + text().contains("finalizado", true) -> SAnime.COMPLETED + text().contains("emision", true) -> SAnime.ONGOING else -> SAnime.UNKNOWN } } - private fun amazonExtractor(url: String): String { - val document = client.newCall(GET(url)).execute().asJsoup() - val videoURl = document.selectFirst("script:containsData(sources: [)")!!.data() - .substringAfter("[{\"file\":\"") - .substringBefore("\",").replace("\\", "") - - return try { - if (client.newCall(GET(videoURl)).execute().code == 200) videoURl else "" - } catch (e: Exception) { - "" + private fun Element.getImageUrl(): String? { + return when { + isValidUrl("data-src") -> attr("abs:data-src") + isValidUrl("data-lazy-src") -> attr("abs:data-lazy-src") + isValidUrl("srcset") -> attr("abs:srcset").substringBefore(" ") + isValidUrl("src") -> attr("abs:src") + else -> "" } } + private fun Element.isValidUrl(attrName: String): Boolean { + if (!hasAttr(attrName)) return false + return !attr(attrName).contains("data:image/") + } + override fun getFilterList(): AnimeFilterList = AnimeFenixFilters.FILTER_LIST override fun setupPreferenceScreen(screen: PreferenceScreen) { - ListPreference(screen.context).apply { - key = PREF_QUALITY_KEY - title = "Preferred quality" - entries = QUALITY_LIST - entryValues = QUALITY_LIST - setDefaultValue(PREF_QUALITY_DEFAULT) - summary = "%s" - - setOnPreferenceChangeListener { _, newValue -> - val selected = newValue as String - val index = findIndexOfValue(selected) - val entry = entryValues[index] as String - preferences.edit().putString(key, entry).commit() - } - }.also(screen::addPreference) - ListPreference(screen.context).apply { key = PREF_SERVER_KEY title = "Preferred server" @@ -287,21 +235,21 @@ class Animefenix : ConfigurableAnimeSource, AnimeHttpSource() { preferences.edit().putString(key, entry).commit() } }.also(screen::addPreference) - } - suspend inline fun <A> Iterable<A>.parallelForEach(crossinline f: suspend (A) -> Unit) { - coroutineScope { - for (item in this@parallelForEach) { - launch(Dispatchers.IO) { - f(item) - } + ListPreference(screen.context).apply { + key = PREF_QUALITY_KEY + title = "Preferred quality" + entries = QUALITY_LIST + entryValues = QUALITY_LIST + setDefaultValue(PREF_QUALITY_DEFAULT) + summary = "%s" + + setOnPreferenceChangeListener { _, newValue -> + val selected = newValue as String + val index = findIndexOfValue(selected) + val entry = entryValues[index] as String + preferences.edit().putString(key, entry).commit() } - } - } - - inline fun <A> Iterable<A>.parallelForEachBlocking(crossinline f: suspend (A) -> Unit) { - runBlocking { - this@parallelForEachBlocking.parallelForEach(f) - } + }.also(screen::addPreference) } } diff --git a/src/es/animefenix/src/eu/kanade/tachiyomi/animeextension/es/animefenix/extractors/SolidFilesExtractor.kt b/src/es/animefenix/src/eu/kanade/tachiyomi/animeextension/es/animefenix/extractors/SolidFilesExtractor.kt deleted file mode 100644 index a66b611e..00000000 --- a/src/es/animefenix/src/eu/kanade/tachiyomi/animeextension/es/animefenix/extractors/SolidFilesExtractor.kt +++ /dev/null @@ -1,27 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.es.animefenix.extractors - -import eu.kanade.tachiyomi.animesource.model.Video -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.util.asJsoup -import okhttp3.OkHttpClient - -class SolidFilesExtractor(private val client: OkHttpClient) { - fun videosFromUrl(url: String, prefix: String = ""): List<Video> { - val videoList = mutableListOf<Video>() - return try { - val document = client.newCall(GET(url)).execute().asJsoup() - document.select("script").forEach { script -> - if (script.data().contains("\"downloadUrl\":")) { - val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",") - val url = data.replace("\"", "") - val videoUrl = url - val quality = prefix + "SolidFiles" - videoList.add(Video(videoUrl, quality, videoUrl)) - } - } - videoList - } catch (e: Exception) { - videoList - } - } -} diff --git a/src/es/cinecalidad/res/mipmap-hdpi/ic_launcher_adaptive_back.png b/src/es/cinecalidad/res/mipmap-hdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index a31f7028..00000000 Binary files a/src/es/cinecalidad/res/mipmap-hdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/es/cinecalidad/res/mipmap-hdpi/ic_launcher_adaptive_fore.png b/src/es/cinecalidad/res/mipmap-hdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 3ce663b6..00000000 Binary files a/src/es/cinecalidad/res/mipmap-hdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/es/cinecalidad/res/mipmap-mdpi/ic_launcher_adaptive_back.png b/src/es/cinecalidad/res/mipmap-mdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 21d5008b..00000000 Binary files a/src/es/cinecalidad/res/mipmap-mdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/es/cinecalidad/res/mipmap-mdpi/ic_launcher_adaptive_fore.png b/src/es/cinecalidad/res/mipmap-mdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 49b2a43e..00000000 Binary files a/src/es/cinecalidad/res/mipmap-mdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/es/cinecalidad/res/mipmap-xhdpi/ic_launcher_adaptive_back.png b/src/es/cinecalidad/res/mipmap-xhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 776ce9a3..00000000 Binary files a/src/es/cinecalidad/res/mipmap-xhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/es/cinecalidad/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png b/src/es/cinecalidad/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index e18190fe..00000000 Binary files a/src/es/cinecalidad/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/es/cinecalidad/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png b/src/es/cinecalidad/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 9de1ea8f..00000000 Binary files a/src/es/cinecalidad/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/es/cinecalidad/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png b/src/es/cinecalidad/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index b65fd053..00000000 Binary files a/src/es/cinecalidad/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/es/cinecalidad/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png b/src/es/cinecalidad/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 81b316ba..00000000 Binary files a/src/es/cinecalidad/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/es/cinecalidad/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png b/src/es/cinecalidad/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 13dcfcb4..00000000 Binary files a/src/es/cinecalidad/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/es/cineplus123/res/mipmap-hdpi/ic_launcher_adaptive_back.png b/src/es/cineplus123/res/mipmap-hdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 3f50df92..00000000 Binary files a/src/es/cineplus123/res/mipmap-hdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/es/cineplus123/res/mipmap-hdpi/ic_launcher_adaptive_fore.png b/src/es/cineplus123/res/mipmap-hdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index ca607167..00000000 Binary files a/src/es/cineplus123/res/mipmap-hdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/es/cineplus123/res/mipmap-mdpi/ic_launcher_adaptive_back.png b/src/es/cineplus123/res/mipmap-mdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 5a270b5a..00000000 Binary files a/src/es/cineplus123/res/mipmap-mdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/es/cineplus123/res/mipmap-mdpi/ic_launcher_adaptive_fore.png b/src/es/cineplus123/res/mipmap-mdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 8efd6289..00000000 Binary files a/src/es/cineplus123/res/mipmap-mdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/es/cineplus123/res/mipmap-xhdpi/ic_launcher_adaptive_back.png b/src/es/cineplus123/res/mipmap-xhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 36d4e2d1..00000000 Binary files a/src/es/cineplus123/res/mipmap-xhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/es/cineplus123/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png b/src/es/cineplus123/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 5091966c..00000000 Binary files a/src/es/cineplus123/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/es/cineplus123/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png b/src/es/cineplus123/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index aacf215b..00000000 Binary files a/src/es/cineplus123/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/es/cineplus123/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png b/src/es/cineplus123/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 636d2123..00000000 Binary files a/src/es/cineplus123/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/es/cineplus123/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png b/src/es/cineplus123/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 50e3aba3..00000000 Binary files a/src/es/cineplus123/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/es/cineplus123/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png b/src/es/cineplus123/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 923c8960..00000000 Binary files a/src/es/cineplus123/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/es/latanime/res/web_hi_res_512.png b/src/es/latanime/res/web_hi_res_512.png deleted file mode 100644 index c67e40f7..00000000 Binary files a/src/es/latanime/res/web_hi_res_512.png and /dev/null differ diff --git a/src/es/otakuverso/build.gradle b/src/es/otakuverso/build.gradle new file mode 100644 index 00000000..830bd251 --- /dev/null +++ b/src/es/otakuverso/build.gradle @@ -0,0 +1,27 @@ +ext { + extName = 'Otakuverso' + extClass = '.Otakuverso' + extVersionCode = 1 +} + +apply from: "$rootDir/common.gradle" + +dependencies { + implementation(project(':lib:mp4upload-extractor')) + implementation(project(':lib:streamtape-extractor')) + implementation(project(':lib:yourupload-extractor')) + implementation(project(':lib:uqload-extractor')) + implementation(project(':lib:okru-extractor')) + implementation(project(':lib:burstcloud-extractor')) + implementation(project(':lib:streamwish-extractor')) + implementation(project(':lib:filemoon-extractor')) + implementation(project(':lib:voe-extractor')) + implementation(project(':lib:streamlare-extractor')) + implementation(project(':lib:dood-extractor')) + implementation(project(':lib:upstream-extractor')) + implementation(project(':lib:streamhidevid-extractor')) + implementation(project(':lib:universal-extractor')) + implementation(project(':lib:sendvid-extractor')) + implementation(project(':lib:playlist-utils')) + implementation(libs.jsunpacker) +} \ No newline at end of file diff --git a/src/es/otakuverso/res/mipmap-hdpi/ic_launcher.png b/src/es/otakuverso/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..cf3d0126 Binary files /dev/null and b/src/es/otakuverso/res/mipmap-hdpi/ic_launcher.png differ diff --git a/src/es/otakuverso/res/mipmap-mdpi/ic_launcher.png b/src/es/otakuverso/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..cf3d0126 Binary files /dev/null and b/src/es/otakuverso/res/mipmap-mdpi/ic_launcher.png differ diff --git a/src/es/otakuverso/res/mipmap-xhdpi/ic_launcher.png b/src/es/otakuverso/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..cf3d0126 Binary files /dev/null and b/src/es/otakuverso/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/src/es/otakuverso/res/mipmap-xxhdpi/ic_launcher.png b/src/es/otakuverso/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..cf3d0126 Binary files /dev/null and b/src/es/otakuverso/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src/es/otakuverso/res/mipmap-xxxhdpi/ic_launcher.png b/src/es/otakuverso/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..cf3d0126 Binary files /dev/null and b/src/es/otakuverso/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src/es/otakuverso/src/eu/kanade/tachiyomi/animeextension/es/otakuverso/Otakuverso.kt b/src/es/otakuverso/src/eu/kanade/tachiyomi/animeextension/es/otakuverso/Otakuverso.kt new file mode 100644 index 00000000..025b34a2 --- /dev/null +++ b/src/es/otakuverso/src/eu/kanade/tachiyomi/animeextension/es/otakuverso/Otakuverso.kt @@ -0,0 +1,339 @@ +package eu.kanade.tachiyomi.animeextension.es.otakuverso + +import android.app.Application +import android.content.SharedPreferences +import android.util.Log +import androidx.preference.ListPreference +import androidx.preference.PreferenceScreen +import eu.kanade.tachiyomi.animeextension.es.otakuverso.extractors.UnpackerExtractor +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.AnimeHttpSource +import eu.kanade.tachiyomi.lib.burstcloudextractor.BurstCloudExtractor +import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor +import eu.kanade.tachiyomi.lib.filemoonextractor.FilemoonExtractor +import eu.kanade.tachiyomi.lib.mp4uploadextractor.Mp4uploadExtractor +import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor +import eu.kanade.tachiyomi.lib.sendvidextractor.SendvidExtractor +import eu.kanade.tachiyomi.lib.streamhidevidextractor.StreamHideVidExtractor +import eu.kanade.tachiyomi.lib.streamlareextractor.StreamlareExtractor +import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor +import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor +import eu.kanade.tachiyomi.lib.universalextractor.UniversalExtractor +import eu.kanade.tachiyomi.lib.upstreamextractor.UpstreamExtractor +import eu.kanade.tachiyomi.lib.uqloadextractor.UqloadExtractor +import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor +import eu.kanade.tachiyomi.lib.youruploadextractor.YourUploadExtractor +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.network.POST +import eu.kanade.tachiyomi.network.await +import eu.kanade.tachiyomi.util.asJsoup +import eu.kanade.tachiyomi.util.parallelCatchingFlatMap +import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking +import okhttp3.FormBody +import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.Request +import okhttp3.Response +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get + +class Otakuverso : ConfigurableAnimeSource, AnimeHttpSource() { + + override val name = "Otakuverso" + + override val baseUrl = "https://otakuverso.net" + + override val lang = "es" + + override val supportsLatest = false + + private val preferences: SharedPreferences by lazy { + Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) + } + + companion object { + private const val PREF_QUALITY_KEY = "preferred_quality" + private const val PREF_QUALITY_DEFAULT = "1080" + private val QUALITY_LIST = arrayOf("1080", "720", "480", "360") + + private const val PREF_SERVER_KEY = "preferred_server" + private const val PREF_SERVER_DEFAULT = "YourUpload" + private val SERVER_LIST = arrayOf( + "YourUpload", "Voe", "Mp4Upload", "Doodstream", + "Upload", "BurstCloud", "Upstream", "StreamTape", + "Fastream", "Filemoon", "StreamWish", "Okru", + "Amazon", "AmazonES", "Fireload", "FileLions", + ) + } + + override fun animeDetailsParse(response: Response): SAnime { + val document = response.asJsoup() + return SAnime.create().apply { + title = document.selectFirst("#back_data_perfil .inn-text h1")?.text().orEmpty() + description = document.selectFirst("#back_data_perfil .inn-text p.font14")?.ownText() + genre = document.select(".pre .text-deco-none.font-GDSherpa-Regular").joinToString { it.text() } + status = with(document.select("#back_data_perfil .inn-text .btn-anime-info")) { + when { + text().contains("finalizado", true) -> SAnime.COMPLETED + text().contains("emision", true) || text().contains("emitiéndose", true) -> SAnime.ONGOING + else -> SAnime.UNKNOWN + } + } + document.select(".col-xl-12 .font-GDSherpa-Regular") + .map { it.select(".text-white").text() to it.select(".lila-color").text() } + .forEach { (title, content) -> + when { + title.contains("Creador(a)", true) -> author = content + title.contains("Director(a)", true) -> artist = content + } + } + } + } + + private fun getToken(): Pair<String, String> { + try { + val request = client.newCall(GET("$baseUrl/animes")).execute() + val document = request.asJsoup() + val token = document.selectFirst("[name=\"_token\"]")?.attr("value").orEmpty() + val xsrfToken = client.cookieJar.loadForRequest("$baseUrl/animes".toHttpUrl()) + .firstOrNull { it.name == "XSRF-TOKEN" }?.let { "${it.name}=${it.value}" } + .orEmpty() + return token to xsrfToken + } catch (e: Exception) { + Log.i("bruh err", e.toString()) + return "" to "" + } + } + + override fun popularAnimeRequest(page: Int): Request { + val (token, xsrfToken) = getToken() + val data = FormBody.Builder() + .add("_token", token) + .add("page", "$page") + .add("search_genero", "0") + .add("search_anno", "0") + .add("search_tipo", "0") + .add("search_orden", "0") + .add("search_estado", "0") + .add("Cookie", xsrfToken) + .build() + + return POST("$baseUrl/animes", body = data, headers = headers) + } + + override fun popularAnimeParse(response: Response): AnimesPage { + val document = response.asJsoup() + val elements = document.select(".row [data-original-title]") + val nextPage = document.select(".pagination a[rel=next]").any() + val animeList = elements.map { element -> + SAnime.create().apply { + title = element.selectFirst(".font-GDSherpa-Bold")?.text().orEmpty() + thumbnail_url = element.selectFirst("img")?.getImageUrl() + setUrlWithoutDomain(element.attr("abs:href")) + } + } + return AnimesPage(animeList, nextPage) + } + + override fun latestUpdatesParse(response: Response) = throw UnsupportedOperationException() + + override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException() + + override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request { + val params = OtakuversoFilters.getSearchParameters(filters) + return when { + query.isNotBlank() -> GET("$baseUrl/buscador?q=$query&page=$page", headers) + params.isFiltered() -> searchRequest(params, page) + else -> popularAnimeRequest(page) + } + } + + private fun searchRequest(params: OtakuversoFilters.FilterSearchParams, page: Int): Request { + val formBody = params.body + val (token, xsrfToken) = getToken() + val data = FormBody.Builder().apply { + for (i in 0 until formBody.size) { + add(formBody.name(i), formBody.value(i)) + } + add("page", "$page") + add("_token", token) + add("Cookie", xsrfToken) + }.build() + + return POST("$baseUrl/animes", body = data, headers = headers) + } + + override fun searchAnimeParse(response: Response) = popularAnimeParse(response) + + private fun parseEpisodeList(document: Document): List<SEpisode> { + return document.select(".pl-lg-4 .container-fluid .row .col-6.text-center").map { + val episode = it.select(".font-GDSherpa-Bold a") + val episodeNumber = episode.text().substringAfter("Episodio").trim().toFloat() + SEpisode.create().apply { + name = episode.text() + episode_number = episodeNumber + scanlator = it.select(".font14 .bog").text().trim() + setUrlWithoutDomain(episode.attr("abs:href")) + } + } + } + + override fun episodeListParse(response: Response): List<SEpisode> { + val document = response.asJsoup() + val pageable = document.select(".dropdown-menu").any() + if (pageable) { + return document.select(".dropdown-menu a") + .map { it.attr("abs:href") } + .parallelCatchingFlatMapBlocking { + val page = client.newCall(GET(it)).execute().asJsoup() + parseEpisodeList(page) + } + } + return parseEpisodeList(document) + } + + override suspend fun getVideoList(episode: SEpisode): List<Video> { + val response = client.newCall(videoListRequest(episode)).await() + val document = response.asJsoup() + return document.select("#ssel option") + .map { it.attr("value") } + .parallelCatchingFlatMap { id -> + val url = getRealLink(id) + serverVideoResolver(url) + } + } + + private fun getRealLink(id: String): String { + val serverResponse = client.newCall(GET("$baseUrl/play-video?id=$id")).execute() + val serverLink = """"url":"([^"]+)""".toRegex() + .find(serverResponse.body.string()) + ?.groupValues?.get(1) + ?.replace("\\/", "/") + .orEmpty() + return when { + serverLink.startsWith("http") -> serverLink + serverLink.startsWith("//") -> "https:$serverLink" + else -> "" + } + } + + override fun getFilterList(): AnimeFilterList = OtakuversoFilters.FILTER_LIST + + /*-------------------------------- Video extractors ------------------------------------*/ + private val universalExtractor by lazy { UniversalExtractor(client) } + private val voeExtractor by lazy { VoeExtractor(client) } + private val okruExtractor by lazy { OkruExtractor(client) } + private val filemoonExtractor by lazy { FilemoonExtractor(client) } + private val uqloadExtractor by lazy { UqloadExtractor(client) } + private val mp4uploadExtractor by lazy { Mp4uploadExtractor(client) } + private val streamwishExtractor by lazy { StreamWishExtractor(client, headers) } + private val doodExtractor by lazy { DoodExtractor(client) } + private val streamlareExtractor by lazy { StreamlareExtractor(client) } + private val yourUploadExtractor by lazy { YourUploadExtractor(client) } + private val burstcloudExtractor by lazy { BurstCloudExtractor(client) } + private val upstreamExtractor by lazy { UpstreamExtractor(client) } + private val streamTapeExtractor by lazy { StreamTapeExtractor(client) } + private val streamHideVidExtractor by lazy { StreamHideVidExtractor(client, headers) } + private val filelionsExtractor by lazy { StreamWishExtractor(client, headers) } + private val sendvidExtractor by lazy { SendvidExtractor(client, headers) } + private val luluExtractor by lazy { UnpackerExtractor(client, headers) } + + private fun serverVideoResolver(url: String): List<Video> { + return when { + arrayOf("voe", "robertordercharacter", "donaldlineelse").any(url) -> voeExtractor.videosFromUrl(url) + arrayOf("ok.ru", "okru").any(url) -> okruExtractor.videosFromUrl(url) + arrayOf("moon").any(url) -> filemoonExtractor.videosFromUrl(url, prefix = "Filemoon:") + arrayOf("uqload").any(url) -> uqloadExtractor.videosFromUrl(url) + arrayOf("mp4upload").any(url) -> mp4uploadExtractor.videosFromUrl(url, headers) + arrayOf("wish").any(url) -> streamwishExtractor.videosFromUrl(url, videoNameGen = { "StreamWish:$it" }) + arrayOf("doodstream", "dood.").any(url) -> doodExtractor.videosFromUrl(url, "DoodStream") + arrayOf("streamlare").any(url) -> streamlareExtractor.videosFromUrl(url) + arrayOf("yourupload", "upload").any(url) -> yourUploadExtractor.videoFromUrl(url, headers = headers) + arrayOf("burstcloud", "burst").any(url) -> burstcloudExtractor.videoFromUrl(url, headers = headers) + arrayOf("upstream").any(url) -> upstreamExtractor.videosFromUrl(url) + arrayOf("streamtape", "stp", "stape").any(url) -> streamTapeExtractor.videosFromUrl(url) + arrayOf("ahvsh", "streamhide").any(url) -> streamHideVidExtractor.videosFromUrl(url) + arrayOf("/stream/fl.php").any(url) -> { + val video = url.substringAfter("/stream/fl.php?v=") + if (client.newCall(GET(video)).execute().code == 200) { + listOf(Video(video, "FireLoad", video)) + } else { + emptyList() + } + } + arrayOf("lion").any(url) -> filelionsExtractor.videosFromUrl(url, videoNameGen = { "FileLions:$it" }) + arrayOf("sendvid").any(url) -> sendvidExtractor.videosFromUrl(url) + arrayOf("lulu").any(url) -> luluExtractor.videosFromUrl(url) + else -> universalExtractor.videosFromUrl(url, headers) + } + } + + override fun List<Video>.sort(): List<Video> { + val quality = preferences.getString(PREF_QUALITY_KEY, PREF_QUALITY_DEFAULT)!! + val server = preferences.getString(PREF_SERVER_KEY, PREF_SERVER_DEFAULT)!! + return this.sortedWith( + compareBy( + { it.quality.contains(server, true) }, + { it.quality.contains(quality) }, + { Regex("""(\d+)p""").find(it.quality)?.groupValues?.get(1)?.toIntOrNull() ?: 0 }, + ), + ).reversed() + } + + private fun Element.getImageUrl(): String? { + return when { + isValidUrl("data-src") -> attr("abs:data-src") + isValidUrl("data-lazy-src") -> attr("abs:data-lazy-src") + isValidUrl("srcset") -> attr("abs:srcset").substringBefore(" ") + isValidUrl("src") -> attr("abs:src") + else -> "" + } + } + + private fun Element.isValidUrl(attrName: String): Boolean { + if (!hasAttr(attrName)) return false + return !attr(attrName).contains("data:image/") + } + + private fun Array<String>.any(url: String): Boolean = this.any { url.contains(it, ignoreCase = true) } + + override fun setupPreferenceScreen(screen: PreferenceScreen) { + ListPreference(screen.context).apply { + key = PREF_SERVER_KEY + title = "Preferred server" + entries = SERVER_LIST + entryValues = SERVER_LIST + setDefaultValue(PREF_SERVER_DEFAULT) + summary = "%s" + + setOnPreferenceChangeListener { _, newValue -> + val selected = newValue as String + val index = findIndexOfValue(selected) + val entry = entryValues[index] as String + preferences.edit().putString(key, entry).commit() + } + }.also(screen::addPreference) + + ListPreference(screen.context).apply { + key = PREF_QUALITY_KEY + title = "Preferred quality" + entries = QUALITY_LIST + entryValues = QUALITY_LIST + setDefaultValue(PREF_QUALITY_DEFAULT) + summary = "%s" + + setOnPreferenceChangeListener { _, newValue -> + val selected = newValue as String + val index = findIndexOfValue(selected) + val entry = entryValues[index] as String + preferences.edit().putString(key, entry).commit() + } + }.also(screen::addPreference) + } +} diff --git a/src/es/otakuverso/src/eu/kanade/tachiyomi/animeextension/es/otakuverso/OtakuversoFilters.kt b/src/es/otakuverso/src/eu/kanade/tachiyomi/animeextension/es/otakuverso/OtakuversoFilters.kt new file mode 100644 index 00000000..073c4488 --- /dev/null +++ b/src/es/otakuverso/src/eu/kanade/tachiyomi/animeextension/es/otakuverso/OtakuversoFilters.kt @@ -0,0 +1,143 @@ +package eu.kanade.tachiyomi.animeextension.es.otakuverso + +import eu.kanade.tachiyomi.animesource.model.AnimeFilter +import eu.kanade.tachiyomi.animesource.model.AnimeFilterList +import okhttp3.FormBody +import java.util.Calendar + +object OtakuversoFilters { + open class QueryPartFilter(displayName: String, val vals: Array<Pair<String, String>>) : AnimeFilter.Select<String>( + displayName, + vals.map { it.first }.toTypedArray(), + ) + + private inline fun <reified R> AnimeFilterList.getFirst(): R { + return this.filterIsInstance<R>().first() + } + + data class FilterSearchParams( + val body: FormBody, + ) { + fun isFiltered(): Boolean { + return (0 until body.size).any { body.value(it) != "0" } + } + } + + internal fun getSearchParameters(filters: AnimeFilterList): FilterSearchParams { + if (filters.isEmpty()) return FilterSearchParams(FormBody.Builder().build()) + + val formBuilder = FormBody.Builder() + filters.getFirst<GenresFilter>().let { filter -> + formBuilder.add("search_genero", filter.vals[filter.state].second) + } + filters.getFirst<TypesFilter>().let { filter -> + formBuilder.add("search_tipo", filter.vals[filter.state].second) + } + filters.getFirst<StatusFilter>().let { filter -> + formBuilder.add("search_estado", filter.vals[filter.state].second) + } + filters.getFirst<YearsFilter>().let { filter -> + formBuilder.add("search_anno", filter.vals[filter.state].second) + } + filters.getFirst<SortFilter>().let { filter -> + formBuilder.add("search_orden", filter.vals[filter.state].second) + } + return FilterSearchParams(formBuilder.build()) + } + + val FILTER_LIST get() = AnimeFilterList( + AnimeFilter.Header("La busqueda por texto ignora el filtro"), + GenresFilter(), + TypesFilter(), + StatusFilter(), + YearsFilter(), + SortFilter(), + ) + + class GenresFilter : QueryPartFilter("Género", OtakuversoFiltersData.GENRES) + + class TypesFilter : QueryPartFilter("Tipo", OtakuversoFiltersData.TYPES) + + class StatusFilter : QueryPartFilter("Estado", OtakuversoFiltersData.STATUS) + + class YearsFilter : QueryPartFilter("Año", OtakuversoFiltersData.YEARS) + + class SortFilter : QueryPartFilter("Orden", OtakuversoFiltersData.SORT) + + private object OtakuversoFiltersData { + val GENRES = arrayOf( + Pair("Todos", "0"), + Pair("Aventura", "jR"), + Pair("Misterio", "k5"), + Pair("Shounen", "l5"), + Pair("Acción", "mO"), + Pair("Fantasía", "nR"), + Pair("Demonios", "oj"), + Pair("Histórico", "p2"), + Pair("Sobrenatural", "q2"), + Pair("Artes Marciales", "rE"), + Pair("Comedia", "vm"), + Pair("Superpoderes", "wR"), + Pair("Magia", "x9"), + Pair("Deportes", "y7"), + Pair("Drama", "zY"), + Pair("Escolares", "AO"), + Pair("Ciencia Ficción", "BX"), + Pair("Horror", "Dx"), + Pair("Psicológico", "Ev"), + Pair("Juegos", "G7"), + Pair("Romance", "J2"), + Pair("Seinen", "KR"), + Pair("Recuentos de la vida", "Lw"), + Pair("Mecha", "MA"), + Pair("Shoujo", "N6"), + Pair("Policía", "Op"), + Pair("Suspenso", "Pw"), + Pair("Música", "Ql"), + Pair("Parodia", "Rq"), + Pair("Ecchi", "VM"), + Pair("Terror", "WJ"), + Pair("Militar", "XW"), + Pair("Vampiros", "YK"), + Pair("Samurai", "ZJ"), + Pair("Infantil", "1R"), + Pair("Harem", "2K"), + Pair("Escuela", "3M"), + Pair("Carreras", "41"), + Pair("Lucha", "5B"), + Pair("Gore", "6n"), + Pair("Latino", "7j"), + Pair("Fútbol", "8m"), + Pair("Espacial", "9x"), + Pair("Josei", "0v"), + Pair("Comida", "gJY"), + Pair("School", "jRR"), + Pair("Yuri", "kR5"), + Pair("Yaoi", "lY5"), + Pair("Shounen Ai", "mZO"), + ) + + val TYPES = arrayOf( + Pair("Todos", "0"), + Pair("Serie", "1"), + Pair("Película", "2"), + Pair("Especial", "3"), + Pair("OVA", "4"), + ) + + val STATUS = arrayOf( + Pair("Todos", "0"), + Pair("Emitiendose", "1"), + Pair("Próximo", "2"), + Pair("Finalizado", "3"), + ) + + val YEARS = arrayOf(Pair("Todos", "0")) + (1980..Calendar.getInstance().get(Calendar.YEAR)).map { Pair("$it", "$it") }.reversed().toTypedArray() + + val SORT = arrayOf( + Pair("Default", "0"), + Pair("Ascendente", "1"), + Pair("Descendente", "2"), + ) + } +} diff --git a/src/es/otakuverso/src/eu/kanade/tachiyomi/animeextension/es/otakuverso/extractors/UnpackerExtractor.kt b/src/es/otakuverso/src/eu/kanade/tachiyomi/animeextension/es/otakuverso/extractors/UnpackerExtractor.kt new file mode 100644 index 00000000..5555e497 --- /dev/null +++ b/src/es/otakuverso/src/eu/kanade/tachiyomi/animeextension/es/otakuverso/extractors/UnpackerExtractor.kt @@ -0,0 +1,31 @@ +package eu.kanade.tachiyomi.animeextension.es.otakuverso.extractors + +import dev.datlag.jsunpacker.JsUnpacker +import eu.kanade.tachiyomi.animesource.model.Video +import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.util.asJsoup +import okhttp3.Headers +import okhttp3.OkHttpClient + +class UnpackerExtractor(private val client: OkHttpClient, private val headers: Headers) { + private val playlistUtils by lazy { PlaylistUtils(client, headers) } + + fun videosFromUrl(url: String): List<Video> { + val doc = client.newCall(GET(url, headers)).execute() + .asJsoup() + + val script = doc.selectFirst("script:containsData(eval)") + ?.data() + ?.let(JsUnpacker::unpackAndCombine) + ?: return emptyList() + + val playlistUrl = script.substringAfter("file:\"").substringBefore('"') + + return playlistUtils.extractFromHls( + playlistUrl, + referer = playlistUrl, + videoNameGen = { "Lulu:$it" }, + ) + } +} diff --git a/src/fr/animesama/res/web_hi_res_512.png b/src/fr/animesama/res/web_hi_res_512.png deleted file mode 100644 index ebaf597e..00000000 Binary files a/src/fr/animesama/res/web_hi_res_512.png and /dev/null differ diff --git a/src/fr/empirestreaming/res/mipmap-hdpi/ic_launcher_adaptive_back.png b/src/fr/empirestreaming/res/mipmap-hdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 8dc560dd..00000000 Binary files a/src/fr/empirestreaming/res/mipmap-hdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/fr/empirestreaming/res/mipmap-hdpi/ic_launcher_adaptive_fore.png b/src/fr/empirestreaming/res/mipmap-hdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 6b3ec01b..00000000 Binary files a/src/fr/empirestreaming/res/mipmap-hdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/fr/empirestreaming/res/mipmap-mdpi/ic_launcher_adaptive_back.png b/src/fr/empirestreaming/res/mipmap-mdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index f8feb6e5..00000000 Binary files a/src/fr/empirestreaming/res/mipmap-mdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/fr/empirestreaming/res/mipmap-mdpi/ic_launcher_adaptive_fore.png b/src/fr/empirestreaming/res/mipmap-mdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 4af4a29a..00000000 Binary files a/src/fr/empirestreaming/res/mipmap-mdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/fr/empirestreaming/res/mipmap-xhdpi/ic_launcher_adaptive_back.png b/src/fr/empirestreaming/res/mipmap-xhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 1b560124..00000000 Binary files a/src/fr/empirestreaming/res/mipmap-xhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/fr/empirestreaming/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png b/src/fr/empirestreaming/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 93321f34..00000000 Binary files a/src/fr/empirestreaming/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/fr/empirestreaming/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png b/src/fr/empirestreaming/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index 369383ac..00000000 Binary files a/src/fr/empirestreaming/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/fr/empirestreaming/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png b/src/fr/empirestreaming/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 06a62196..00000000 Binary files a/src/fr/empirestreaming/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/fr/empirestreaming/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png b/src/fr/empirestreaming/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png deleted file mode 100644 index de26e98f..00000000 Binary files a/src/fr/empirestreaming/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png and /dev/null differ diff --git a/src/fr/empirestreaming/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png b/src/fr/empirestreaming/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png deleted file mode 100644 index 7cad125f..00000000 Binary files a/src/fr/empirestreaming/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png and /dev/null differ diff --git a/src/fr/frenchanime/res/web_hi_res_512.png b/src/fr/frenchanime/res/web_hi_res_512.png deleted file mode 100644 index 0089d6ef..00000000 Binary files a/src/fr/frenchanime/res/web_hi_res_512.png and /dev/null differ diff --git a/src/fr/jetanime/res/web_hi_res_512.png b/src/fr/jetanime/res/web_hi_res_512.png deleted file mode 100644 index b219ab1b..00000000 Binary files a/src/fr/jetanime/res/web_hi_res_512.png and /dev/null differ diff --git a/src/fr/mykdrama/res/web_hi_res_512.png b/src/fr/mykdrama/res/web_hi_res_512.png deleted file mode 100644 index 579972f1..00000000 Binary files a/src/fr/mykdrama/res/web_hi_res_512.png and /dev/null differ diff --git a/src/fr/otakufr/res/web_hi_res_512.png b/src/fr/otakufr/res/web_hi_res_512.png deleted file mode 100644 index d992179a..00000000 Binary files a/src/fr/otakufr/res/web_hi_res_512.png and /dev/null differ diff --git a/src/fr/wiflix/res/web_hi_res_512.png b/src/fr/wiflix/res/web_hi_res_512.png deleted file mode 100644 index 1aacf919..00000000 Binary files a/src/fr/wiflix/res/web_hi_res_512.png and /dev/null differ diff --git a/src/hi/animesaga/build.gradle b/src/hi/animesaga/build.gradle index 1da6278d..bcfeeaa0 100644 --- a/src/hi/animesaga/build.gradle +++ b/src/hi/animesaga/build.gradle @@ -3,7 +3,7 @@ ext { extClass = '.AniSAGA' themePkg = 'dooplay' baseUrl = 'https://www.anisaga.org' - overrideVersionCode = 15 + overrideVersionCode = 16 isNsfw = false } diff --git a/src/hi/animesaga/src/eu/kanade/tachiyomi/animeextension/hi/animesaga/AniSAGA.kt b/src/hi/animesaga/src/eu/kanade/tachiyomi/animeextension/hi/animesaga/AniSAGA.kt index c9e15245..6c077aed 100644 --- a/src/hi/animesaga/src/eu/kanade/tachiyomi/animeextension/hi/animesaga/AniSAGA.kt +++ b/src/hi/animesaga/src/eu/kanade/tachiyomi/animeextension/hi/animesaga/AniSAGA.kt @@ -14,7 +14,7 @@ class AniSAGA : DooPlay( "AniSAGA", "https://www.anisaga.org", ) { - private val videoHost = "https://cdn.anisaga.org" + private val videoHost = "https://plyrxcdn.site/" // ============================== Popular =============================== override fun popularAnimeSelector() = "div.top-imdb-list > div.top-imdb-item" diff --git a/src/hi/yomovies/res/web_hi_res_512.png b/src/hi/yomovies/res/web_hi_res_512.png deleted file mode 100644 index d8cce433..00000000 Binary files a/src/hi/yomovies/res/web_hi_res_512.png and /dev/null differ diff --git a/src/id/kuramanime/res/web_hi_res_512.png b/src/id/kuramanime/res/web_hi_res_512.png deleted file mode 100644 index 8f1628be..00000000 Binary files a/src/id/kuramanime/res/web_hi_res_512.png and /dev/null differ diff --git a/src/id/kuronime/res/web_hi_res_512.png b/src/id/kuronime/res/web_hi_res_512.png deleted file mode 100644 index a469dc18..00000000 Binary files a/src/id/kuronime/res/web_hi_res_512.png and /dev/null differ diff --git a/src/id/minioppai/res/web_hi_res_512.png b/src/id/minioppai/res/web_hi_res_512.png deleted file mode 100644 index 06ca48d3..00000000 Binary files a/src/id/minioppai/res/web_hi_res_512.png and /dev/null differ diff --git a/src/id/neonime/res/web_hi_res_128.png b/src/id/neonime/res/web_hi_res_128.png deleted file mode 100644 index 170b0247..00000000 Binary files a/src/id/neonime/res/web_hi_res_128.png and /dev/null differ diff --git a/src/id/oploverz/res/web_hi_res_512.png b/src/id/oploverz/res/web_hi_res_512.png deleted file mode 100644 index f6e7473a..00000000 Binary files a/src/id/oploverz/res/web_hi_res_512.png and /dev/null differ diff --git a/src/id/otakudesu/res/web_hi_res_512.png b/src/id/otakudesu/res/web_hi_res_512.png deleted file mode 100644 index fe706242..00000000 Binary files a/src/id/otakudesu/res/web_hi_res_512.png and /dev/null differ diff --git a/src/id/samehadaku/res/web_hi_res_512.png b/src/id/samehadaku/res/web_hi_res_512.png deleted file mode 100644 index b8a3e6a8..00000000 Binary files a/src/id/samehadaku/res/web_hi_res_512.png and /dev/null differ diff --git a/src/it/animeunity/res/web_hi_res_512.png b/src/it/animeunity/res/web_hi_res_512.png deleted file mode 100644 index 005a0666..00000000 Binary files a/src/it/animeunity/res/web_hi_res_512.png and /dev/null differ diff --git a/src/it/animeworld/res/play_store_512.png b/src/it/animeworld/res/play_store_512.png deleted file mode 100644 index 470fb01b..00000000 Binary files a/src/it/animeworld/res/play_store_512.png and /dev/null differ diff --git a/src/it/streamingcommunity/res/web_hi_res_512.png b/src/it/streamingcommunity/res/web_hi_res_512.png deleted file mode 100644 index bb51a179..00000000 Binary files a/src/it/streamingcommunity/res/web_hi_res_512.png and /dev/null differ diff --git a/src/it/toonitalia/res/web_hi_res_512.png b/src/it/toonitalia/res/web_hi_res_512.png deleted file mode 100644 index bb20f995..00000000 Binary files a/src/it/toonitalia/res/web_hi_res_512.png and /dev/null differ diff --git a/src/it/vvvvid/res/web_hi_res_512.png b/src/it/vvvvid/res/web_hi_res_512.png deleted file mode 100644 index 2b0c990f..00000000 Binary files a/src/it/vvvvid/res/web_hi_res_512.png and /dev/null differ diff --git a/src/ko/aniweek/res/web_hi_res_512.png b/src/ko/aniweek/res/web_hi_res_512.png deleted file mode 100644 index c4fb09a4..00000000 Binary files a/src/ko/aniweek/res/web_hi_res_512.png and /dev/null differ diff --git a/src/pl/desuonline/res/web_hi_res_512.png b/src/pl/desuonline/res/web_hi_res_512.png deleted file mode 100644 index 641868dd..00000000 Binary files a/src/pl/desuonline/res/web_hi_res_512.png and /dev/null differ diff --git a/src/pl/wbijam/res/web_hi_res_512.png b/src/pl/wbijam/res/web_hi_res_512.png deleted file mode 100644 index 6da98071..00000000 Binary files a/src/pl/wbijam/res/web_hi_res_512.png and /dev/null differ diff --git a/src/pt/anidong/AndroidManifest.xml b/src/pt/anidong/AndroidManifest.xml deleted file mode 100644 index 2970f0d2..00000000 --- a/src/pt/anidong/AndroidManifest.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<manifest xmlns:android="http://schemas.android.com/apk/res/android"> - - <application> - <activity - android:name=".pt.anidong.AniDongUrlActivity" - android:excludeFromRecents="true" - android:exported="true" - android:theme="@android:style/Theme.NoDisplay"> - <intent-filter> - <action android:name="android.intent.action.VIEW" /> - - <category android:name="android.intent.category.DEFAULT" /> - <category android:name="android.intent.category.BROWSABLE" /> - - <data - android:host="anidong.net" - android:pathPattern="/anime/..*" - android:scheme="https" /> - </intent-filter> - </activity> - </application> -</manifest> diff --git a/src/pt/anidong/build.gradle b/src/pt/anidong/build.gradle deleted file mode 100644 index 57fb4d05..00000000 --- a/src/pt/anidong/build.gradle +++ /dev/null @@ -1,7 +0,0 @@ -ext { - extName = 'AniDong' - extClass = '.AniDong' - extVersionCode = 2 -} - -apply from: "$rootDir/common.gradle" diff --git a/src/pt/anidong/res/mipmap-hdpi/ic_launcher.png b/src/pt/anidong/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 50be877d..00000000 Binary files a/src/pt/anidong/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/anidong/res/mipmap-mdpi/ic_launcher.png b/src/pt/anidong/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index b23fff3a..00000000 Binary files a/src/pt/anidong/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/anidong/res/mipmap-xhdpi/ic_launcher.png b/src/pt/anidong/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 71ddb7b8..00000000 Binary files a/src/pt/anidong/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/anidong/res/mipmap-xxhdpi/ic_launcher.png b/src/pt/anidong/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 720b33eb..00000000 Binary files a/src/pt/anidong/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/anidong/res/mipmap-xxxhdpi/ic_launcher.png b/src/pt/anidong/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index a0cb538f..00000000 Binary files a/src/pt/anidong/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/anidong/src/eu/kanade/tachiyomi/animeextension/pt/anidong/AniDong.kt b/src/pt/anidong/src/eu/kanade/tachiyomi/animeextension/pt/anidong/AniDong.kt deleted file mode 100644 index ea22f1d3..00000000 --- a/src/pt/anidong/src/eu/kanade/tachiyomi/animeextension/pt/anidong/AniDong.kt +++ /dev/null @@ -1,264 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.pt.anidong - -import eu.kanade.tachiyomi.animeextension.pt.anidong.dto.EpisodeDto -import eu.kanade.tachiyomi.animeextension.pt.anidong.dto.EpisodeListDto -import eu.kanade.tachiyomi.animeextension.pt.anidong.dto.SearchResultDto -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.network.GET -import eu.kanade.tachiyomi.network.POST -import eu.kanade.tachiyomi.network.awaitSuccess -import eu.kanade.tachiyomi.util.asJsoup -import kotlinx.serialization.json.Json -import okhttp3.FormBody -import okhttp3.Request -import okhttp3.Response -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import uy.kohesive.injekt.injectLazy - -class AniDong : ParsedAnimeHttpSource() { - - override val name = "AniDong" - - override val baseUrl = "https://anidong.net" - - override val lang = "pt-BR" - - override val supportsLatest = true - - private val json: Json by injectLazy() - - private val apiHeaders by lazy { - headersBuilder() // sets user-agent - .add("Referer", baseUrl) - .add("x-requested-with", "XMLHttpRequest") - .build() - } - - // ============================== Popular =============================== - override fun popularAnimeRequest(page: Int) = GET(baseUrl) - - override fun popularAnimeSelector() = "article.top10_animes_item > a" - - override fun popularAnimeFromElement(element: Element) = SAnime.create().apply { - setUrlWithoutDomain(element.attr("href")) - title = element.attr("title") - thumbnail_url = element.selectFirst("img")?.attr("src") - } - - override fun popularAnimeNextPageSelector() = null - - // =============================== Latest =============================== - override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/lancamentos/page/$page/") - - override fun latestUpdatesSelector() = "article.main_content_article > a" - - override fun latestUpdatesFromElement(element: Element) = popularAnimeFromElement(element) - - override fun latestUpdatesNextPageSelector() = "div.paginacao > a.next" - - // =============================== Search =============================== - 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/anime/$id")) - .awaitSuccess() - .use(::searchAnimeByIdParse) - } else { - super.getSearchAnime(page, query, filters) - } - } - - private fun searchAnimeByIdParse(response: Response): AnimesPage { - val details = animeDetailsParse(response.asJsoup()).apply { - setUrlWithoutDomain(response.request.url.toString()) - initialized = true - } - - return AnimesPage(listOf(details), false) - } - - override fun getFilterList() = AniDongFilters.FILTER_LIST - - private val nonce by lazy { - client.newCall(GET("$baseUrl/?js_global=1&ver=6.2.2")).execute() - .body.string() - .substringAfter("search_nonce") - .substringAfter("'") - .substringBefore("'") - } - - override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request { - val params = AniDongFilters.getSearchParameters(filters) - - val body = FormBody.Builder() - .add("letra", "") - .add("action", "show_animes_ajax") - .add("nome", query) - .add("status", params.status) - .add("formato", params.format) - .add("search_nonce", nonce) - .add("paged", page.toString()) - .apply { - params.genres.forEach { add("generos[]", it) } - }.build() - - return POST("$baseUrl/wp-admin/admin-ajax.php", headers = apiHeaders, body = body) - } - - override fun searchAnimeParse(response: Response): AnimesPage { - val searchData: SearchResultDto = response.body.string() - .takeIf { it.trim() != "402" } - ?.let(json::decodeFromString) - ?: return AnimesPage(emptyList(), false) - - val animes = searchData.animes.map { - SAnime.create().apply { - setUrlWithoutDomain(it.url) - title = it.title - thumbnail_url = it.thumbnail_url - } - } - - val hasNextPage = searchData.pages > 1 && searchData.animes.size == 10 - - return AnimesPage(animes, hasNextPage) - } - - override fun searchAnimeSelector(): String { - throw UnsupportedOperationException() - } - - override fun searchAnimeFromElement(element: Element): SAnime { - throw UnsupportedOperationException() - } - - override fun searchAnimeNextPageSelector(): String? { - throw UnsupportedOperationException() - } - - // =========================== Anime Details ============================ - override fun animeDetailsParse(document: Document) = SAnime.create().apply { - val doc = getRealDoc(document) - val infos = doc.selectFirst("div.anime_infos")!! - - setUrlWithoutDomain(doc.location()) - title = infos.selectFirst("div > h3")!!.ownText() - thumbnail_url = infos.selectFirst("img")?.attr("src") - genre = infos.select("div[itemprop=genre] a").eachText().joinToString() - artist = infos.selectFirst("div[itemprop=productionCompany]")?.text() - - status = doc.selectFirst("div:contains(Status) span")?.text().let { - when { - it == null -> SAnime.UNKNOWN - it == "Completo" -> SAnime.COMPLETED - it.contains("Lançamento") -> SAnime.ONGOING - else -> SAnime.UNKNOWN - } - } - - description = buildString { - infos.selectFirst("div.anime_name + div.anime_info")?.text()?.also { - append("Nomes alternativos: $it\n") - } - - doc.selectFirst("div[itemprop=description]")?.text()?.also { - append("\n$it") - } - } - } - - // ============================== Episodes ============================== - override fun episodeListSelector(): String { - throw UnsupportedOperationException() - } - - override fun episodeFromElement(element: Element): SEpisode { - throw UnsupportedOperationException() - } - - override fun episodeListParse(response: Response): List<SEpisode> { - val doc = getRealDoc(response.asJsoup()) - - val id = doc.selectFirst("link[rel=shortlink]")!!.attr("href").substringAfter("=") - val body = FormBody.Builder() - .add("action", "show_videos") - .add("anime_id", id) - .build() - - val res = client.newCall(POST("$baseUrl/api", apiHeaders, body)).execute() - .body.string() - val data = json.decodeFromString<EpisodeListDto>(res) - - return buildList { - data.episodes.forEach { add(episodeFromObject(it, "Episódio")) } - data.movies.forEach { add(episodeFromObject(it, "Filme")) } - data.ovas.forEach { add(episodeFromObject(it, "OVA")) } - sortByDescending { it.episode_number } - } - } - - private fun episodeFromObject(episode: EpisodeDto, prefix: String) = SEpisode.create().apply { - setUrlWithoutDomain(episode.epi_url) - episode_number = episode.epi_num.toFloatOrNull() ?: 0F - name = "$prefix ${episode.epi_num}" - } - - // ============================ Video Links ============================= - override fun videoListParse(response: Response): List<Video> { - val doc = response.asJsoup() - return doc.select("div.player_option").flatMap { - val url = it.attr("data-playerlink") - val playerName = it.text().trim() - videosFromUrl(url, playerName) - } - } - - private fun videosFromUrl(url: String, playerName: String): List<Video> { - val scriptData = client.newCall(GET(url, apiHeaders)).execute() - .asJsoup() - .selectFirst("script:containsData(sources)") - ?.data() ?: return emptyList() - - return scriptData.substringAfter("sources: [").substringBefore("]") - .split("{") - .drop(1) - .map { - val videoUrl = it.substringAfter("file: \"").substringBefore('"') - val label = it.substringAfter("label: \"", "Unknown").substringBefore('"') - val quality = "$playerName - $label" - Video(videoUrl, quality, videoUrl, headers = apiHeaders) - } - } - - override fun videoFromElement(element: Element): Video { - throw UnsupportedOperationException() - } - - override fun videoListSelector(): String { - throw UnsupportedOperationException() - } - - override fun videoUrlParse(document: Document): String { - throw UnsupportedOperationException() - } - - // ============================= Utilities ============================== - private fun getRealDoc(document: Document): Document { - if (!document.location().contains("/video/")) return document - - return document.selectFirst(".episodioControleItem:has(i.ri-grid-fill)")?.let { - client.newCall(GET(it.attr("href"), headers)).execute() - .asJsoup() - } ?: document - } - - companion object { - const val PREFIX_SEARCH = "id:" - } -} diff --git a/src/pt/anidong/src/eu/kanade/tachiyomi/animeextension/pt/anidong/AniDongFilters.kt b/src/pt/anidong/src/eu/kanade/tachiyomi/animeextension/pt/anidong/AniDongFilters.kt deleted file mode 100644 index 28f949e8..00000000 --- a/src/pt/anidong/src/eu/kanade/tachiyomi/animeextension/pt/anidong/AniDongFilters.kt +++ /dev/null @@ -1,124 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.pt.anidong - -import eu.kanade.tachiyomi.animesource.model.AnimeFilter -import eu.kanade.tachiyomi.animesource.model.AnimeFilterList - -object AniDongFilters { - open class QueryPartFilter( - displayName: String, - val vals: Array<Pair<String, String>>, - ) : AnimeFilter.Select<String>( - displayName, - vals.map { it.first }.toTypedArray(), - ) { - fun toQueryPart() = vals[state].second - } - - open class CheckBoxFilterList(name: String, val pairs: Array<Pair<String, String>>) : - AnimeFilter.Group<AnimeFilter.CheckBox>(name, pairs.map { CheckBoxVal(it.first, false) }) - - private class CheckBoxVal(name: String, state: Boolean = false) : AnimeFilter.CheckBox(name, state) - - private inline fun <reified R> AnimeFilterList.asQueryPart(): String { - return (getFirst<R>() as QueryPartFilter).toQueryPart() - } - - private inline fun <reified R> AnimeFilterList.getFirst(): R { - return first { it is R } as R - } - - private inline fun <reified R> AnimeFilterList.parseCheckbox( - options: Array<Pair<String, String>>, - ): List<String> { - return (getFirst<R>() as CheckBoxFilterList).state - .asSequence() - .filter { it.state } - .map { checkbox -> options.find { it.first == checkbox.name }!!.second } - .filter(String::isNotBlank) - .toList() - } - - class StatusFilter : QueryPartFilter("Status", AniDongFiltersData.STATUS_LIST) - class FormatFilter : QueryPartFilter("Formato", AniDongFiltersData.FORMAT_LIST) - - class GenresFilter : CheckBoxFilterList("Gêneros", AniDongFiltersData.GENRES_LIST) - - val FILTER_LIST get() = AnimeFilterList( - StatusFilter(), - FormatFilter(), - GenresFilter(), - ) - - data class FilterSearchParams( - val status: String = "", - val format: String = "", - val genres: List<String> = emptyList(), - ) - - internal fun getSearchParameters(filters: AnimeFilterList): FilterSearchParams { - if (filters.isEmpty()) return FilterSearchParams() - - return FilterSearchParams( - filters.asQueryPart<StatusFilter>(), - filters.asQueryPart<FormatFilter>(), - filters.parseCheckbox<GenresFilter>(AniDongFiltersData.GENRES_LIST), - ) - } - - private object AniDongFiltersData { - private val SELECT = Pair("<Selecione>", "") - - val STATUS_LIST = arrayOf( - SELECT, - Pair("Lançamento", "Lançamento"), - Pair("Completo", "Completo"), - ) - - val FORMAT_LIST = arrayOf( - SELECT, - Pair("Donghua", "Anime"), - Pair("Filme", "Filme"), - ) - - val GENRES_LIST = arrayOf( - Pair("Artes Marciais", "9"), - Pair("Aventura", "6"), - Pair("Ação", "2"), - Pair("Boys Love", "43"), - Pair("Comédia", "15"), - Pair("Corrida", "94"), - Pair("Cultivo", "12"), - Pair("Demônios", "18"), - Pair("Detetive", "24"), - Pair("Drama", "16"), - Pair("Escolar", "77"), - Pair("Espaço", "54"), - Pair("Esporte", "95"), - Pair("Fantasia", "7"), - Pair("Guerra", "26"), - Pair("Harém", "17"), - Pair("Histórico", "8"), - Pair("Horror", "44"), - Pair("Isekai", "72"), - Pair("Jogo", "25"), - Pair("Mecha", "40"), - Pair("Militar", "21"), - Pair("Mistério", "3"), - Pair("Mitolgia", "96"), - Pair("Mitologia", "19"), - Pair("O Melhor Donghua", "91"), - Pair("Polícia", "57"), - Pair("Política", "63"), - Pair("Psicológico", "33"), - Pair("Reencarnação", "30"), - Pair("Romance", "11"), - Pair("Sci-Fi", "39"), - Pair("Slice of Life", "84"), - Pair("Sobrenatural", "4"), - Pair("Super Poder", "67"), - Pair("Suspense", "32"), - Pair("Tragédia", "58"), - Pair("Vampiro", "82"), - ) - } -} diff --git a/src/pt/anidong/src/eu/kanade/tachiyomi/animeextension/pt/anidong/AniDongUrlActivity.kt b/src/pt/anidong/src/eu/kanade/tachiyomi/animeextension/pt/anidong/AniDongUrlActivity.kt deleted file mode 100644 index 883d9a50..00000000 --- a/src/pt/anidong/src/eu/kanade/tachiyomi/animeextension/pt/anidong/AniDongUrlActivity.kt +++ /dev/null @@ -1,41 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.pt.anidong - -import android.app.Activity -import android.content.ActivityNotFoundException -import android.content.Intent -import android.os.Bundle -import android.util.Log -import kotlin.system.exitProcess - -/** - * Springboard that accepts https://anidong.net/anime/<item> intents - * and redirects them to the main Aniyomi process. - */ -class AniDongUrlActivity : Activity() { - - private val tag = javaClass.simpleName - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - val pathSegments = intent?.data?.pathSegments - if (pathSegments != null && pathSegments.size > 1) { - val item = pathSegments[1] - val mainIntent = Intent().apply { - action = "eu.kanade.tachiyomi.ANIMESEARCH" - putExtra("query", "${AniDong.PREFIX_SEARCH}$item") - putExtra("filter", packageName) - } - - try { - startActivity(mainIntent) - } catch (e: ActivityNotFoundException) { - Log.e(tag, e.toString()) - } - } else { - Log.e(tag, "could not parse uri from intent $intent") - } - - finish() - exitProcess(0) - } -} diff --git a/src/pt/anidong/src/eu/kanade/tachiyomi/animeextension/pt/anidong/dto/AniDongDto.kt b/src/pt/anidong/src/eu/kanade/tachiyomi/animeextension/pt/anidong/dto/AniDongDto.kt deleted file mode 100644 index 4945071c..00000000 --- a/src/pt/anidong/src/eu/kanade/tachiyomi/animeextension/pt/anidong/dto/AniDongDto.kt +++ /dev/null @@ -1,53 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.pt.anidong.dto - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.builtins.ListSerializer -import kotlinx.serialization.json.JsonArray -import kotlinx.serialization.json.JsonElement -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.JsonTransformingSerializer - -@Serializable -data class SearchResultDto( - val animes: List<AnimeDto>, - @SerialName("total_pages") - val pages: Int, -) - -@Serializable -data class AnimeDto( - @SerialName("anime_capa") - val thumbnail_url: String, - @SerialName("anime_permalink") - val url: String, - @SerialName("anime_title") - val title: String, -) - -@Serializable -data class EpisodeListDto( - @Serializable(with = EpisodeListSerializer::class) - @SerialName("episodios") - val episodes: List<EpisodeDto>, - @Serializable(with = EpisodeListSerializer::class) - @SerialName("filmes") - val movies: List<EpisodeDto>, - @Serializable(with = EpisodeListSerializer::class) - val ovas: List<EpisodeDto>, -) - -@Serializable -data class EpisodeDto( - val epi_num: String, - val epi_url: String, -) - -object EpisodeListSerializer : - JsonTransformingSerializer<List<EpisodeDto>>(ListSerializer(EpisodeDto.serializer())) { - override fun transformDeserialize(element: JsonElement): JsonElement = - when (element) { - is JsonObject -> JsonArray(element.values.toList()) - else -> JsonArray(emptyList()) - } -} diff --git a/src/pt/animesgratis/build.gradle b/src/pt/animesgratis/build.gradle index a9f7edf9..8e0c3b14 100644 --- a/src/pt/animesgratis/build.gradle +++ b/src/pt/animesgratis/build.gradle @@ -3,7 +3,7 @@ ext { extClass = '.Q1N' themePkg = 'dooplay' baseUrl = 'https://q1n.net' - overrideVersionCode = 17 + overrideVersionCode = 18 } apply from: "$rootDir/common.gradle" diff --git a/src/pt/animesgratis/src/eu/kanade/tachiyomi/animeextension/pt/animesgratis/Q1N.kt b/src/pt/animesgratis/src/eu/kanade/tachiyomi/animeextension/pt/animesgratis/Q1N.kt index ef9a0bb1..03e410bc 100644 --- a/src/pt/animesgratis/src/eu/kanade/tachiyomi/animeextension/pt/animesgratis/Q1N.kt +++ b/src/pt/animesgratis/src/eu/kanade/tachiyomi/animeextension/pt/animesgratis/Q1N.kt @@ -129,6 +129,7 @@ class Q1N : DooPlay( "mixdrop" in name -> mixDropExtractor.videoFromUrl(url) "streamtape" in name -> streamTapeExtractor.videosFromUrl(url) "noa" in name -> noaExtractor.videosFromUrl(url) + "mdplayer" in name -> noaExtractor.videosFromUrl(url, "MDPLAYER") "/player/" in url -> bloggerExtractor.videosFromUrl(url, headers) else -> emptyList() } diff --git a/src/pt/animesgratis/src/eu/kanade/tachiyomi/animeextension/pt/animesgratis/extractors/NoaExtractor.kt b/src/pt/animesgratis/src/eu/kanade/tachiyomi/animeextension/pt/animesgratis/extractors/NoaExtractor.kt index 5bb5d42c..9755a9a1 100644 --- a/src/pt/animesgratis/src/eu/kanade/tachiyomi/animeextension/pt/animesgratis/extractors/NoaExtractor.kt +++ b/src/pt/animesgratis/src/eu/kanade/tachiyomi/animeextension/pt/animesgratis/extractors/NoaExtractor.kt @@ -6,7 +6,7 @@ import okhttp3.Headers import okhttp3.OkHttpClient class NoaExtractor(private val client: OkHttpClient, private val headers: Headers) { - fun videosFromUrl(url: String): List<Video> { + fun videosFromUrl(url: String, name: String = "NOA"): List<Video> { val body = client.newCall(GET(url)).execute() .body.string() @@ -16,7 +16,7 @@ class NoaExtractor(private val client: OkHttpClient, private val headers: Header .substringAfter(":\"") .substringBefore('"') .replace("\\", "") - listOf(Video(videoUrl, "NOA", videoUrl, headers)) + listOf(Video(videoUrl, name, videoUrl, headers)) } "sources:" in body -> { @@ -31,7 +31,7 @@ class NoaExtractor(private val client: OkHttpClient, private val headers: Header .substringAfter(":\"") .substringBefore('"') .replace("\\", "") - Video(videoUrl, "NOA - $label", videoUrl, headers) + Video(videoUrl, "$name - $label", videoUrl, headers) } } diff --git a/src/pt/animesgratis/src/eu/kanade/tachiyomi/animeextension/pt/animesgratis/extractors/RuplayExtractor.kt b/src/pt/animesgratis/src/eu/kanade/tachiyomi/animeextension/pt/animesgratis/extractors/RuplayExtractor.kt index 0f6e4a73..aa2bcc52 100644 --- a/src/pt/animesgratis/src/eu/kanade/tachiyomi/animeextension/pt/animesgratis/extractors/RuplayExtractor.kt +++ b/src/pt/animesgratis/src/eu/kanade/tachiyomi/animeextension/pt/animesgratis/extractors/RuplayExtractor.kt @@ -15,7 +15,7 @@ class RuplayExtractor(private val client: OkHttpClient) { .split(",") .map { val videoUrl = it.substringAfter("]") - val quality = it.substringAfter("[").substringBefore("]") + val quality = it.substringAfter("[", "").substringBefore("]").ifEmpty { "Default" } val headers = Headers.headersOf("Referer", videoUrl) Video(videoUrl, "Ruplay - $quality", videoUrl, headers = headers) } diff --git a/src/pt/anitube/build.gradle b/src/pt/anitube/build.gradle index d20560a0..9f22f339 100644 --- a/src/pt/anitube/build.gradle +++ b/src/pt/anitube/build.gradle @@ -1,7 +1,7 @@ ext { extName = 'Anitube' extClass = '.Anitube' - extVersionCode = 23 + extVersionCode = 24 } apply from: "$rootDir/common.gradle" diff --git a/src/pt/anitube/res/web_hi_res_512.png b/src/pt/anitube/res/web_hi_res_512.png deleted file mode 100644 index a1f94f75..00000000 Binary files a/src/pt/anitube/res/web_hi_res_512.png and /dev/null differ diff --git a/src/pt/anitube/src/eu/kanade/tachiyomi/animeextension/pt/anitube/extractors/AnitubeExtractor.kt b/src/pt/anitube/src/eu/kanade/tachiyomi/animeextension/pt/anitube/extractors/AnitubeExtractor.kt index ddf1dcb4..1736832d 100644 --- a/src/pt/anitube/src/eu/kanade/tachiyomi/animeextension/pt/anitube/extractors/AnitubeExtractor.kt +++ b/src/pt/anitube/src/eu/kanade/tachiyomi/animeextension/pt/anitube/extractors/AnitubeExtractor.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.animeextension.pt.anitube.extractors import android.content.SharedPreferences +import android.util.Base64 import android.util.Log import eu.kanade.tachiyomi.animesource.model.Video import eu.kanade.tachiyomi.network.GET @@ -14,6 +15,9 @@ import okhttp3.OkHttpClient import okhttp3.Request import org.jsoup.nodes.Document import java.net.ProtocolException +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Locale class AnitubeExtractor( private val headers: Headers, @@ -132,32 +136,86 @@ class AnitubeExtractor( return "https://widgets.outbrain.com/outbrain.js" } - private fun getAuthCode(serverUrl: String, thumbUrl: String, link: String): String { - var authCode = preferences.getString(PREF_AUTHCODE_KEY, "")!! + private fun getAuthCode(serverUrl: String, thumbUrl: String, link: String): String? { + try { + var authCode = preferences.getString(PREF_AUTHCODE_KEY, "")!! - if (authCode.isNotBlank()) { - Log.d(tag, "AuthCode found in preferences") + if (authCode.isNotBlank()) { + Log.d(tag, "AuthCode found in preferences") - val response = checkVideoExists("${serverUrl}$authCode") + val authArgs = Base64.decode(authCode.substringAfter("="), Base64.DEFAULT).let(::String) + val url = "$serverUrl?$authArgs".toHttpUrl() - if (response.exists || response.code == 500) { - Log.d(tag, "AuthCode is OK") + val serverTime = + SimpleDateFormat("M/d/yyyy h:m:s a", Locale.ENGLISH).parse( + url.queryParameter("server_time") ?: "", + ) + + val calendar = Calendar.getInstance() + serverTime?.let { calendar.setTime(it) } + + url.queryParameter("validminutes")?.toInt() + ?.let { calendar.add(Calendar.MINUTE, it) } + + if (Calendar.getInstance() < calendar) { + Log.d(tag, "AuthCode is OK") + return authCode + } + Log.d(tag, "AuthCode is invalid") + } + + Log.d(tag, "Fetching new authCode") + + val adsUrl = getAdsUrl(serverUrl, thumbUrl, link, headers) + + val adsContent = client.newCall(GET(adsUrl)).execute().body.string() + + val body = FormBody.Builder() + .add("category", "client") + .add("type", "premium") + .add("ad", adsContent) + .build() + + val newHeaders = headers.newBuilder() + .set("Referer", "https://${SITE_URL.toHttpUrl().host}/") + .add("Accept", "*/*") + .add("Cache-Control", "no-cache") + .add("Pragma", "no-cache") + .add("Connection", "keep-alive") + .add("Sec-Fetch-Dest", "empty") + .add("Sec-Fetch-Mode", "cors") + .add("Sec-Fetch-Site", "same-site") + .build() + + authCode = + client.newCall(POST(ADS_URL, headers = newHeaders, body = body)) + .execute() + .body.string() + .substringAfter("\"publicidade\"") + .substringAfter('"') + .substringBefore('"') + + if (authCode.startsWith("?wmsAuthSign=")) { + Log.d(tag, "Auth code fetched successfully") + preferences.edit().putString(PREF_AUTHCODE_KEY, authCode).commit() return authCode } - Log.d(tag, "AuthCode is invalid") + + Log.e( + tag, + "Failed to fetch \"publicidade\" code, the current response: $authCode", + ) + } catch (e: Exception) { + Log.e(tag, e.toString()) } - Log.d(tag, "Fetching new authCode") + preferences.edit().putString(PREF_AUTHCODE_KEY, "").commit() - val adsUrl = getAdsUrl(serverUrl, thumbUrl, link, headers) + return null + } - val adsContent = client.newCall(GET(adsUrl)).execute().body.string() - - val body = FormBody.Builder() - .add("category", "client") - .add("type", "premium") - .add("ad", adsContent) - .build() + private fun getVideoToken(videoUrl: String, authCode: String?): String { + val token = authCode ?: "undefined" val newHeaders = headers.newBuilder() .set("Referer", "https://${SITE_URL.toHttpUrl().host}/") @@ -170,27 +228,10 @@ class AnitubeExtractor( .add("Sec-Fetch-Site", "same-site") .build() - val publicidade = - client.newCall(POST(ADS_URL, headers = newHeaders, body = body)) - .execute() - .body.string() - .substringAfter("\"publicidade\"") - .substringAfter('"') - .substringBefore('"') - - if (publicidade.isBlank()) { - Log.e( - tag, - "Failed to fetch \"publicidade\" code, the current response: $publicidade", - ) - - throw Exception("Por favor, abra o vídeo uma vez no navegador para liberar o IP") - } - - authCode = + val videoToken = client.newCall( GET( - "$ADS_URL?token=$publicidade", + "$ADS_URL?token=$token&url=$videoUrl", headers = newHeaders, ), ) @@ -200,25 +241,25 @@ class AnitubeExtractor( .substringAfter('"') .substringBefore('"') - if (authCode.startsWith("?")) { - Log.d(tag, "Auth code fetched successfully") - preferences.edit().putString(PREF_AUTHCODE_KEY, authCode).commit() - } else { - Log.e( - tag, - "Failed to fetch auth code, the current response: $authCode", - ) + if (videoToken.startsWith("?")) { + Log.d(tag, "Video token fetched successfully") + return videoToken } - return authCode + Log.e( + tag, + "Failed to fetch video token, the current response: $videoToken", + ) + + return "" } fun getVideoList(doc: Document): List<Video> { + Log.d(tag, "Starting to fetch video list") + val hasFHD = doc.selectFirst("div.abaItem:contains(FULLHD)") != null val serverUrl = doc.selectFirst("meta[itemprop=contentURL]")!! .attr("content") - .replace("cdn1", "cdn3") - .replace("cdn80", "cdn8") val thumbUrl = doc.selectFirst("meta[itemprop=thumbnailUrl]")!! .attr("content") val type = serverUrl.split("/").get(3) @@ -231,6 +272,8 @@ class AnitubeExtractor( } } + listOf("appfullhd") + Log.d(tag, "Found ${paths.size} videos") + val firstLink = doc.selectFirst("div.video_container > a, div.playerContainer > a")!!.attr("href") @@ -240,16 +283,35 @@ class AnitubeExtractor( .mapIndexed { index, quality -> object { var path = paths[index] - var url = serverUrl.replace(type, path) + authCode + var url = serverUrl.replace(type, path) var quality = "$quality - Anitube" } } .parallelCatchingFlatMapBlocking { - if (!checkVideoExists(it.url).exists) { - Log.d(tag, "Video not exists: ${it.url.substringBefore("?")}") - return@parallelCatchingFlatMapBlocking emptyList() + if (!authCode.isNullOrBlank() && checkVideoExists(it.url + authCode).exists) { + return@parallelCatchingFlatMapBlocking listOf( + Video( + it.url + authCode, + it.quality, + it.url + authCode, + headers = headers, + ), + ) } - listOf(Video(it.url, it.quality, it.url, headers = headers)) + val videoToken = getVideoToken(it.url, authCode) + if (videoToken.isNotBlank() && checkVideoExists(it.url + videoToken).exists) { + return@parallelCatchingFlatMapBlocking listOf( + Video( + it.url + videoToken, + it.quality, + it.url + videoToken, + headers = headers, + ), + ) + } + + Log.d(tag, "Video not exists: ${it.url.substringBefore("?")}") + return@parallelCatchingFlatMapBlocking emptyList() } .reversed() } diff --git a/src/pt/flixei/AndroidManifest.xml b/src/pt/flixei/AndroidManifest.xml deleted file mode 100644 index 6fa0bad2..00000000 --- a/src/pt/flixei/AndroidManifest.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<manifest xmlns:android="http://schemas.android.com/apk/res/android"> - - <application> - <activity - android:name=".pt.flixei.FlixeiUrlActivity" - android:excludeFromRecents="true" - android:exported="true" - android:theme="@android:style/Theme.NoDisplay"> - <intent-filter> - <action android:name="android.intent.action.VIEW" /> - - <category android:name="android.intent.category.DEFAULT" /> - <category android:name="android.intent.category.BROWSABLE" /> - - <data - android:host="flixei.com" - android:pathPattern="/assistir/..*/..*" - android:scheme="https" /> - </intent-filter> - </activity> - </application> -</manifest> diff --git a/src/pt/flixei/build.gradle b/src/pt/flixei/build.gradle deleted file mode 100644 index efc6facf..00000000 --- a/src/pt/flixei/build.gradle +++ /dev/null @@ -1,12 +0,0 @@ -ext { - extName = 'Flixei' - extClass = '.Flixei' - extVersionCode = 8 -} - -apply from: "$rootDir/common.gradle" - -dependencies { - implementation(project(":lib:streamtape-extractor")) - implementation(project(":lib:mixdrop-extractor")) -} diff --git a/src/pt/flixei/res/mipmap-hdpi/ic_launcher.png b/src/pt/flixei/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 61d07595..00000000 Binary files a/src/pt/flixei/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/flixei/res/mipmap-mdpi/ic_launcher.png b/src/pt/flixei/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 8b2f31da..00000000 Binary files a/src/pt/flixei/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/flixei/res/mipmap-xhdpi/ic_launcher.png b/src/pt/flixei/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 58738047..00000000 Binary files a/src/pt/flixei/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/flixei/res/mipmap-xxhdpi/ic_launcher.png b/src/pt/flixei/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 0dee2e43..00000000 Binary files a/src/pt/flixei/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/flixei/res/mipmap-xxxhdpi/ic_launcher.png b/src/pt/flixei/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 678679b5..00000000 Binary files a/src/pt/flixei/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/flixei/src/eu/kanade/tachiyomi/animeextension/pt/flixei/Flixei.kt b/src/pt/flixei/src/eu/kanade/tachiyomi/animeextension/pt/flixei/Flixei.kt deleted file mode 100644 index 1aad72bc..00000000 --- a/src/pt/flixei/src/eu/kanade/tachiyomi/animeextension/pt/flixei/Flixei.kt +++ /dev/null @@ -1,346 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.pt.flixei - -import android.app.Application -import androidx.preference.ListPreference -import androidx.preference.PreferenceScreen -import eu.kanade.tachiyomi.animeextension.pt.flixei.dto.AnimeDto -import eu.kanade.tachiyomi.animeextension.pt.flixei.dto.ApiResultsDto -import eu.kanade.tachiyomi.animeextension.pt.flixei.dto.EpisodeDto -import eu.kanade.tachiyomi.animeextension.pt.flixei.dto.PlayersDto -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.mixdropextractor.MixDropExtractor -import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.network.POST -import eu.kanade.tachiyomi.network.awaitSuccess -import eu.kanade.tachiyomi.util.asJsoup -import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking -import eu.kanade.tachiyomi.util.parseAs -import kotlinx.serialization.json.Json -import okhttp3.MediaType.Companion.toMediaType -import okhttp3.Request -import okhttp3.RequestBody.Companion.toRequestBody -import okhttp3.Response -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get -import uy.kohesive.injekt.injectLazy - -class Flixei : ConfigurableAnimeSource, ParsedAnimeHttpSource() { - - override val name = "Flixei" - - override val baseUrl = "https://flixei.com" - - override val lang = "pt-BR" - - override val supportsLatest = true - - private val json: Json by injectLazy() - - private val preferences by lazy { - Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) - } - - // ============================== Popular =============================== - override fun popularAnimeRequest(page: Int): Request { - val body = "slider=3".toFormBody() - return POST("$baseUrl/includes/ajax/home.php", body = body) - } - - override fun popularAnimeParse(response: Response): AnimesPage { - val results = response.parseAs<ApiResultsDto<AnimeDto>>() - val animes = results.items.values.map(::parseAnimeFromObject) - return AnimesPage(animes, false) - } - - private fun parseAnimeFromObject(anime: AnimeDto) = SAnime.create().apply { - title = anime.title - setUrlWithoutDomain("/assistir/filme/${anime.url}/online/gratis") - thumbnail_url = "$baseUrl/content/movies/posterPt/185/${anime.id}.webp" - } - - override fun popularAnimeFromElement(element: Element): SAnime { - throw UnsupportedOperationException() - } - - override fun popularAnimeNextPageSelector(): String? { - throw UnsupportedOperationException() - } - - override fun popularAnimeSelector(): String { - throw UnsupportedOperationException() - } - - // =============================== Latest =============================== - override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/filmes/estreia/$page") - - override fun latestUpdatesSelector() = "div.generalMoviesList > a.gPoster" - - override fun latestUpdatesFromElement(element: Element) = SAnime.create().apply { - title = element.selectFirst("div.i span")!!.text() - thumbnail_url = element.selectFirst("img")?.attr("src") - setUrlWithoutDomain(element.attr("abs:href")) - } - - override fun latestUpdatesNextPageSelector() = "div.paginationSystem a.next" - - // =============================== Search =============================== - override suspend fun getSearchAnime(page: Int, query: String, filters: AnimeFilterList): AnimesPage { - return if (query.startsWith(PREFIX_SEARCH)) { // URL intent handler - val path = query.removePrefix(PREFIX_SEARCH) - client.newCall(GET("$baseUrl/assistir/$path/online/gratis")) - .awaitSuccess() - .use(::searchAnimeByPathParse) - } else { - super.getSearchAnime(page, query, filters) - } - } - - private fun searchAnimeByPathParse(response: Response): AnimesPage { - val details = animeDetailsParse(response.asJsoup()).apply { - setUrlWithoutDomain(response.request.url.toString()) - initialized = true - } - - return AnimesPage(listOf(details), false) - } - - override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request { - return GET("$baseUrl/pesquisar/$query") - } - - override fun searchAnimeSelector() = latestUpdatesSelector() - - override fun searchAnimeFromElement(element: Element) = latestUpdatesFromElement(element) - - override fun searchAnimeNextPageSelector() = null - - // =========================== Anime Details ============================ - override fun animeDetailsParse(document: Document) = SAnime.create().apply { - setUrlWithoutDomain(document.location()) - thumbnail_url = document.selectFirst("meta[property=og:image]")?.attr("content") - val container = document.selectFirst("div.moviePresent")!! - with(container) { - title = selectFirst("h2.tit")!!.text() - genre = select("div.genres > span").eachText().joinToString() - author = getInfo("Diretor") - artist = getInfo("Produtoras") - description = buildString { - selectFirst("p")?.text()?.also { append(it + "\n\n") } - getInfo("Título")?.also { append("Título original: $it\n") } - getInfo("Serie de")?.also { append("ano: $it\n") } - getInfo("Elenco")?.also { append("Elenco: $it\n") } - getInfo("Qualidade")?.also { append("Qualidade: $it\n") } - } - } - } - - // ============================== Episodes ============================== - private fun getSeasonEps(seasonElement: Element): List<SEpisode> { - val id = seasonElement.attr("data-load-episodes") - val sname = seasonElement.text() - val body = "getEpisodes=$id".toFormBody() - val response = client.newCall(POST("$EMBED_WAREZ_URL/serieAjax.php", body = body)).execute() - val episodes = response.parseAs<ApiResultsDto<EpisodeDto>>().items.values.map { - SEpisode.create().apply { - name = "Temp $sname: Ep ${it.name}" - episode_number = it.name.toFloatOrNull() ?: 0F - url = it.id - } - } - return episodes - } - - override fun episodeListParse(response: Response): List<SEpisode> { - val docUrl = response.asJsoup().selectFirst("div#playButton")!! - .attr("onclick") - .substringAfter("'") - .substringBefore("'") - return if (response.request.url.toString().contains("/serie/")) { - client.newCall(GET(docUrl)).execute() - .asJsoup() - .select("div#seasons div.item[data-load-episodes]") - .flatMap(::getSeasonEps) - .reversed() - } else { - listOf( - SEpisode.create().apply { - name = "Filme" - episode_number = 1F - url = "$EMBED_WAREZ_URL/filme/" + docUrl.substringAfter("=") - }, - ) - } - } - override fun episodeFromElement(element: Element): SEpisode { - throw UnsupportedOperationException() - } - - override fun episodeListSelector(): String { - throw UnsupportedOperationException() - } - - // ============================ Video Links ============================= - override fun videoListRequest(episode: SEpisode): Request { - val url = episode.url - return if (url.startsWith("https")) { - // Its an real url, maybe from a movie - GET(url, headers) - } else { - POST("$EMBED_WAREZ_URL/serieAjax.php", body = "getAudios=$url".toFormBody()) - } - } - - override fun videoListParse(response: Response): List<Video> { - val body = response.body.string() - // Pair<Language, Query> - val items = if (body.startsWith("{")) { - val data = json.decodeFromString<ApiResultsDto<PlayersDto>>(body) - data.items.values.flatMap { - val lang = if (it.audio == "1") "LEGENDADO" else "DUBLADO" - it.iterator().mapNotNull { (server, status) -> - if (status == "3") { - Pair(lang, "?id=${it.id}&sv=$server") - } else { - null - } - } - } - } else { - val doc = response.asJsoup(body) - doc.select("div.selectAudioButton").flatMap { - val lang = it.text() - val id = it.attr("data-load-hosts") - doc.select("div[data-load-embed=$id]").map { element -> - lang to "?id=$id&sv=${element.attr("data-load-embed-host")}" - } - }.ifEmpty { - val lang = doc.selectFirst("div.selectAudio > b")!!.text() - .substringBefore("/") - .uppercase() - val id = doc.selectFirst("*[data-load-embed]")!!.attr("data-load-embed") - doc.select("div.buttonLoadHost").map { - lang to "?id=$id&sv=${it.attr("data-load-embed-host")}" - } - } - } - return items.parallelCatchingFlatMapBlocking(::getVideosFromItem) - } - - private val streamtapeExtractor by lazy { StreamTapeExtractor(client) } - private val mixdropExtractor by lazy { MixDropExtractor(client) } - - private fun getVideosFromItem(item: Pair<String, String>): List<Video> { - val (lang, query) = item - val headers = headersBuilder().set("referer", WAREZ_URL).build() - val hostUrl = if ("warezcdn" in query) { - "$WAREZ_URL/player/player.php$query" - } else { - client.newCall(GET("$WAREZ_URL/embed/getPlay.php$query", headers)) - .execute() - .body.string() - .substringAfter("location.href=\"") - .substringBefore("\";") - } - - return when (query.substringAfter("sv=")) { - "streamtape" -> streamtapeExtractor.videosFromUrl(hostUrl, "Streamtape($lang)") - "mixdrop" -> mixdropExtractor.videoFromUrl(hostUrl, lang) - else -> null // TODO: Add warezcdn extractor - }.orEmpty() - } - - override fun videoFromElement(element: Element): Video { - throw UnsupportedOperationException() - } - - override fun videoListSelector(): String { - throw UnsupportedOperationException() - } - - override fun videoUrlParse(document: Document): String { - throw UnsupportedOperationException() - } - - // ============================== Settings ============================== - override fun setupPreferenceScreen(screen: PreferenceScreen) { - ListPreference(screen.context).apply { - key = PREF_PLAYER_KEY - title = PREF_PLAYER_TITLE - entries = PREF_PLAYER_ARRAY - entryValues = PREF_PLAYER_ARRAY - setDefaultValue(PREF_PLAYER_DEFAULT) - summary = "%s" - - setOnPreferenceChangeListener { _, newValue -> - val selected = newValue as String - val index = findIndexOfValue(selected) - val entry = entryValues[index] as String - preferences.edit().putString(key, entry).commit() - } - }.also(screen::addPreference) - - ListPreference(screen.context).apply { - key = PREF_LANGUAGE_KEY - title = PREF_LANGUAGE_TITLE - entries = PREF_LANGUAGE_ENTRIES - entryValues = PREF_LANGUAGE_VALUES - setDefaultValue(PREF_LANGUAGE_DEFAULT) - summary = "%s" - - setOnPreferenceChangeListener { _, newValue -> - val selected = newValue as String - val index = findIndexOfValue(selected) - val entry = entryValues[index] as String - preferences.edit().putString(key, entry).commit() - } - }.also(screen::addPreference) - } - - // ============================= Utilities ============================== - - private fun Element.getInfo(item: String) = selectFirst("*:containsOwn($item) b")?.text() - - private fun String.toFormBody() = toRequestBody("application/x-www-form-urlencoded".toMediaType()) - - override fun List<Video>.sort(): List<Video> { - val player = preferences.getString(PREF_PLAYER_KEY, PREF_PLAYER_DEFAULT)!! - val language = preferences.getString(PREF_LANGUAGE_KEY, PREF_LANGUAGE_DEFAULT)!! - return sortedWith( - compareBy( - { it.quality.contains(player) }, - { it.quality.contains(language) }, - ), - ).reversed() - } - - companion object { - - const val PREFIX_SEARCH = "path:" - - private const val EMBED_WAREZ_URL = "https://embed.warezcdn.net" - private const val WAREZ_URL = "https://warezcdn.com" - - private const val PREF_PLAYER_KEY = "pref_player" - private const val PREF_PLAYER_DEFAULT = "MixDrop" - private const val PREF_PLAYER_TITLE = "Player/Server favorito" - private val PREF_PLAYER_ARRAY = arrayOf( - "MixDrop", - "Streamtape", - ) - - private const val PREF_LANGUAGE_KEY = "pref_language" - private const val PREF_LANGUAGE_DEFAULT = "LEG" - private const val PREF_LANGUAGE_TITLE = "Língua/tipo preferido" - private val PREF_LANGUAGE_ENTRIES = arrayOf("Legendado", "Dublado") - private val PREF_LANGUAGE_VALUES = arrayOf("LEG", "DUB") - } -} diff --git a/src/pt/flixei/src/eu/kanade/tachiyomi/animeextension/pt/flixei/FlixeiUrlActivity.kt b/src/pt/flixei/src/eu/kanade/tachiyomi/animeextension/pt/flixei/FlixeiUrlActivity.kt deleted file mode 100644 index de531bdc..00000000 --- a/src/pt/flixei/src/eu/kanade/tachiyomi/animeextension/pt/flixei/FlixeiUrlActivity.kt +++ /dev/null @@ -1,42 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.pt.flixei - -import android.app.Activity -import android.content.ActivityNotFoundException -import android.content.Intent -import android.os.Bundle -import android.util.Log -import kotlin.system.exitProcess - -/** - * Springboard that accepts https://flixei.com/assistir/<type>/<item> intents - * and redirects them to the main Aniyomi process. - */ -class FlixeiUrlActivity : Activity() { - - private val tag = javaClass.simpleName - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - val pathSegments = intent?.data?.pathSegments - if (pathSegments != null && pathSegments.size > 2) { - val type = pathSegments[1] - val item = pathSegments[2] - val mainIntent = Intent().apply { - action = "eu.kanade.tachiyomi.ANIMESEARCH" - putExtra("query", "${Flixei.PREFIX_SEARCH}$type/$item") - putExtra("filter", packageName) - } - - try { - startActivity(mainIntent) - } catch (e: ActivityNotFoundException) { - Log.e(tag, e.toString()) - } - } else { - Log.e(tag, "could not parse uri from intent $intent") - } - - finish() - exitProcess(0) - } -} diff --git a/src/pt/flixei/src/eu/kanade/tachiyomi/animeextension/pt/flixei/dto/FlixeiDto.kt b/src/pt/flixei/src/eu/kanade/tachiyomi/animeextension/pt/flixei/dto/FlixeiDto.kt deleted file mode 100644 index e3849cd9..00000000 --- a/src/pt/flixei/src/eu/kanade/tachiyomi/animeextension/pt/flixei/dto/FlixeiDto.kt +++ /dev/null @@ -1,33 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.pt.flixei.dto - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class ApiResultsDto<T>( - @SerialName("list") - val items: Map<String, T>, -) - -@Serializable -data class AnimeDto(val id: String, val title: String, val url: String) - -@Serializable -data class EpisodeDto(val id: String, val name: String) - -@Serializable -data class PlayersDto( - val id: String, - val audio: String, - val mixdropStatus: String = "0", - val streamtapeStatus: String = "0", - val warezcdnStatus: String = "0", -) { - operator fun iterator(): List<Pair<String, String>> { - return listOf( - "streamtape" to streamtapeStatus, - "mixdrop" to mixdropStatus, - "warezcdn" to warezcdnStatus, - ) - } -} diff --git a/src/pt/listadeanimes/build.gradle b/src/pt/listadeanimes/build.gradle deleted file mode 100644 index 6ac76a1d..00000000 --- a/src/pt/listadeanimes/build.gradle +++ /dev/null @@ -1,7 +0,0 @@ -ext { - extName = 'Lista de Animes' - extClass = '.ListaDeAnimes' - extVersionCode = 2 -} - -apply from: "$rootDir/common.gradle" diff --git a/src/pt/listadeanimes/res/mipmap-hdpi/ic_launcher.png b/src/pt/listadeanimes/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 5cee6385..00000000 Binary files a/src/pt/listadeanimes/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/listadeanimes/res/mipmap-mdpi/ic_launcher.png b/src/pt/listadeanimes/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index a09f0d88..00000000 Binary files a/src/pt/listadeanimes/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/listadeanimes/res/mipmap-xhdpi/ic_launcher.png b/src/pt/listadeanimes/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index fe66479c..00000000 Binary files a/src/pt/listadeanimes/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/listadeanimes/res/mipmap-xxhdpi/ic_launcher.png b/src/pt/listadeanimes/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 4d18c5d5..00000000 Binary files a/src/pt/listadeanimes/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/listadeanimes/res/mipmap-xxxhdpi/ic_launcher.png b/src/pt/listadeanimes/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 91b2c05b..00000000 Binary files a/src/pt/listadeanimes/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/listadeanimes/src/eu/kanade/tachiyomi/animeextension/pt/listadeanimes/ListaDeAnimes.kt b/src/pt/listadeanimes/src/eu/kanade/tachiyomi/animeextension/pt/listadeanimes/ListaDeAnimes.kt deleted file mode 100644 index b4b3b04f..00000000 --- a/src/pt/listadeanimes/src/eu/kanade/tachiyomi/animeextension/pt/listadeanimes/ListaDeAnimes.kt +++ /dev/null @@ -1,112 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.pt.listadeanimes - -import eu.kanade.tachiyomi.animesource.model.AnimeFilterList -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.network.GET -import eu.kanade.tachiyomi.util.asJsoup -import okhttp3.Request -import okhttp3.Response -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element - -class ListaDeAnimes : ParsedAnimeHttpSource() { - override val name = "Lista de Animes" - - override val baseUrl = "https://www.listadeanimes.com" - - override val lang = "pt-BR" - - override val supportsLatest = false - - override fun headersBuilder() = super.headersBuilder() - .add("Referer", baseUrl) - - // ============================== Popular =============================== - override fun popularAnimeRequest(page: Int) = GET("$baseUrl/page/$page") - - override fun popularAnimeSelector() = "article.post.excerpt > div.capa:not(:has(a[href=$baseUrl/anime-lista-online]))" - - override fun popularAnimeFromElement(element: Element) = SAnime.create().apply { - setUrlWithoutDomain(element.selectFirst("a")!!.attr("href")) - val img = element.selectFirst("img")!! - title = titleCase(img.attr("title").substringBefore(" todos os episódios")) - thumbnail_url = img.attr("data-src") - } - - override fun popularAnimeNextPageSelector() = "a.next.page-numbers" - - // =============================== Latest =============================== - override fun latestUpdatesRequest(page: Int): Request = throw UnsupportedOperationException() - override fun latestUpdatesSelector(): String = throw UnsupportedOperationException() - override fun latestUpdatesFromElement(element: Element): SAnime = throw UnsupportedOperationException() - override fun latestUpdatesNextPageSelector() = throw UnsupportedOperationException() - - // =============================== Search =============================== - override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList) = GET("$baseUrl/page/$page?s=$query") - override fun searchAnimeParse(response: Response) = popularAnimeParse(response) - override fun searchAnimeSelector() = popularAnimeSelector() - override fun searchAnimeFromElement(element: Element) = popularAnimeFromElement(element) - override fun searchAnimeNextPageSelector() = popularAnimeNextPageSelector() - - // =========================== Anime Details ============================ - override fun animeDetailsParse(document: Document) = SAnime.create().apply { - setUrlWithoutDomain(document.location()) - val titleText = document.selectFirst("h1.title.single-title")!!.text() - title = titleCase(titleText.substringBefore(" todos os episódios")) - thumbnail_url = document.selectFirst("img.aligncenter.size-full")?.attr("src") - val infos = document.selectFirst("div#content.post-single-content > center") - val infosText = infos?.run { - html() - .replace("<br>", "\n") - .replace("<b>", "") - .replace("</b>", "") - }?.let { "\n\n$it" }.orEmpty() - - val sinopse = document.selectFirst("div#content > *:contains(Sinopse)")?.nextElementSibling() - description = (sinopse?.text() ?: "Sem sinopse.") + infosText - genre = document.select("a[rel=tag]").joinToString { it.text() } - } - - // ============================== Episodes ============================== - override fun episodeListSelector() = "div.videos > ul" - - override fun episodeListParse(response: Response): List<SEpisode> { - val doc = response.asJsoup() - return doc.select("div.videos > ul > li:gt(0)") - .map(::episodeFromElement) - .reversed() - } - override fun episodeFromElement(element: Element): SEpisode { - return SEpisode.create().apply { - episode_number = runCatching { - element.selectFirst("string")!! - .text() - .substringAfter(" ") - .toFloat() - }.getOrDefault(0F) - name = element.text().substringAfter("► ") - url = element.attr("id") - } - } - - // ============================ Video Links ============================= - override suspend fun getVideoList(episode: SEpisode): List<Video> { - return listOf(Video(episode.url, episode.name, episode.url)) - } - - override fun videoListSelector() = throw UnsupportedOperationException() - override fun videoListRequest(episode: SEpisode) = throw UnsupportedOperationException() - override fun videoListParse(response: Response) = throw UnsupportedOperationException() - override fun videoFromElement(element: Element) = throw UnsupportedOperationException() - override fun videoUrlParse(document: Document) = throw UnsupportedOperationException() - - // ============================= Utilities ============================== - private fun titleCase(str: String): String { - return str.split(' ') - .map { it.replaceFirstChar(Char::uppercase) } - .joinToString(" ") - } -} diff --git a/src/pt/megaflix/AndroidManifest.xml b/src/pt/megaflix/AndroidManifest.xml deleted file mode 100644 index c7f04aa4..00000000 --- a/src/pt/megaflix/AndroidManifest.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<manifest xmlns:android="http://schemas.android.com/apk/res/android"> - - <application> - <activity - android:name=".pt.megaflix.MegaflixUrlActivity" - android:excludeFromRecents="true" - android:exported="true" - android:theme="@android:style/Theme.NoDisplay"> - <intent-filter> - <action android:name="android.intent.action.VIEW" /> - - <category android:name="android.intent.category.DEFAULT" /> - <category android:name="android.intent.category.BROWSABLE" /> - - <data - android:host="megaflix.co" - android:pathPattern="/..*/..*/" - android:scheme="https" /> - </intent-filter> - </activity> - </application> -</manifest> diff --git a/src/pt/megaflix/build.gradle b/src/pt/megaflix/build.gradle deleted file mode 100644 index a5713572..00000000 --- a/src/pt/megaflix/build.gradle +++ /dev/null @@ -1,20 +0,0 @@ -ext { - extName = 'Megaflix' - extClass = '.Megaflix' - extVersionCode = 24 - isNsfw = true -} - -apply from: "$rootDir/common.gradle" - -dependencies { - implementation(project(':lib:mixdrop-extractor')) - implementation(project(":lib:streamtape-extractor")) - implementation(project(":lib:voe-extractor")) - implementation(project(":lib:filemoon-extractor")) - implementation(project(":lib:vidhide-extractor")) - implementation(project(":lib:streamwish-extractor")) - implementation(project(":lib:playlist-utils")) - // for mixdrop and megaflix - implementation(libs.jsunpacker) -} diff --git a/src/pt/megaflix/res/mipmap-hdpi/ic_launcher.png b/src/pt/megaflix/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index bf99313a..00000000 Binary files a/src/pt/megaflix/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/megaflix/res/mipmap-mdpi/ic_launcher.png b/src/pt/megaflix/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 0bf5f9da..00000000 Binary files a/src/pt/megaflix/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/megaflix/res/mipmap-xhdpi/ic_launcher.png b/src/pt/megaflix/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 6ea93116..00000000 Binary files a/src/pt/megaflix/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/megaflix/res/mipmap-xxhdpi/ic_launcher.png b/src/pt/megaflix/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index c441ac81..00000000 Binary files a/src/pt/megaflix/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/megaflix/res/mipmap-xxxhdpi/ic_launcher.png b/src/pt/megaflix/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 524bfd1d..00000000 Binary files a/src/pt/megaflix/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/megaflix/src/eu/kanade/tachiyomi/animeextension/pt/megaflix/Megaflix.kt b/src/pt/megaflix/src/eu/kanade/tachiyomi/animeextension/pt/megaflix/Megaflix.kt deleted file mode 100644 index e64a0785..00000000 --- a/src/pt/megaflix/src/eu/kanade/tachiyomi/animeextension/pt/megaflix/Megaflix.kt +++ /dev/null @@ -1,317 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.pt.megaflix - -import android.app.Application -import androidx.preference.ListPreference -import androidx.preference.PreferenceScreen -import eu.kanade.tachiyomi.animeextension.pt.megaflix.extractors.MegaflixExtractor -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.filemoonextractor.FilemoonExtractor -import eu.kanade.tachiyomi.lib.mixdropextractor.MixDropExtractor -import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils -import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor -import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor -import eu.kanade.tachiyomi.lib.vidhideextractor.VidHideExtractor -import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor -import eu.kanade.tachiyomi.network.GET -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.parallelFlatMapBlocking -import okhttp3.Request -import okhttp3.Response -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get - -class Megaflix : ConfigurableAnimeSource, ParsedAnimeHttpSource() { - - override val name = "Megaflix" - - override val baseUrl = "https://megaflix.ac" - - override val lang = "pt-BR" - - override val supportsLatest = true - - override fun headersBuilder() = super.headersBuilder().add("Referer", "$baseUrl/") - - private val preferences by lazy { - Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) - } - - // ============================== Popular =============================== - override fun popularAnimeRequest(page: Int) = GET(baseUrl) - - override fun popularAnimeSelector() = "section#widget_list_movies_series-5 li > article" - - override fun popularAnimeFromElement(element: Element) = SAnime.create().apply { - title = element.selectFirst("h2.entry-title")!!.text() - setUrlWithoutDomain(element.selectFirst("a.lnk-blk")!!.attr("href")) - thumbnail_url = element.selectFirst("img")?.absUrl("src") - } - - override fun popularAnimeNextPageSelector() = null - - // =============================== Latest =============================== - override fun latestUpdatesRequest(page: Int): Request { - val pageType = preferences.getString(PREF_LATEST_PAGE_KEY, PREF_LATEST_PAGE_DEFAULT)!! - return GET("$baseUrl/$pageType/page/$page") - } - - override fun latestUpdatesSelector() = "li > article" - - override fun latestUpdatesFromElement(element: Element) = popularAnimeFromElement(element) - - override fun latestUpdatesNextPageSelector() = "div.nav-links > a:containsOwn(PRÓXIMO)" - - // =============================== Search =============================== - override suspend fun getSearchAnime( - page: Int, - query: String, - filters: AnimeFilterList, - ): AnimesPage { - return if (query.startsWith(PREFIX_SEARCH)) { // URL intent handler - val path = query.removePrefix(PREFIX_SEARCH) - client.newCall(GET("$baseUrl/$path")) - .awaitSuccess() - .use(::searchAnimeByPathParse) - } else { - super.getSearchAnime(page, query, filters) - } - } - - private fun searchAnimeByPathParse(response: Response): AnimesPage { - val details = animeDetailsParse(response.asJsoup()).apply { - setUrlWithoutDomain(response.request.url.toString()) - initialized = true - } - - return AnimesPage(listOf(details), false) - } - - override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request { - return if (query.isNotBlank()) { - GET("$baseUrl/page/$page/?s=$query") - } else { - val genre = MegaflixFilters.getGenre(filters) - GET("$baseUrl/categoria/$genre/page/$page") - } - } - - override fun searchAnimeSelector() = latestUpdatesSelector() - - override fun searchAnimeFromElement(element: Element) = popularAnimeFromElement(element) - - override fun searchAnimeNextPageSelector() = latestUpdatesNextPageSelector() - - override fun getFilterList() = MegaflixFilters.FILTER_LIST - - // =========================== Anime Details ============================ - override fun animeDetailsParse(document: Document) = SAnime.create().apply { - setUrlWithoutDomain(document.location()) - val infos = document.selectFirst("div.bd > article.post.single")!! - title = infos.selectFirst("h1.entry-title")!!.text() - thumbnail_url = infos.selectFirst("img")?.absUrl("src") - genre = infos.select("span.genres > a").eachText().joinToString() - description = infos.selectFirst("div.description")?.text() - } - - // ============================== Episodes ============================== - override fun episodeListSelector() = "li > article.episodes" - private fun seasonListSelector() = "section.episodes div.choose-season > a" - - override fun episodeListParse(response: Response): List<SEpisode> { - val doc = response.asJsoup() - val seasons = doc.select(seasonListSelector()) - return when { - seasons.isEmpty() -> listOf( - SEpisode.create().apply { - name = "Filme" - setUrlWithoutDomain(doc.location()) - episode_number = 1F - }, - ) - - else -> seasons.parallelFlatMapBlocking(::episodesFromSeason).reversed() - } - } - - private suspend fun episodesFromSeason(seasonElement: Element): List<SEpisode> { - return seasonElement.attr("href").let { url -> - client.newCall(GET(url, headers)).await() - .asJsoup() - .select(episodeListSelector()) - .map(::episodeFromElement) - } - } - - override fun episodeFromElement(element: Element) = SEpisode.create().apply { - name = element.selectFirst("h2.entry-title")!!.text() - setUrlWithoutDomain(element.selectFirst("a.lnk-blk")!!.attr("href")) - episode_number = element.selectFirst("span.num-epi")?.run { - text().split("x").last().toFloatOrNull() ?: 0F - } ?: 0F - } - - // ============================ Video Links ============================= - override fun videoListParse(response: Response): List<Video> { - val items = response.asJsoup().select(videoListSelector()) - return items - .parallelCatchingFlatMapBlocking { element -> - val language = element.text().substringAfter("-") - val id = element.attr("href") - val url = element.closest("body")?.selectFirst("div$id iframe") - ?.let { - val iframeUrl = it.attr("src") - client.newCall(GET(iframeUrl, headers)) - .execute() - .asJsoup() - .selectFirst("iframe") - ?.attr("src") - } ?: return@parallelCatchingFlatMapBlocking emptyList() - - getVideoList(url, language) - } - } - - /*--------------------------------Video extractors------------------------------------*/ - private val webViewResolver by lazy { WebViewResolver() } - private val playlistUtils by lazy { PlaylistUtils(client, headers) } - - private val mixdropExtractor by lazy { MixDropExtractor(client) } - private val streamtapeExtractor by lazy { StreamTapeExtractor(client) } - private val megaflixExtractor by lazy { MegaflixExtractor(client, headers) } - private val voeExtractor by lazy { VoeExtractor(client) } - private val filemoonExtractor by lazy { FilemoonExtractor(client) } - private val vidHideExtractor by lazy { VidHideExtractor(client, headers) } - private val streamWishExtractor by lazy { StreamWishExtractor(client, headers) } - - private fun getVideoList(url: String, language: String): List<Video> { - return when { - arrayOf("mixdrop", "mixdroop", "mix").any(url) -> mixdropExtractor.videoFromUrl(url, language) - arrayOf("streamtape", "stp", "stape").any(url) -> streamtapeExtractor.videosFromUrl(url, "StreamTape - $language") - arrayOf("mflix").any(url) -> megaflixExtractor.videosFromUrl(url, language) - arrayOf("voe").any(url) -> voeExtractor.videosFromUrl(url, "$language ") - arrayOf("filemoon", "moonplayer").any(url) -> filemoonExtractor.videosFromUrl(url, prefix = "$language Filemoon:") - arrayOf("vidhide", "vid.").any(url) -> vidHideExtractor.videosFromUrl(url, videoNameGen = { "$language VidHide:$it" }) - arrayOf("wishembed", "streamwish", "strwish", "wish", "jwplayerhls").any(url) -> streamWishExtractor.videosFromUrl(url, videoNameGen = { "$language StreamWish:$it" }) - arrayOf("fembedder").any(url) -> { - val webViewResult = webViewResolver.getUrl(url, headers) - if (webViewResult.isBlank()) { - return emptyList() - } - return if (webViewResult.contains("m3u8")) { - playlistUtils.extractFromHls(webViewResult) - } else { - listOf(Video(url, "Default", url)) - } - } - else -> emptyList() - } - } - - override fun videoListSelector() = "aside.video-options li a" - - override fun videoFromElement(element: Element) = throw UnsupportedOperationException() - - override fun videoUrlParse(document: Document) = throw UnsupportedOperationException() - - // ============================== Settings ============================== - override fun setupPreferenceScreen(screen: PreferenceScreen) { - ListPreference(screen.context).apply { - key = PREF_QUALITY_KEY - title = PREF_QUALITY_TITLE - entries = PREF_QUALITY_ENTRIES - entryValues = PREF_QUALITY_ENTRIES - setDefaultValue(PREF_QUALITY_DEFAULT) - summary = "%s" - - setOnPreferenceChangeListener { _, newValue -> - val selected = newValue as String - val index = findIndexOfValue(selected) - val entry = entryValues[index] as String - preferences.edit().putString(key, entry).commit() - } - }.also(screen::addPreference) - - ListPreference(screen.context).apply { - key = PREF_LANGUAGE_KEY - title = PREF_LANGUAGE_TITLE - entries = PREF_LANGUAGE_VALUES - entryValues = PREF_LANGUAGE_VALUES - setDefaultValue(PREF_LANGUAGE_DEFAULT) - summary = "%s" - - setOnPreferenceChangeListener { _, newValue -> - val selected = newValue as String - val index = findIndexOfValue(selected) - val entry = entryValues[index] as String - preferences.edit().putString(key, entry).commit() - } - }.also(screen::addPreference) - - ListPreference(screen.context).apply { - key = PREF_LATEST_PAGE_KEY - title = PREF_LATEST_PAGE_TITLE - entries = PREF_LATEST_PAGE_ENTRIES - entryValues = PREF_LATEST_PAGE_VALUES - setDefaultValue(PREF_LATEST_PAGE_DEFAULT) - summary = "%s" - - setOnPreferenceChangeListener { _, newValue -> - val selected = newValue as String - val index = findIndexOfValue(selected) - val entry = entryValues[index] as String - preferences.edit().putString(key, entry).commit() - } - }.also(screen::addPreference) - } - - // ============================= Utilities ============================== - override fun List<Video>.sort(): List<Video> { - val quality = preferences.getString(PREF_QUALITY_KEY, PREF_QUALITY_DEFAULT)!! - val lang = preferences.getString(PREF_LANGUAGE_KEY, PREF_LANGUAGE_DEFAULT)!! - return sortedWith( - compareBy( - { it.quality.contains(quality) }, - { it.quality.contains(lang) }, - ), - ).reversed() - } - - private fun Array<String>.any(url: String): Boolean = this.any { url.contains(it, ignoreCase = true) } - - companion object { - const val PREFIX_SEARCH = "path:" - - private const val PREF_QUALITY_KEY = "preferred_quality" - private const val PREF_QUALITY_TITLE = "Qualidade preferida" - private const val PREF_QUALITY_DEFAULT = "720p" - private val PREF_QUALITY_ENTRIES = arrayOf("360p", "480p", "720p", "1080p") - - private const val PREF_LANGUAGE_KEY = "pref_language" - private const val PREF_LANGUAGE_DEFAULT = "Legendado" - private const val PREF_LANGUAGE_TITLE = "Língua/tipo preferido" - private val PREF_LANGUAGE_VALUES = arrayOf("Legendado", "Dublado") - - private const val PREF_LATEST_PAGE_KEY = "pref_latest_page" - private const val PREF_LATEST_PAGE_DEFAULT = "series" - private const val PREF_LATEST_PAGE_TITLE = "Página de últimos adicionados" - private val PREF_LATEST_PAGE_ENTRIES = arrayOf( - "Filmes", - "Séries", - ) - private val PREF_LATEST_PAGE_VALUES = arrayOf( - "filmes", - "series", - ) - } -} diff --git a/src/pt/megaflix/src/eu/kanade/tachiyomi/animeextension/pt/megaflix/MegaflixFilters.kt b/src/pt/megaflix/src/eu/kanade/tachiyomi/animeextension/pt/megaflix/MegaflixFilters.kt deleted file mode 100644 index 07f6de38..00000000 --- a/src/pt/megaflix/src/eu/kanade/tachiyomi/animeextension/pt/megaflix/MegaflixFilters.kt +++ /dev/null @@ -1,59 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.pt.megaflix - -import eu.kanade.tachiyomi.animesource.model.AnimeFilter -import eu.kanade.tachiyomi.animesource.model.AnimeFilterList - -object MegaflixFilters { - - open class QueryPartFilter( - displayName: String, - val vals: Array<Pair<String, String>>, - ) : AnimeFilter.Select<String>( - displayName, - vals.map { it.first }.toTypedArray(), - ) { - fun toQueryPart() = vals[state].second - } - - private inline fun <reified R> AnimeFilterList.asQueryPart(): String { - return (first { it is R } as QueryPartFilter).toQueryPart() - } - - class GenreFilter : QueryPartFilter("Gênero", MegaflixFiltersData.GENRES) - - val FILTER_LIST get() = AnimeFilterList( - AnimeFilter.Header(MegaflixFiltersData.IGNORE_SEARCH_MSG), - GenreFilter(), - ) - - fun getGenre(filters: AnimeFilterList) = filters.asQueryPart<GenreFilter>() - - private object MegaflixFiltersData { - const val IGNORE_SEARCH_MSG = "NOTA: O filtro é IGNORADO ao usar a pesquisa." - - val GENRES = arrayOf( - Pair("Animação", "animacao"), - Pair("Aventura", "aventura"), - Pair("Ação", "acao"), - Pair("Biografia", "biografia"), - Pair("Comédia", "comedia"), - Pair("Crime", "crime"), - Pair("Documentário", "documentario"), - Pair("Drama", "drama"), - Pair("Esporte", "esporte"), - Pair("Família", "familia"), - Pair("Fantasia", "fantasia"), - Pair("Faroeste", "faroeste"), - Pair("Ficção científica", "ficcao-cientifica"), - Pair("Guerra", "guerra"), - Pair("História", "historia"), - Pair("Mistério", "misterio"), - Pair("Musical", "musical"), - Pair("Música", "musica"), - Pair("Romance", "romance"), - Pair("Show", "show"), - Pair("Terror", "terror"), - Pair("Thriller", "thriller"), - ) - } -} diff --git a/src/pt/megaflix/src/eu/kanade/tachiyomi/animeextension/pt/megaflix/MegaflixUrlActivity.kt b/src/pt/megaflix/src/eu/kanade/tachiyomi/animeextension/pt/megaflix/MegaflixUrlActivity.kt deleted file mode 100644 index cec9a93d..00000000 --- a/src/pt/megaflix/src/eu/kanade/tachiyomi/animeextension/pt/megaflix/MegaflixUrlActivity.kt +++ /dev/null @@ -1,41 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.pt.megaflix - -import android.app.Activity -import android.content.ActivityNotFoundException -import android.content.Intent -import android.os.Bundle -import android.util.Log -import kotlin.system.exitProcess - -/** - * Springboard that accepts https://megaflix.ac/<type>/<item> intents - * and redirects them to the main Aniyomi process. - */ -class MegaflixUrlActivity : Activity() { - - private val tag = javaClass.simpleName - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - val pathSegments = intent?.data?.pathSegments - if (pathSegments != null && pathSegments.size > 1) { - val path = "${pathSegments[0]}/${pathSegments[1]}" - val mainIntent = Intent().apply { - action = "eu.kanade.tachiyomi.ANIMESEARCH" - putExtra("query", "${Megaflix.PREFIX_SEARCH}$path") - putExtra("filter", packageName) - } - - try { - startActivity(mainIntent) - } catch (e: ActivityNotFoundException) { - Log.e(tag, e.toString()) - } - } else { - Log.e(tag, "could not parse uri from intent $intent") - } - - finish() - exitProcess(0) - } -} diff --git a/src/pt/megaflix/src/eu/kanade/tachiyomi/animeextension/pt/megaflix/WebViewResolver.kt b/src/pt/megaflix/src/eu/kanade/tachiyomi/animeextension/pt/megaflix/WebViewResolver.kt deleted file mode 100644 index a1c377b0..00000000 --- a/src/pt/megaflix/src/eu/kanade/tachiyomi/animeextension/pt/megaflix/WebViewResolver.kt +++ /dev/null @@ -1,69 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.pt.megaflix - -import android.annotation.SuppressLint -import android.app.Application -import android.os.Handler -import android.os.Looper -import android.webkit.WebResourceRequest -import android.webkit.WebResourceResponse -import android.webkit.WebView -import android.webkit.WebViewClient -import okhttp3.Headers -import uy.kohesive.injekt.injectLazy -import java.util.concurrent.CountDownLatch -import java.util.concurrent.TimeUnit - -class WebViewResolver() { - private val context: Application by injectLazy() - private val handler by lazy { Handler(Looper.getMainLooper()) } - - @SuppressLint("SetJavaScriptEnabled") - fun getUrl(origRequestUrl: String, origRequestheader: Headers): String { - val latch = CountDownLatch(1) - var webView: WebView? = null - var resultUrl = "" - val headers = origRequestheader.toMultimap().mapValues { it.value.getOrNull(0) ?: "" }.toMutableMap() - - handler.post { - val webview = WebView(context) - webView = webview - with(webview.settings) { - javaScriptEnabled = true - domStorageEnabled = true - databaseEnabled = true - useWideViewPort = false - loadWithOverviewMode = false - userAgentString = origRequestheader["User-Agent"] - } - webview.webViewClient = object : WebViewClient() { - override fun shouldInterceptRequest( - view: WebView, - request: WebResourceRequest, - ): WebResourceResponse? { - val url = request.url.toString() - if (VIDEO_REGEX.containsMatchIn(url)) { - resultUrl = url - latch.countDown() - } - return super.shouldInterceptRequest(view, request) - } - } - - webView?.loadUrl(origRequestUrl, headers) - } - - latch.await(TIMEOUT_SEC, TimeUnit.SECONDS) - - handler.post { - webView?.stopLoading() - webView?.destroy() - webView = null - } - return resultUrl - } - - companion object { - const val TIMEOUT_SEC: Long = 20 - private val VIDEO_REGEX by lazy { Regex("\\.(mp4|m3u8)") } - } -} diff --git a/src/pt/megaflix/src/eu/kanade/tachiyomi/animeextension/pt/megaflix/extractors/MegaflixExtractor.kt b/src/pt/megaflix/src/eu/kanade/tachiyomi/animeextension/pt/megaflix/extractors/MegaflixExtractor.kt deleted file mode 100644 index 849511d8..00000000 --- a/src/pt/megaflix/src/eu/kanade/tachiyomi/animeextension/pt/megaflix/extractors/MegaflixExtractor.kt +++ /dev/null @@ -1,28 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.pt.megaflix.extractors - -import dev.datlag.jsunpacker.JsUnpacker -import eu.kanade.tachiyomi.animesource.model.Video -import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils -import eu.kanade.tachiyomi.network.GET -import okhttp3.Headers -import okhttp3.OkHttpClient - -class MegaflixExtractor(private val client: OkHttpClient, private val headers: Headers) { - private val playlistUtils by lazy { PlaylistUtils(client, headers) } - - fun videosFromUrl(url: String, lang: String = ""): List<Video> { - val unpacked = client.newCall(GET(url, headers)).execute() - .body.string() - .let(JsUnpacker::unpackAndCombine) - ?.replace("\\", "") - ?: return emptyList() - - val playlistUrl = unpacked.substringAfter("file':'").substringBefore("'") - - return playlistUtils.extractFromHls( - playlistUrl, - "https://megaflix.ac", - videoNameGen = { "Megaflix($lang) - $it" }, - ) - } -} diff --git a/src/pt/pifansubs/res/web_hi_res_512.png b/src/pt/pifansubs/res/web_hi_res_512.png deleted file mode 100644 index e586e291..00000000 Binary files a/src/pt/pifansubs/res/web_hi_res_512.png and /dev/null differ diff --git a/src/pt/pobreflix/build.gradle b/src/pt/pobreflix/build.gradle deleted file mode 100644 index a3dcec69..00000000 --- a/src/pt/pobreflix/build.gradle +++ /dev/null @@ -1,19 +0,0 @@ -ext { - extName = 'Pobreflix' - extClass = '.Pobreflix' - themePkg = 'dooplay' - baseUrl = 'https://pobreflix.global' - overrideVersionCode = 18 - isNsfw = true -} - -apply from: "$rootDir/common.gradle" - -dependencies { - implementation(project(":lib:filemoon-extractor")) - implementation(project(':lib:fireplayer-extractor')) - implementation(project(":lib:streamwish-extractor")) - implementation(project(":lib:streamtape-extractor")) - implementation(project(":lib:playlist-utils")) - implementation(libs.jsunpacker) -} diff --git a/src/pt/pobreflix/res/mipmap-hdpi/ic_launcher.png b/src/pt/pobreflix/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index d5f7231a..00000000 Binary files a/src/pt/pobreflix/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/pobreflix/res/mipmap-mdpi/ic_launcher.png b/src/pt/pobreflix/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 208cbaa0..00000000 Binary files a/src/pt/pobreflix/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/pobreflix/res/mipmap-xhdpi/ic_launcher.png b/src/pt/pobreflix/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 30444a76..00000000 Binary files a/src/pt/pobreflix/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/pobreflix/res/mipmap-xxhdpi/ic_launcher.png b/src/pt/pobreflix/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index cbd9fe5d..00000000 Binary files a/src/pt/pobreflix/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/pobreflix/res/mipmap-xxxhdpi/ic_launcher.png b/src/pt/pobreflix/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 35b2f3c2..00000000 Binary files a/src/pt/pobreflix/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/pobreflix/src/eu/kanade/tachiyomi/animeextension/pt/pobreflix/Pobreflix.kt b/src/pt/pobreflix/src/eu/kanade/tachiyomi/animeextension/pt/pobreflix/Pobreflix.kt deleted file mode 100644 index c1159018..00000000 --- a/src/pt/pobreflix/src/eu/kanade/tachiyomi/animeextension/pt/pobreflix/Pobreflix.kt +++ /dev/null @@ -1,80 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.pt.pobreflix - -import android.util.Base64 -import eu.kanade.tachiyomi.animeextension.pt.pobreflix.extractors.MyStreamExtractor -import eu.kanade.tachiyomi.animeextension.pt.pobreflix.extractors.PlayerFlixExtractor -import eu.kanade.tachiyomi.animeextension.pt.pobreflix.extractors.SuperFlixExtractor -import eu.kanade.tachiyomi.animesource.model.Video -import eu.kanade.tachiyomi.lib.filemoonextractor.FilemoonExtractor -import eu.kanade.tachiyomi.lib.fireplayerextractor.FireplayerExtractor -import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor -import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor -import eu.kanade.tachiyomi.multisrc.dooplay.DooPlay -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.util.asJsoup -import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking -import okhttp3.HttpUrl.Companion.toHttpUrl -import okhttp3.Response - -class Pobreflix : DooPlay( - "pt-BR", - "Pobreflix", - "https://pobreflix.global", -) { - // ============================== Popular =============================== - override fun popularAnimeSelector() = "div.featured div.poster" - - // =============================== Latest =============================== - override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/series/page/$page/", headers) - - // ============================ Video Links ============================= - private val fireplayerExtractor by lazy { FireplayerExtractor(client) } - private val filemoonExtractor by lazy { FilemoonExtractor(client) } - private val mystreamExtractor by lazy { MyStreamExtractor(client, headers) } - private val streamtapeExtractor by lazy { StreamTapeExtractor(client) } - private val streamwishExtractor by lazy { StreamWishExtractor(client, headers) } - private val playerflixExtractor by lazy { PlayerFlixExtractor(client, headers, ::genericExtractor) } - private val superflixExtractor by lazy { SuperFlixExtractor(client, headers, ::genericExtractor) } - private val supercdnExtractor by lazy { SuperFlixExtractor(client, headers, ::genericExtractor, "https://supercdn.org") } - - override fun videoListParse(response: Response): List<Video> { - val doc = response.asJsoup() - return doc.select("div.source-box > a").parallelCatchingFlatMapBlocking { - val data = it.attr("href").trim().toHttpUrl().queryParameter("auth") - ?.let { Base64.decode(it, Base64.DEFAULT) } - ?.let(::String) - ?: return@parallelCatchingFlatMapBlocking emptyList() - val url = data.replace("\\", "").substringAfter("url\":\"").substringBefore('"') - genericExtractor(url) - } - } - - private fun genericExtractor(url: String, language: String = ""): List<Video> { - val langSubstr = if (language.isBlank()) "" else "[$language] " - return when { - url.contains("superflix") -> - superflixExtractor.videosFromUrl(url) - url.contains("supercdn") -> - supercdnExtractor.videosFromUrl(url) - url.contains("filemoon") -> - filemoonExtractor.videosFromUrl(url, "${langSubstr}Filemoon - ", headers = headers) - url.contains("watch.brplayer") || url.contains("/watch?v=") -> - mystreamExtractor.videosFromUrl(url, language) - url.contains("brbeast") -> - fireplayerExtractor.videosFromUrl(url = url, videoNameGen = { "${langSubstr}BrBeast - $it" }) - url.contains("embedplayer") -> - fireplayerExtractor.videosFromUrl(url = url, videoNameGen = { "${langSubstr}EmbedPlayer - $it" }) - url.contains("superembeds") -> - fireplayerExtractor.videosFromUrl(url = url, videoNameGen = { "${langSubstr}SuperEmbeds - $it" }) - url.contains("streamtape") -> - streamtapeExtractor.videosFromUrl(url, "${langSubstr}Streamtape") - url.contains("filelions") -> - streamwishExtractor.videosFromUrl(url, videoNameGen = { "${langSubstr}FileLions - $it" }) - url.contains("streamwish") -> - streamwishExtractor.videosFromUrl(url, videoNameGen = { "${langSubstr}Streamwish - $it" }) - url.contains("playerflix") -> - playerflixExtractor.videosFromUrl(url) - else -> emptyList() - } - } -} diff --git a/src/pt/pobreflix/src/eu/kanade/tachiyomi/animeextension/pt/pobreflix/extractors/MyStreamExtractor.kt b/src/pt/pobreflix/src/eu/kanade/tachiyomi/animeextension/pt/pobreflix/extractors/MyStreamExtractor.kt deleted file mode 100644 index b510b9db..00000000 --- a/src/pt/pobreflix/src/eu/kanade/tachiyomi/animeextension/pt/pobreflix/extractors/MyStreamExtractor.kt +++ /dev/null @@ -1,48 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.pt.pobreflix.extractors - -import eu.kanade.tachiyomi.animesource.model.Video -import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils -import eu.kanade.tachiyomi.network.GET -import okhttp3.Headers -import okhttp3.OkHttpClient - -// From animeworldindia -class MyStreamExtractor(private val client: OkHttpClient, private val headers: Headers) { - - private val playlistUtils by lazy { PlaylistUtils(client, headers) } - - fun videosFromUrl(url: String, language: String): List<Video> { - val host = url.substringBefore("/watch?") - - val response = client.newCall(GET(url, headers)).execute() - val body = response.body.string() - - val codePart = body - .substringAfter("sniff(") // Video function - .substringBefore(",[") - - val streamCode = codePart - .substringAfterLast(",\"") // our beloved hash - .substringBefore('"') - - val id = codePart.substringAfter(",\"").substringBefore('"') // required ID - - val streamUrl = "$host/m3u8/$id/$streamCode/master.txt?s=1&cache=1" - - val cookie = response.headers.firstOrNull { - it.first.startsWith("set-cookie", true) && it.second.startsWith("PHPSESSID", true) - }?.second?.substringBefore(";") ?: "" - - val newHeaders = headers.newBuilder() - .set("cookie", cookie) - .set("accept", "*/*") - .build() - - return playlistUtils.extractFromHls( - streamUrl, - masterHeaders = newHeaders, - videoHeaders = newHeaders, - videoNameGen = { "[$language] MyStream: $it" }, - ) - } -} diff --git a/src/pt/pobreflix/src/eu/kanade/tachiyomi/animeextension/pt/pobreflix/extractors/PlayerFlixExtractor.kt b/src/pt/pobreflix/src/eu/kanade/tachiyomi/animeextension/pt/pobreflix/extractors/PlayerFlixExtractor.kt deleted file mode 100644 index 0dab9340..00000000 --- a/src/pt/pobreflix/src/eu/kanade/tachiyomi/animeextension/pt/pobreflix/extractors/PlayerFlixExtractor.kt +++ /dev/null @@ -1,35 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.pt.pobreflix.extractors - -import eu.kanade.tachiyomi.animesource.model.Video -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.util.asJsoup -import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking -import okhttp3.Headers -import okhttp3.OkHttpClient - -class PlayerFlixExtractor( - private val client: OkHttpClient, - private val defaultHeaders: Headers, - private val genericExtractor: (String, String) -> List<Video>, -) { - fun videosFromUrl(url: String): List<Video> { - val doc = client.newCall(GET(url, defaultHeaders)).execute().asJsoup() - - val items = doc.select("#hostList div.buttonLoadHost").mapNotNull { - val url = it.attr("onclick") - .substringAfter('"', "") - .substringBefore('"') - ?: return@mapNotNull null - - val language = if (it.hasClass("hostDub")) { - "Dublado" - } else { - "Legendado" - } - - language to url // (Language, videoId) - } - - return items.parallelCatchingFlatMapBlocking { genericExtractor(it.second, it.first) } - } -} diff --git a/src/pt/pobreflix/src/eu/kanade/tachiyomi/animeextension/pt/pobreflix/extractors/SuperFlixExtractor.kt b/src/pt/pobreflix/src/eu/kanade/tachiyomi/animeextension/pt/pobreflix/extractors/SuperFlixExtractor.kt deleted file mode 100644 index 92a2dcbe..00000000 --- a/src/pt/pobreflix/src/eu/kanade/tachiyomi/animeextension/pt/pobreflix/extractors/SuperFlixExtractor.kt +++ /dev/null @@ -1,134 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.pt.pobreflix.extractors - -import eu.kanade.tachiyomi.animesource.model.Video -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.network.POST -import eu.kanade.tachiyomi.network.await -import eu.kanade.tachiyomi.util.asJsoup -import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import okhttp3.FormBody -import okhttp3.Headers -import okhttp3.HttpUrl.Companion.toHttpUrl -import okhttp3.OkHttpClient -import uy.kohesive.injekt.injectLazy - -class SuperFlixExtractor( - private val client: OkHttpClient, - private val defaultHeaders: Headers, - private val genericExtractor: (String, String) -> List<Video>, - private val host: String = "https://superflixapi.dev", -) { - private val json: Json by injectLazy() - - fun videosFromUrl(url: String): List<Video> { - val links = linksFromUrl(url) - - val fixedLinks = links.parallelCatchingFlatMapBlocking { - val (language, linkUrl) = it - when { - linkUrl.contains("?vid=") -> linksFromPlayer(linkUrl, language) - else -> listOf(it) - } - } - - return fixedLinks.parallelCatchingFlatMapBlocking { genericExtractor(it.second, it.first) } - } - - private suspend fun linksFromPlayer(url: String, language: String): List<Pair<String, String>> { - val httpUrl = url.toHttpUrl() - val id = httpUrl.queryParameter("vid")!! - val headers = defaultHeaders.newBuilder() - .set("referer", "$host/") - .set("origin", host) - .build() - - val doc = client.newCall(GET(url, headers)).await().asJsoup() - - val baseUrl = "https://" + httpUrl.host - val apiUrl = "$baseUrl/ajax_sources.php" - - val apiHeaders = headers.newBuilder() - .set("referer", url) - .set("origin", baseUrl) - .set("X-Requested-With", "XMLHttpRequest") - .build() - - return doc.select("ul > li[data-order-value]").mapNotNull { - val name = it.attr("data-dropdown-value") - val order = it.attr("data-order-value") - - val formBody = FormBody.Builder() - .add("vid", id) - .add("alternative", name) - .add("ord", order) - .build() - - val req = client.newCall(POST(apiUrl, apiHeaders, formBody)).await() - .body.string() - - runCatching { - val iframeUrl = json.decodeFromString<PlayerLinkDto>(req).iframe!! - val iframeServer = iframeUrl.toHttpUrl().queryParameter("sv")!! - language to when (name) { - "1xbet" -> "https://watch.brplayer.site/watch?v=${iframeServer.trim('/')}" - else -> iframeServer - } - }.getOrNull() - } - } - - @Serializable - data class PlayerLinkDto(val iframe: String? = null) - - private fun linksFromUrl(url: String): List<Pair<String, String>> { - val doc = client.newCall(GET(url, defaultHeaders)).execute().asJsoup() - - val items = doc.select("div.select_languages").mapNotNull { - val id = it.nextElementSibling() - ?.selectFirst("div[data-id]") - ?.attr("data-id") - ?: return@mapNotNull null - - val language = it.text() - .replace("Disponível", "") - .replace("disponível", "") - .replace("Apenas", "") - .replace("em", "") - .trim() - - language to id // (Language, videoId) - } - - val headers = defaultHeaders.newBuilder() - .set("Origin", host) - .set("Referer", url) - .set("X-Requested-With", "XMLHttpRequest") - .build() - - return items.mapNotNull { - runCatching { - it.first to getLink(it.second, headers)!! - }.getOrNull() - } - } - - private fun getLink(id: String, headers: Headers): String? { - val body = FormBody.Builder() - .add("action", "getPlayer") - .add("video_id", id) - .build() - - val res = client.newCall(POST("$host/api", headers, body)).execute() - .body.string() - - return json.decodeFromString<ApiResponseDto>(res).data?.video_url - } - - @Serializable - data class ApiResponseDto(val data: DataDto? = null) - - @Serializable - data class DataDto(val video_url: String? = null) -} diff --git a/src/pt/vizer/AndroidManifest.xml b/src/pt/vizer/AndroidManifest.xml deleted file mode 100644 index b9524492..00000000 --- a/src/pt/vizer/AndroidManifest.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<manifest xmlns:android="http://schemas.android.com/apk/res/android"> - - <application> - <activity - android:name=".pt.vizer.VizerUrlActivity" - android:excludeFromRecents="true" - android:exported="true" - android:theme="@android:style/Theme.NoDisplay"> - <intent-filter> - <action android:name="android.intent.action.VIEW" /> - - <category android:name="android.intent.category.DEFAULT" /> - <category android:name="android.intent.category.BROWSABLE" /> - - <data - android:host="vizer.tv" - android:pathPattern="/..*/..*/..*" - android:scheme="https" /> - </intent-filter> - </activity> - </application> -</manifest> diff --git a/src/pt/vizer/build.gradle b/src/pt/vizer/build.gradle deleted file mode 100644 index f5ed1181..00000000 --- a/src/pt/vizer/build.gradle +++ /dev/null @@ -1,16 +0,0 @@ -ext { - extName = 'Vizer.tv' - extClass = '.Vizer' - extVersionCode = 24 - isNsfw = true -} - -apply from: "$rootDir/common.gradle" - -dependencies { - implementation(project(':lib:fireplayer-extractor')) - implementation(project(':lib:mixdrop-extractor')) - implementation(project(':lib:playlist-utils')) - implementation(project(':lib:streamtape-extractor')) - implementation(libs.jsunpacker) -} diff --git a/src/pt/vizer/res/mipmap-hdpi/ic_launcher.png b/src/pt/vizer/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index ae34c91d..00000000 Binary files a/src/pt/vizer/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/vizer/res/mipmap-mdpi/ic_launcher.png b/src/pt/vizer/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index b78a281b..00000000 Binary files a/src/pt/vizer/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/vizer/res/mipmap-xhdpi/ic_launcher.png b/src/pt/vizer/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index e07ab4a7..00000000 Binary files a/src/pt/vizer/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/vizer/res/mipmap-xxhdpi/ic_launcher.png b/src/pt/vizer/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index a5654df6..00000000 Binary files a/src/pt/vizer/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/vizer/res/mipmap-xxxhdpi/ic_launcher.png b/src/pt/vizer/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index b904558c..00000000 Binary files a/src/pt/vizer/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/vizer/src/eu/kanade/tachiyomi/animeextension/pt/vizer/Vizer.kt b/src/pt/vizer/src/eu/kanade/tachiyomi/animeextension/pt/vizer/Vizer.kt deleted file mode 100644 index caa95dbb..00000000 --- a/src/pt/vizer/src/eu/kanade/tachiyomi/animeextension/pt/vizer/Vizer.kt +++ /dev/null @@ -1,359 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.pt.vizer - -import android.app.Application -import androidx.preference.ListPreference -import androidx.preference.PreferenceScreen -import eu.kanade.tachiyomi.animeextension.pt.vizer.VizerFilters.FilterSearchParams -import eu.kanade.tachiyomi.animeextension.pt.vizer.dto.EpisodeListDto -import eu.kanade.tachiyomi.animeextension.pt.vizer.dto.HostersDto -import eu.kanade.tachiyomi.animeextension.pt.vizer.dto.SearchItemDto -import eu.kanade.tachiyomi.animeextension.pt.vizer.dto.SearchResultDto -import eu.kanade.tachiyomi.animeextension.pt.vizer.dto.VideoDto -import eu.kanade.tachiyomi.animeextension.pt.vizer.dto.VideoListDto -import eu.kanade.tachiyomi.animeextension.pt.vizer.interceptor.WebViewResolver -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.AnimeHttpSource -import eu.kanade.tachiyomi.lib.fireplayerextractor.FireplayerExtractor -import eu.kanade.tachiyomi.lib.mixdropextractor.MixDropExtractor -import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.network.POST -import eu.kanade.tachiyomi.network.awaitSuccess -import eu.kanade.tachiyomi.network.interceptor.rateLimitHost -import eu.kanade.tachiyomi.util.asJsoup -import eu.kanade.tachiyomi.util.parallelCatchingFlatMap -import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking -import eu.kanade.tachiyomi.util.parseAs -import okhttp3.HttpUrl.Companion.toHttpUrl -import okhttp3.MediaType.Companion.toMediaType -import okhttp3.Request -import okhttp3.RequestBody.Companion.toRequestBody -import okhttp3.Response -import org.jsoup.nodes.Element -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get -import kotlin.time.Duration.Companion.seconds - -class Vizer : ConfigurableAnimeSource, AnimeHttpSource() { - - override val name = "Vizer.tv" - - override val baseUrl = "https://novizer.com" - private val apiUrl = "$baseUrl/includes/ajax" - - override val lang = "pt-BR" - - override val supportsLatest = true - - override fun headersBuilder() = super.headersBuilder().add("Referer", "$baseUrl/") - - private val episodesClient by lazy { - client.newBuilder().rateLimitHost(baseUrl.toHttpUrl(), 1, 1.5.seconds).build() - } - - private val preferences by lazy { - Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) - } - - private val webViewResolver by lazy { WebViewResolver(headers) } - - // ============================== Popular =============================== - override fun popularAnimeRequest(page: Int): Request { - val pageType = preferences.getString(PREF_POPULAR_PAGE_KEY, PREF_POPULAR_PAGE_DEFAULT)!! - val params = FilterSearchParams( - orderBy = "vzViews", - orderWay = "desc", - type = pageType, - ) - return searchAnimeRequest(page, "", params) - } - - override fun popularAnimeParse(response: Response): AnimesPage { - val result = response.parseAs<SearchResultDto>() - val animes = result.items.values.map(::animeFromObject) - val hasNext = result.quantity == 35 - return AnimesPage(animes, hasNext) - } - - private fun animeFromObject(item: SearchItemDto) = SAnime.create().apply { - val (urlslug, imgslug) = when { - item.status.isBlank() -> Pair("filme", "movies") - else -> Pair("serie", "series") - } - url = "/$urlslug/online/${item.url}" - title = item.title - status = when (item.status) { - "Retornando" -> SAnime.ONGOING - else -> SAnime.COMPLETED - } - thumbnail_url = "$baseUrl/content/$imgslug/posterPt/342/${item.id}.webp" - } - - // =============================== Latest =============================== - override fun latestUpdatesRequest(page: Int) = apiRequest("getHomeSliderSeries=1") - - override fun latestUpdatesParse(response: Response): AnimesPage { - val parsedData = response.parseAs<SearchResultDto>() - val animes = parsedData.items.values.map(::animeFromObject) - return AnimesPage(animes, false) - } - - // =============================== Search =============================== - override fun getFilterList(): AnimeFilterList = VizerFilters.FILTER_LIST - - override fun searchAnimeParse(response: Response) = popularAnimeParse(response) - - override suspend fun getSearchAnime(page: Int, query: String, filters: AnimeFilterList): AnimesPage { - return if (query.startsWith(PREFIX_SEARCH)) { - val path = query.removePrefix(PREFIX_SEARCH).replace("/", "/online/") - client.newCall(GET("$baseUrl/$path")) - .awaitSuccess() - .use(::searchAnimeByPathParse) - } else { - super.getSearchAnime(page, query, filters) - } - } - - private fun searchAnimeByPathParse(response: Response): AnimesPage { - val details = animeDetailsParse(response).apply { - setUrlWithoutDomain(response.request.url.toString()) - initialized = true - } - - return AnimesPage(listOf(details), false) - } - - override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request { - val params = VizerFilters.getSearchParameters(filters) - return searchAnimeRequest(page, query, params) - } - - private fun searchAnimeRequest(page: Int, query: String, params: FilterSearchParams): Request { - val urlBuilder = "$apiUrl/ajaxPagination.php".toHttpUrl().newBuilder() - .addQueryParameter("page", "${page - 1}") - .addQueryParameter("categoryFilterYearMin", params.minYear) - .addQueryParameter("categoryFilterYearMax", params.maxYear) - .addQueryParameter("categoryFilterOrderBy", params.orderBy) - .addQueryParameter("categoryFilterOrderWay", params.orderWay) - .apply { - if (query.isNotBlank()) addQueryParameter("search", query) - - when (params.type) { - "Movies" -> { - addQueryParameter("saga", "0") - addQueryParameter("categoriesListMovies", params.genre) - } - else -> { - addQueryParameter("categoriesListSeries", params.genre) - val isAnime = params.type == "anime" - addQueryParameter("anime", if (isAnime) "1" else "0") - } - } - } - return GET(urlBuilder.build(), headers) - } - - // =========================== Anime Details ============================ - override fun animeDetailsParse(response: Response) = SAnime.create().apply { - val doc = response.asJsoup() - setUrlWithoutDomain(doc.location()) - title = doc.selectFirst("section.ai > h2")!!.text() - thumbnail_url = doc.selectFirst("meta[property=og:image]")!!.attr("content") - - description = buildString { - append(doc.selectFirst("span.desc")!!.text() + "\n") - doc.selectFirst("div.year")?.also { append("\nAno: ", it.text()) } - doc.selectFirst("div.tm")?.also { append("\nDuração: ", it.text()) } - doc.selectFirst("a.rating")?.also { append("\nNota: ", it.text()) } - } - } - - // ============================== Episodes ============================== - private fun getSeasonEps(seasonElement: Element): List<SEpisode> { - val id = seasonElement.attr("data-season-id") - val sname = seasonElement.text() - val response = episodesClient.newCall(apiRequest("getEpisodes=$id")).execute() - val episodes = response.parseAs<EpisodeListDto>().episodes - .values - .filter { it.released === true } - .map { - SEpisode.create().apply { - name = "$sname: Ep ${it.name}".run { - if (!it.title.contains("Episode ")) { - this + " - ${it.title}" - } else { - this - } - } - episode_number = it.name.toFloatOrNull() ?: 0F - url = it.id - } - } - return episodes - } - - override fun episodeListParse(response: Response): List<SEpisode> { - val doc = response.asJsoup() - val seasons = doc.select("div.seasons div.list div.item[data-season-id]") - return if (seasons.size > 0) { - seasons.flatMap(::getSeasonEps).reversed() - } else { - listOf( - SEpisode.create().apply { - name = "Filme" - episode_number = 1F - url = response.request.url.toString() - }, - ) - } - } - - // ============================ Video Links ============================= - override fun videoListRequest(episode: SEpisode): Request { - val url = episode.url - return if (url.startsWith("https")) { - // Its an real url, maybe from a movie - GET(url, headers) - } else { - // Fake url, its an ID that will be used to get episode languages - // (sub/dub) and then return the video link - apiRequest("getEpisodeData=$url") - } - } - - override fun videoListParse(response: Response): List<Video> { - val body = response.body.string() - val videoObjectList = if (body.startsWith("{")) { - body.parseAs<VideoListDto>().videos.values.toList() - } else { - val doc = response.asJsoup(body) - doc.select("div.audios div[data-load-player]").mapNotNull { - try { - val movieHosters = it.attr("data-players").parseAs<HostersDto>() - val movieId = it.attr("data-load-player") - val movieLang = if (it.hasClass("legendado")) "1" else "0" - VideoDto(movieId, movieLang).apply { hosters = movieHosters } - } catch (_: Throwable) { null } - } - } - - return videoObjectList.parallelCatchingFlatMapBlocking(::getVideosFromObject) - } - - private val mixdropExtractor by lazy { MixDropExtractor(client) } - private val streamtapeExtractor by lazy { StreamTapeExtractor(client) } - private val fireplayerExtractor by lazy { FireplayerExtractor(client) } - - private suspend fun getVideosFromObject(videoObj: VideoDto): List<Video> { - val hosters = videoObj.hosters ?: return emptyList() - - val langPrefix = if (videoObj.lang == "1") "LEG" else "DUB" - - return hosters.iterator().parallelCatchingFlatMap { (name, status) -> - // Always try the warezcdn - if (status != 3 && name != "warezcdn") return@parallelCatchingFlatMap emptyList() - val url = getPlayerUrl(videoObj.id, name) - if (url.isNullOrBlank()) { - return@parallelCatchingFlatMap emptyList() - } - when (name) { - "mixdrop" -> mixdropExtractor.videosFromUrl(url, langPrefix) - "streamtape" -> streamtapeExtractor.videosFromUrl(url, "StreamTape($langPrefix)") - "warezcdn" -> fireplayerExtractor.videosFromUrl(url, videoNameGen = { "WarezCDN($langPrefix) - $it" }) - else -> emptyList() - } - } - } - - // ============================== Settings ============================== - override fun setupPreferenceScreen(screen: PreferenceScreen) { - ListPreference(screen.context).apply { - key = PREF_POPULAR_PAGE_KEY - title = PREF_POPULAR_PAGE_TITLE - entries = PREF_POPULAR_PAGE_ENTRIES - entryValues = PREF_POPULAR_PAGE_VALUES - setDefaultValue(PREF_POPULAR_PAGE_DEFAULT) - summary = "%s" - }.also(screen::addPreference) - - ListPreference(screen.context).apply { - key = PREF_PLAYER_KEY - title = PREF_PLAYER_TITLE - entries = PREF_PLAYER_ARRAY - entryValues = PREF_PLAYER_ARRAY - setDefaultValue(PREF_PLAYER_DEFAULT) - summary = "%s" - }.also(screen::addPreference) - - ListPreference(screen.context).apply { - key = PREF_LANGUAGE_KEY - title = PREF_LANGUAGE_TITLE - entries = PREF_LANGUAGE_ENTRIES - entryValues = PREF_LANGUAGE_VALUES - setDefaultValue(PREF_LANGUAGE_DEFAULT) - summary = "%s" - }.also(screen::addPreference) - } - - // ============================= Utilities ============================== - private val noRedirectClient = client.newBuilder().followRedirects(false).build() - - private fun getPlayerUrl(id: String, name: String): String? { - return webViewResolver.getUrl("$baseUrl/embed/getEmbed.php?id=$id&sv=$name", "$baseUrl/termos") - } - - private fun apiRequest(body: String): Request { - val reqBody = body.toRequestBody("application/x-www-form-urlencoded".toMediaType()) - val newHeaders = headersBuilder().add("x-requested-with", "XMLHttpRequest").build() - return POST("$apiUrl/publicFunctions.php", newHeaders, body = reqBody) - } - - override fun List<Video>.sort(): List<Video> { - val player = preferences.getString(PREF_PLAYER_KEY, PREF_PLAYER_DEFAULT)!! - val language = preferences.getString(PREF_LANGUAGE_KEY, PREF_LANGUAGE_DEFAULT)!! - return sortedWith( - compareBy( - { it.quality.contains(player) }, - { it.quality.contains(language) }, - ), - ).reversed() - } - - companion object { - private const val PREF_POPULAR_PAGE_KEY = "pref_popular_page" - private const val PREF_POPULAR_PAGE_DEFAULT = "movie" - private const val PREF_POPULAR_PAGE_TITLE = "Página de Populares" - private val PREF_POPULAR_PAGE_ENTRIES = arrayOf( - "Animes", - "Filmes", - "Séries", - ) - private val PREF_POPULAR_PAGE_VALUES = arrayOf( - "anime", - "movie", - "serie", - ) - - private const val PREF_PLAYER_KEY = "pref_player" - private const val PREF_PLAYER_DEFAULT = "MixDrop" - private const val PREF_PLAYER_TITLE = "Player/Server favorito" - private val PREF_PLAYER_ARRAY = arrayOf( - "MixDrop", - "StreamTape", - "WarezCDN", - ) - - private const val PREF_LANGUAGE_KEY = "pref_language" - private const val PREF_LANGUAGE_DEFAULT = "LEG" - private const val PREF_LANGUAGE_TITLE = "Língua/tipo preferido" - private val PREF_LANGUAGE_ENTRIES = arrayOf("Legendado", "Dublado") - private val PREF_LANGUAGE_VALUES = arrayOf("LEG", "DUB") - - const val PREFIX_SEARCH = "path:" - } -} diff --git a/src/pt/vizer/src/eu/kanade/tachiyomi/animeextension/pt/vizer/VizerFilters.kt b/src/pt/vizer/src/eu/kanade/tachiyomi/animeextension/pt/vizer/VizerFilters.kt deleted file mode 100644 index 3940da20..00000000 --- a/src/pt/vizer/src/eu/kanade/tachiyomi/animeextension/pt/vizer/VizerFilters.kt +++ /dev/null @@ -1,116 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.pt.vizer - -import eu.kanade.tachiyomi.animeextension.pt.vizer.VizerFilters.VizerFiltersData.CURRENT_YEAR -import eu.kanade.tachiyomi.animesource.model.AnimeFilter -import eu.kanade.tachiyomi.animesource.model.AnimeFilterList -import java.util.Calendar - -object VizerFilters { - open class QueryPartFilter( - displayName: String, - val vals: Array<Pair<String, String>>, - ) : AnimeFilter.Select<String>( - displayName, - vals.map { it.first }.toTypedArray(), - ) { - - fun toQueryPart() = vals[state].second - } - - private inline fun <reified R> AnimeFilterList.asQueryPart(): String { - return (first { it is R } as QueryPartFilter).toQueryPart() - } - - class TypeFilter : QueryPartFilter("Tipo", VizerFiltersData.TYPES) - class MinYearFilter : QueryPartFilter("Ano (min)", VizerFiltersData.MIN_YEARS) - class MaxYearFilter : QueryPartFilter("Ano (max)", VizerFiltersData.MAX_YEARS) - class GenreFilter : QueryPartFilter("Categoria", VizerFiltersData.GENRES) - - class SortFilter : AnimeFilter.Sort( - "Ordernar por", - VizerFiltersData.ORDERS.map { it.first }.toTypedArray(), - Selection(0, false), - ) - - val FILTER_LIST get() = AnimeFilterList( - TypeFilter(), - MinYearFilter(), - MaxYearFilter(), - GenreFilter(), - SortFilter(), - ) - - data class FilterSearchParams( - val type: String = "anime", - val minYear: String = "1890", - val maxYear: String = CURRENT_YEAR.toString(), - val genre: String = "all", - val orderBy: String = "rating", - val orderWay: String = "desc", - ) - - internal fun getSearchParameters(filters: AnimeFilterList): FilterSearchParams { - if (filters.isEmpty()) return FilterSearchParams() - - val sortFilter = filters.firstOrNull { it is SortFilter } as? SortFilter - val (orderBy, ascending) = sortFilter?.state?.run { - val order = VizerFiltersData.ORDERS[index].second - val orderWay = if (ascending) "asc" else "desc" - - Pair(order, orderWay) - } ?: Pair("rating", "desc") - - return FilterSearchParams( - filters.asQueryPart<TypeFilter>(), - filters.asQueryPart<MinYearFilter>(), - filters.asQueryPart<MaxYearFilter>(), - filters.asQueryPart<GenreFilter>(), - orderBy, - ascending, - ) - } - - private object VizerFiltersData { - val TYPES = arrayOf( - Pair("Animes", "anime"), - Pair("Filmes", "Movies"), - Pair("Series", "Series"), - ) - val CURRENT_YEAR by lazy { - Calendar.getInstance()[Calendar.YEAR] - } - val MAX_YEARS = (CURRENT_YEAR downTo 1890).map { - Pair(it.toString(), it.toString()) - }.toTypedArray() - - val MIN_YEARS = MAX_YEARS.reversed().toTypedArray() - - val ORDERS = arrayOf( - Pair("Popularidade", "vzViews"), - Pair("Ano", "year"), - Pair("Título", "title"), - Pair("Rating", "rating"), - ) - - val GENRES = arrayOf( - Pair("Todas", "all"), - Pair("Animação", "animacao"), - Pair("Aventura", "aventura"), - Pair("Ação", "acao"), - Pair("Comédia", "comedia"), - Pair("Crime", "crime"), - Pair("Documentário", "documentario"), - Pair("Drama", "drama"), - Pair("Família", "familia"), - Pair("Fantasia", "fantasia"), - Pair("Faroeste", "faroeste"), - Pair("Guerra", "guerra"), - Pair("LGBTQ+", "lgbt"), - Pair("Mistério", "misterio"), - Pair("Músical", "musical"), - Pair("Romance", "romance"), - Pair("Suspense", "suspense"), - Pair("Terror", "terror"), - ) - } -} diff --git a/src/pt/vizer/src/eu/kanade/tachiyomi/animeextension/pt/vizer/VizerUrlActivity.kt b/src/pt/vizer/src/eu/kanade/tachiyomi/animeextension/pt/vizer/VizerUrlActivity.kt deleted file mode 100644 index be22e4b7..00000000 --- a/src/pt/vizer/src/eu/kanade/tachiyomi/animeextension/pt/vizer/VizerUrlActivity.kt +++ /dev/null @@ -1,42 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.pt.vizer - -import android.app.Activity -import android.content.ActivityNotFoundException -import android.content.Intent -import android.os.Bundle -import android.util.Log -import kotlin.system.exitProcess - -/** - * Springboard that accepts https://vizer.tv/[anime|filme|serie]/online/<slug> intents - * and redirects them to the main Aniyomi process. - */ -class VizerUrlActivity : Activity() { - - private val tag = "VizerUrlActivity" - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - val pathSegments = intent?.data?.pathSegments - if (pathSegments != null && pathSegments.size > 1) { - val query = "${pathSegments[0]}/${pathSegments[2]}" - val searchQuery = Vizer.PREFIX_SEARCH + query - val mainIntent = Intent().apply { - action = "eu.kanade.tachiyomi.ANIMESEARCH" - putExtra("query", searchQuery) - putExtra("filter", packageName) - } - - try { - startActivity(mainIntent) - } catch (e: ActivityNotFoundException) { - Log.e(tag, e.toString()) - } - } else { - Log.e(tag, "could not parse uri from intent $intent") - } - - finish() - exitProcess(0) - } -} diff --git a/src/pt/vizer/src/eu/kanade/tachiyomi/animeextension/pt/vizer/dto/VizerDto.kt b/src/pt/vizer/src/eu/kanade/tachiyomi/animeextension/pt/vizer/dto/VizerDto.kt deleted file mode 100644 index f8bf3c96..00000000 --- a/src/pt/vizer/src/eu/kanade/tachiyomi/animeextension/pt/vizer/dto/VizerDto.kt +++ /dev/null @@ -1,92 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.pt.vizer.dto - -import eu.kanade.tachiyomi.util.parseAs -import kotlinx.serialization.EncodeDefault -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.builtins.serializer -import kotlinx.serialization.json.JsonElement -import kotlinx.serialization.json.JsonPrimitive -import kotlinx.serialization.json.JsonTransformingSerializer -import kotlinx.serialization.json.booleanOrNull -import kotlinx.serialization.json.jsonPrimitive - -typealias FakeList<T> = Map<String, T> - -@Serializable -class SearchResultDto( - val quantity: Int = 0, - @EncodeDefault - @SerialName("list") - val items: FakeList<SearchItemDto> = emptyMap(), -) - -@Serializable -class SearchItemDto( - val id: String, - val title: String, - val url: String, - @EncodeDefault - val status: String = "", -) - -@Serializable -class EpisodeListDto( - @SerialName("list") - val episodes: FakeList<EpisodeItemDto>, -) - -@Serializable -class EpisodeItemDto( - val id: String, - val name: String, - @Serializable(with = BooleanSerializer::class) - val released: Boolean, - val title: String, -) - -@Serializable -class VideoListDto( - @SerialName("list") - val videos: FakeList<VideoDto>, -) - -@Serializable -class VideoDto( - val id: String, - val lang: String, - @SerialName("players") - private val players: String? = null, -) { - var hosters = try { - players?.parseAs<HostersDto>() - } catch (e: Throwable) { - null - } -} - -@Serializable -class HostersDto( - val mixdrop: Int = 0, - val streamtape: Int = 0, - val warezcdn: Int = 0, -) { - operator fun iterator(): List<Pair<String, Int>> { - return listOf( - "mixdrop" to mixdrop, - "streamtape" to streamtape, - "warezcdn" to warezcdn, - ) - } -} - -object BooleanSerializer : JsonTransformingSerializer<Boolean>(Boolean.serializer()) { - override fun transformDeserialize(element: JsonElement): JsonElement { - require(element is JsonPrimitive) - return if (element.jsonPrimitive.isString && element.jsonPrimitive.content == "true") { - JsonPrimitive(true) - } else { - JsonPrimitive(element.jsonPrimitive.booleanOrNull ?: false) - } - } -} diff --git a/src/pt/vizer/src/eu/kanade/tachiyomi/animeextension/pt/vizer/interceptor/WebViewResolver.kt b/src/pt/vizer/src/eu/kanade/tachiyomi/animeextension/pt/vizer/interceptor/WebViewResolver.kt deleted file mode 100644 index 177f2704..00000000 --- a/src/pt/vizer/src/eu/kanade/tachiyomi/animeextension/pt/vizer/interceptor/WebViewResolver.kt +++ /dev/null @@ -1,78 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.pt.vizer.interceptor - -import android.annotation.SuppressLint -import android.app.Application -import android.os.Handler -import android.os.Looper -import android.util.Log -import android.webkit.WebResourceRequest -import android.webkit.WebResourceResponse -import android.webkit.WebView -import android.webkit.WebViewClient -import okhttp3.Headers -import uy.kohesive.injekt.injectLazy -import java.util.concurrent.CountDownLatch -import java.util.concurrent.TimeUnit - -class WebViewResolver(private val globalHeaders: Headers) { - private val context: Application by injectLazy() - private val handler by lazy { Handler(Looper.getMainLooper()) } - private val tag by lazy { javaClass.simpleName } - - @SuppressLint("SetJavaScriptEnabled") - fun getUrl(origRequestUrl: String, baseUrl: String): String? { - val latch = CountDownLatch(1) - var webView: WebView? = null - var result: String? = null - - handler.post { - val webview = WebView(context) - webView = webview - with(webview.settings) { - javaScriptEnabled = true - domStorageEnabled = true - databaseEnabled = true - useWideViewPort = false - loadWithOverviewMode = false - userAgentString = globalHeaders["User-Agent"] - } - webview.webViewClient = object : WebViewClient() { - override fun shouldInterceptRequest( - view: WebView, - request: WebResourceRequest, - ): WebResourceResponse? { - val url = request.url.toString() - Log.d(tag, "Checking url $url") - if (VIDEO_REGEX.containsMatchIn(url)) { - result = url - latch.countDown() - } - return super.shouldInterceptRequest(view, request) - } - - override fun onPageFinished(view: WebView?, url: String?) { - Log.d(tag, "onPageFinished $url") - super.onPageFinished(view, url) - - view?.evaluateJavascript("document.body.innerHTML += '<iframe src=\"" + origRequestUrl + "\" scrolling=\"no\" frameborder=\"0\" allowfullscreen=\"\" webkitallowfullscreen=\"\" mozallowfullscreen=\"\"></iframe>'") {} - } - } - - webView?.loadUrl(baseUrl) - } - - latch.await(TIMEOUT_SEC, TimeUnit.SECONDS) - - handler.post { - webView?.stopLoading() - webView?.destroy() - webView = null - } - return result - } - - companion object { - const val TIMEOUT_SEC: Long = 25 - private val VIDEO_REGEX by lazy { Regex("//(mixdrop|streamtape|warezcdn)|/video/") } - } -} diff --git a/src/tr/turkanime/res/web_hi_res_512.png b/src/tr/turkanime/res/web_hi_res_512.png deleted file mode 100644 index 4f080baa..00000000 Binary files a/src/tr/turkanime/res/web_hi_res_512.png and /dev/null differ diff --git a/src/uk/uakino/ic_launcher-playstore.png b/src/uk/uakino/ic_launcher-playstore.png deleted file mode 100644 index 0df13731..00000000 Binary files a/src/uk/uakino/ic_launcher-playstore.png and /dev/null differ diff --git a/src/uk/ufdub/ic_launcher-playstore.png b/src/uk/ufdub/ic_launcher-playstore.png deleted file mode 100644 index 77a1ef3c..00000000 Binary files a/src/uk/ufdub/ic_launcher-playstore.png and /dev/null differ