german extensions: updates & fixes (#1266)

* german extensions: updates & fixes

- removed Anifreakz (website down)
- filmpalast: add upstream & filemoon extractor
- filmpalast: add latest
- fimpalast: streamtape block fix
- animetoast: set supportlatest to false
- streamcloud: set supportlatest to false

* Update build.gradle

* Update StreamCloud.kt
This commit is contained in:
LuftVerbot
2023-02-11 23:24:28 +01:00
committed by GitHub
parent c4d4a87a3e
commit 215e42f5a3
27 changed files with 75 additions and 301 deletions

View File

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="eu.kanade.tachiyomi.animeextension" />

View File

@ -1,13 +0,0 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'Anifreakz'
pkgNameSuffix = 'de.anifreakz'
extClass = '.Anifreakz'
extVersionCode = 1
libVersion = '13'
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

View File

@ -1,264 +0,0 @@
package eu.kanade.tachiyomi.animeextension.de.anifreakz
import android.app.Application
import android.content.SharedPreferences
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.de.anifreakz.extractors.AnimefreakzExtractor
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
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.network.POST
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Headers
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
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 kotlin.Exception
class Anifreakz : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val name = "Anifreakz"
override val baseUrl = "https://anifreakz.com"
override val lang = "de"
override val supportsLatest = false
override val client: OkHttpClient = network.cloudflareClient
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
override fun popularAnimeSelector(): String = "div.row.row-cols-md-5 div.col div.list-movie"
override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/series?filter={\"sorting\":\"popular\"}&page=$page")
override fun popularAnimeFromElement(element: Element): SAnime {
val anime = SAnime.create()
anime.setUrlWithoutDomain(element.select("a.list-media").attr("href"))
anime.thumbnail_url = element.select("a.list-media div.media.media-cover").attr("data-src")
anime.title = element.select("div.list-caption a.list-title").text()
return anime
}
override fun popularAnimeNextPageSelector(): String = "li.page-item:last-child a"
// episodes
override fun episodeListRequest(anime: SAnime): Request {
return GET("$baseUrl${anime.url}", headers = Headers.headersOf("if-modified-since", ""))
}
override fun episodeListSelector() = throw Exception("not used")
override fun episodeListParse(response: Response): List<SEpisode> {
val document = response.asJsoup()
val url = document.select("meta[property=\"og:url\"]").attr("content")
val episodeList = mutableListOf<SEpisode>()
if (url.contains("/serie/")) {
val seasonElements = document.select("div.episodes.tab-content div.tab-pane")
seasonElements.forEach {
val episode = parseEpisodesFromSeries(it)
episodeList.addAll(episode)
}
} else {
val episode = SEpisode.create()
episode.name = document.select("div.caption-content h1").text()
episode.episode_number = 1F
episode.setUrlWithoutDomain(document.select("link[rel=canonical]").attr("href"))
episodeList.add(episode)
}
return episodeList.reversed()
}
private fun parseEpisodesFromSeries(element: Element): List<SEpisode> {
val season = element.attr("id")
.substringAfter("season-")
val episodeElements = element.select("a")
return episodeElements.map { episodeFromElement(it, season) }
}
override fun episodeFromElement(element: Element): SEpisode = throw Exception("not Used")
private fun episodeFromElement(element: Element, season: String): SEpisode {
val episode = SEpisode.create()
episode.setUrlWithoutDomain(element.attr("href"))
episode.episode_number = element.select("div.episode").text()
.substringBefore(".Episode").toFloat()
val folge = element.select("div.episode").text()
.substringBefore(".Episode")
episode.name = "Staffel $season Folge $folge : " + element.select("div.name").text()
return episode
}
// Video Extractor
override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup()
return videosFromElement(document)
}
private fun videosFromElement(document: Document): List<Video> {
val videoList = mutableListOf<Video>()
if (!document.select("div.dropdown-menu[aria-labelledby=\"videoSource\"] button").isNullOrEmpty()) {
val langs = document.select("div.dropdown-menu[aria-labelledby=\"videoSource\"] button")
langs.forEach {
val id = it.attr("data-embed")
val hoster = it.select("span.language").text()
val hostdoc = client.newCall(POST("$baseUrl/ajax/embed", body = "id=$id&captcha=".toRequestBody("application/x-www-form-urlencoded".toMediaType()))).execute().asJsoup()
if (it.select("span.name").text().contains("GerSub")) {
val quality = "$hoster SUB"
val url = hostdoc.select("iframe").attr("src")
val video = AnimefreakzExtractor(client).videoFromUrl(url, quality)
if (video != null) {
videoList.addAll(video)
}
} else {
val quality = "$hoster DUB"
val url = hostdoc.select("iframe").attr("src")
val video = AnimefreakzExtractor(client).videoFromUrl(url, quality)
if (video != null) {
videoList.addAll(video)
}
}
}
} else {
val id = document.select("div.nav-player-select a.dropdown-toggle").attr("data-embed")
val hostdoc = client.newCall(POST("$baseUrl/ajax/embed", body = "id=$id&captcha=".toRequestBody("application/x-www-form-urlencoded".toMediaType()))).execute().asJsoup()
val hoster = hostdoc.select("iframe").attr("src")
.substringAfter("https://").substringBefore(".")
if (document.select("div.nav-player-select a.dropdown-toggle span").text().contains("GerSub")) {
val quality = "$hoster SUB"
val url = hostdoc.select("iframe").attr("src")
val video = AnimefreakzExtractor(client).videoFromUrl(url, quality)
if (video != null) {
videoList.addAll(video)
}
} else {
val quality = "$hoster DUB"
val url = hostdoc.select("iframe").attr("src")
val video = AnimefreakzExtractor(client).videoFromUrl(url, quality)
if (video != null) {
videoList.addAll(video)
}
}
}
return videoList.reversed()
}
override fun List<Video>.sort(): List<Video> {
val subPreference = preferences.getString("preferred_sub", null)
if (subPreference != null) {
val newList = mutableListOf<Video>()
var preferred = 0
for (video in this) {
if (video.quality.contains(subPreference)) {
newList.add(preferred, video)
preferred++
} else {
newList.add(video)
}
}
return newList
}
return this
}
override fun videoListSelector() = throw Exception("not used")
override fun videoFromElement(element: Element) = throw Exception("not used")
override fun videoUrlParse(document: Document) = throw Exception("not used")
// Search
override fun searchAnimeFromElement(element: Element): SAnime {
val anime = SAnime.create()
anime.setUrlWithoutDomain(element.select("a.list-media").attr("href"))
anime.thumbnail_url = element.select("a.list-media div.media.media-cover").attr("data-src")
// .substringAfter("url(\"").substringBefore("\");")
anime.title = element.select("div.list-caption a.list-title").text()
return anime
}
override fun searchAnimeNextPageSelector(): String? = null
override fun searchAnimeSelector(): String = "div.row.row-cols-5 div.col div.list-movie"
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request = GET("$baseUrl/search/$query")
// Details
override fun animeDetailsParse(document: Document): SAnime {
val anime = SAnime.create()
val url = document.select("meta[property=\"og:url\"]").attr("content")
if (url.contains("/serie/")) {
anime.thumbnail_url = document.select("div.media.media-cover").attr("data-src")
anime.title = document.select("div.col-md-9 div.pl-md-4 h1").text()
anime.genre = document.select("div.col-md-9 div.pl-md-4 div.categories a").joinToString(", ") { it.text() }
anime.description = document.select("div.text div.text-content").text()
anime.author = document.select("div.featured-attr div.text a").joinToString(", ") { it.text() }
anime.status = parseStatus(document.select("span.stato").text())
return anime
} else {
anime.thumbnail_url = document.select("div.media.media-cover").attr("data-src")
anime.title = document.select("div.caption-content h1").text()
anime.genre = document.select("div.col-md-9 div.pl-md-4 div.categories a").joinToString(", ") { it.text() }
anime.description = document.select("script[type=\"application/ld+json\"]").toString()
.substringAfter("\"reviewBody\": \"").substringBefore("\"")
anime.author = document.select("div.text[data-more] a").joinToString(", ") { it.text() }
anime.status = parseStatus(document.select("span.stato").text())
return anime
}
}
private fun parseStatus(status: String?) = when {
status == null -> SAnime.UNKNOWN
status.contains("Returning Series", ignoreCase = true) -> SAnime.ONGOING
else -> SAnime.COMPLETED
}
// Latest
override fun latestUpdatesNextPageSelector(): String = throw Exception("Not used")
override fun latestUpdatesFromElement(element: Element): SAnime = throw Exception("Not used")
override fun latestUpdatesRequest(page: Int): Request = throw Exception("Not used")
override fun latestUpdatesSelector(): String = throw Exception("Not used")
// Preferences
override fun setupPreferenceScreen(screen: PreferenceScreen) {
val subPref = ListPreference(screen.context).apply {
key = "preferred_sub"
title = "Standardmäßig Sub oder Dub?"
entries = arrayOf("Sub", "Dub")
entryValues = arrayOf("SUB", "DUB")
setDefaultValue("SUB")
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()
}
}
screen.addPreference(subPref)
}
}

View File

@ -6,7 +6,7 @@ ext {
extName = 'AnimeToast'
pkgNameSuffix = 'de.animetoast'
extClass = '.AnimeToast'
extVersionCode = 5
extVersionCode = 6
libVersion = '13'
}

View File

@ -32,7 +32,7 @@ class AnimeToast : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val lang = "de"
override val supportsLatest = true
override val supportsLatest = false
override val client: OkHttpClient = network.cloudflareClient

View File

@ -6,7 +6,7 @@ ext {
extName = 'FilmPalast'
pkgNameSuffix = 'de.filmpalast'
extClass = '.FilmPalast'
extVersionCode = 7
extVersionCode = 8
libVersion = '13'
}

View File

@ -6,6 +6,8 @@ import androidx.preference.ListPreference
import androidx.preference.MultiSelectListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.de.filmpalast.extractors.EvoloadExtractor
import eu.kanade.tachiyomi.animeextension.de.filmpalast.extractors.FilemoonExtractor
import eu.kanade.tachiyomi.animeextension.de.filmpalast.extractors.UpstreamExtractor
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.model.SAnime
@ -64,7 +66,7 @@ class FilmPalast : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val document = response.asJsoup()
val episodeList = mutableListOf<SEpisode>()
val episode = SEpisode.create()
episode.name = document.select("h2.bgDark").text()
episode.name = "Film"
episode.episode_number = 1F
episode.setUrlWithoutDomain(document.select("link[rel=canonical]").attr("href"))
episodeList.add(episode)
@ -83,7 +85,7 @@ class FilmPalast : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
private fun videosFromElement(document: Document): List<Video> {
val videoList = mutableListOf<Video>()
val elements = document.select("ul.currentStreamLinks > li > a")
val hosterSelection = preferences.getStringSet("hoster_selection", setOf("voe", "stape", "evo"))
val hosterSelection = preferences.getStringSet("hoster_selection", setOf("voe", "stape", "evo", "up", "moon"))
for (element in elements) {
val url = element.attr("abs:href")
when {
@ -94,6 +96,12 @@ class FilmPalast : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
videoList.add(video)
}
}
url.contains("https://upstream.to") && hosterSelection?.contains("up") == true -> {
val videos = UpstreamExtractor(client).videoFromUrl(url)
if (videos != null) {
videoList.addAll(videos)
}
}
}
}
for (element in elements) {
@ -107,7 +115,8 @@ class FilmPalast : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
) {
linkRegex.find(this.select("script:containsData(document.getElementById('robotlink'))").toString())?.let {
val quality = "Streamtape"
val videoUrl = "https://streamtape.com/get_video?${it.groupValues[1]}&stream=1".replace("""" + '""", "")
val id = it.groupValues[1].replace("%27+%20(%27xcdb", "")
val videoUrl = "https://streamtape.com/get_video?$id&stream=1".replace("""" + '""", "")
videoList.add(Video(videoUrl, quality, videoUrl))
}
}
@ -126,6 +135,12 @@ class FilmPalast : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
videoList.addAll(EvoloadExtractor(client).videoFromUrl(url, quality))
}
}
url.contains("filemoon.sx") && hosterSelection?.contains("moon") == true -> {
val videos = FilemoonExtractor(client).videoFromUrl(url)
if (videos != null) {
videoList.addAll(videos)
}
}
}
}
@ -207,13 +222,20 @@ class FilmPalast : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
// Latest
override fun latestUpdatesNextPageSelector(): String = throw Exception("Not used")
override fun latestUpdatesNextPageSelector(): String = "a.pageing:contains(vorwärts)"
override fun latestUpdatesFromElement(element: Element): SAnime = throw Exception("Not used")
override fun latestUpdatesFromElement(element: Element): SAnime {
val anime = SAnime.create()
anime.setUrlWithoutDomain(element.attr("href"))
val file = element.select("img").attr("src")
anime.thumbnail_url = "$baseUrl$file"
anime.title = element.attr("title")
return anime
}
override fun latestUpdatesRequest(page: Int): Request = throw Exception("Not used")
override fun latestUpdatesRequest(page: Int): Request = GET("$baseUrl/page/$page")
override fun latestUpdatesSelector(): String = throw Exception("Not used")
override fun latestUpdatesSelector(): String = "article.liste > a"
// Preferences
@ -221,8 +243,8 @@ class FilmPalast : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val hosterPref = ListPreference(screen.context).apply {
key = "preferred_hoster"
title = "Standard-Hoster"
entries = arrayOf("Voe", "Streamtape", "Evoload")
entryValues = arrayOf("https://voe.sx", "https://streamtape.com", "https://evoload.io")
entries = arrayOf("Voe", "Streamtape", "Evoload", "Upstream", "Filemoon")
entryValues = arrayOf("https://voe.sx", "https://streamtape.com", "https://evoload.io", "https://upstream.to", "https://filemoon.sx")
setDefaultValue("https://voe.sx")
summary = "%s"
@ -236,9 +258,9 @@ class FilmPalast : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val subSelection = MultiSelectListPreference(screen.context).apply {
key = "hoster_selection"
title = "Hoster auswählen"
entries = arrayOf("Voe", "Streamtape", "Evoload")
entryValues = arrayOf("voe", "stape", "evo")
setDefaultValue(setOf("voe", "stape", "evo"))
entries = arrayOf("Voe", "Streamtape", "Evoload", "Upstream", "Filemoon")
entryValues = arrayOf("voe", "stape", "evo", "up", "moon")
setDefaultValue(setOf("voe", "stape", "evo", "up", "moon"))
setOnPreferenceChangeListener { _, newValue ->
preferences.edit().putStringSet(key, newValue as Set<String>).commit()

View File

@ -1,13 +1,13 @@
package eu.kanade.tachiyomi.animeextension.de.anifreakz.extractors
package eu.kanade.tachiyomi.animeextension.de.filmpalast.extractors
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient
class AnimefreakzExtractor(private val client: OkHttpClient) {
class FilemoonExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String, prequality: String): MutableList<Video>? {
fun videoFromUrl(url: String): MutableList<Video>? {
try {
val jsE = client.newCall(GET(url)).execute().asJsoup().selectFirst("script:containsData(eval)").data()
@ -17,7 +17,7 @@ class AnimefreakzExtractor(private val client: OkHttpClient) {
val videoList = mutableListOf<Video>()
masterPlaylist.substringAfter("#EXT-X-STREAM-INF:").split("#EXT-X-STREAM-INF:")
.forEach {
val quality = "$prequality : " + it.substringAfter("RESOLUTION=").substringAfter("x").substringBefore(",") + "p "
val quality = "Filemoon:" + it.substringAfter("RESOLUTION=").substringAfter("x").substringBefore(",") + "p "
val videoUrl = it.substringAfter("\n").substringBefore("\n")
videoList.add(Video(videoUrl, quality, videoUrl))
}

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.animeextension.de.anifreakz.extractors
package eu.kanade.tachiyomi.animeextension.de.filmpalast.extractors
import java.util.regex.Pattern
import kotlin.math.pow

View File

@ -0,0 +1,31 @@
package eu.kanade.tachiyomi.animeextension.de.filmpalast.extractors
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Headers
import okhttp3.OkHttpClient
class UpstreamExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String): MutableList<Video>? {
try {
val jsE = client.newCall(GET(url)).execute().asJsoup().selectFirst("script:containsData(eval)").data()
val masterUrl = JsUnpacker(jsE).unpack().toString()
.substringAfter("{file:\"").substringBefore("\"}")
val masterBase = masterUrl.substringBefore("master")
val masterPlaylist = client.newCall(GET(masterUrl)).execute().body!!.string()
val videoList = mutableListOf<Video>()
masterPlaylist.substringAfter("#EXT-X-STREAM-INF:").split("#EXT-X-STREAM-INF:")
.forEach {
val quality = "Upstream:" + it.substringAfter("RESOLUTION=").substringAfter("x").substringBefore(",") + "p "
val videoUrl = masterBase + it.substringAfter("\n").substringBefore("\n")
videoList.add(Video(videoUrl, quality, videoUrl, headers = Headers.headersOf("origin", "https://upstream.to", "referer", "https://upstream.to/")))
}
return videoList
} catch (e: Exception) {
return null
}
}
}

View File

@ -6,7 +6,7 @@ ext {
extName = 'StreamCloud'
pkgNameSuffix = 'de.streamcloud'
extClass = '.StreamCloud'
extVersionCode = 3
extVersionCode = 4
libVersion = '13'
}

View File

@ -32,7 +32,7 @@ class StreamCloud : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val lang = "de"
override val supportsLatest = true
override val supportsLatest = false
override val client: OkHttpClient = network.cloudflareClient