feat(src/de): Remove login for serienstream and aniworld (#3201)

This commit is contained in:
LuftVerbot 2024-04-28 22:24:12 +02:00 committed by GitHub
parent 79c7f052d2
commit ebb2163465
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 14 additions and 754 deletions

View File

@ -1,5 +1,5 @@
ext { ext {
extName = 'AniWorld (experimental)' extName = 'AniWorld'
extClass = '.AniWorld' extClass = '.AniWorld'
extVersionCode = 23 extVersionCode = 23
} }

View File

@ -1,7 +1,5 @@
package eu.kanade.tachiyomi.animeextension.de.aniworld package eu.kanade.tachiyomi.animeextension.de.aniworld
import android.content.SharedPreferences
object AWConstants { object AWConstants {
const val NAME_DOOD = "Doodstream" const val NAME_DOOD = "Doodstream"
const val NAME_STAPE = "Streamtape" const val NAME_STAPE = "Streamtape"
@ -29,14 +27,4 @@ object AWConstants {
const val PREFERRED_HOSTER = "preferred_hoster" const val PREFERRED_HOSTER = "preferred_hoster"
const val PREFERRED_LANG = "preferred_lang" const val PREFERRED_LANG = "preferred_lang"
const val HOSTER_SELECTION = "hoster_selection" const val HOSTER_SELECTION = "hoster_selection"
const val LOGIN_TITLE = "E-Mail-Adresse"
const val LOGIN_DEFAULT = ""
const val PASSWORD_TITLE = "Passwort"
const val PASSWORD_DEFAULT = ""
const val LOGIN_URL = "https://aniworld.to/login"
fun getPrefBaseLogin(preferences: SharedPreferences): String = preferences.getString(LOGIN_TITLE, LOGIN_DEFAULT)!!
fun getPrefBasePassword(preferences: SharedPreferences): String = preferences.getString(PASSWORD_TITLE, PASSWORD_DEFAULT)!!
} }

View File

@ -2,10 +2,6 @@ package eu.kanade.tachiyomi.animeextension.de.aniworld
import android.app.Application import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
import android.text.InputType
import android.util.Log
import android.widget.Toast
import androidx.preference.EditTextPreference
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.MultiSelectListPreference import androidx.preference.MultiSelectListPreference
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
@ -30,7 +26,6 @@ import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive import kotlinx.serialization.json.jsonPrimitive
import okhttp3.FormBody import okhttp3.FormBody
import okhttp3.Headers import okhttp3.Headers
import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
@ -41,15 +36,14 @@ import uy.kohesive.injekt.injectLazy
class AniWorld : ConfigurableAnimeSource, ParsedAnimeHttpSource() { class AniWorld : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val name = "AniWorld (experimental)" override val name = "AniWorld"
override val baseUrl = "https://aniworld.to" override val baseUrl = "https://aniworld.to"
private val baseLogin by lazy { AWConstants.getPrefBaseLogin(preferences) }
private val basePassword by lazy { AWConstants.getPrefBasePassword(preferences) }
override val lang = "de" override val lang = "de"
override val id: Long = 8286900189409315836
override val supportsLatest = true override val supportsLatest = true
private val preferences: SharedPreferences by lazy { private val preferences: SharedPreferences by lazy {
@ -60,14 +54,8 @@ class AniWorld : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
.addInterceptor(DdosGuardInterceptor(network.client)) .addInterceptor(DdosGuardInterceptor(network.client))
.build() .build()
private val authClient = network.client.newBuilder()
.addInterceptor(AniWorldInterceptor(client, preferences))
.build()
private val json: Json by injectLazy() private val json: Json by injectLazy()
val context = Injekt.get<Application>()
// ===== POPULAR ANIME ===== // ===== POPULAR ANIME =====
override fun popularAnimeSelector(): String = "div.seriesListContainer div" override fun popularAnimeSelector(): String = "div.seriesListContainer div"
@ -78,7 +66,6 @@ class AniWorld : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
} }
override fun popularAnimeFromElement(element: Element): SAnime { override fun popularAnimeFromElement(element: Element): SAnime {
context
val anime = SAnime.create() val anime = SAnime.create()
val linkElement = element.selectFirst("a")!! val linkElement = element.selectFirst("a")!!
anime.url = linkElement.attr("href") anime.url = linkElement.attr("href")
@ -190,14 +177,14 @@ class AniWorld : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
private fun parseEpisodesFromSeries(element: Element): List<SEpisode> { private fun parseEpisodesFromSeries(element: Element): List<SEpisode> {
val seasonId = element.attr("abs:href") val seasonId = element.attr("abs:href")
val episodesHtml = authClient.newCall(GET(seasonId)).execute().asJsoup() val episodesHtml = client.newCall(GET(seasonId)).execute().asJsoup()
val episodeElements = episodesHtml.select("table.seasonEpisodesList tbody tr") val episodeElements = episodesHtml.select("table.seasonEpisodesList tbody tr")
return episodeElements.map { episodeFromElement(it) } return episodeElements.map { episodeFromElement(it) }
} }
private fun parseMoviesFromSeries(element: Element): List<SEpisode> { private fun parseMoviesFromSeries(element: Element): List<SEpisode> {
val seasonId = element.attr("abs:href") val seasonId = element.attr("abs:href")
val episodesHtml = authClient.newCall(GET(seasonId)).execute().asJsoup() val episodesHtml = client.newCall(GET(seasonId)).execute().asJsoup()
val episodeElements = episodesHtml.select("table.seasonEpisodesList tbody tr") val episodeElements = episodesHtml.select("table.seasonEpisodesList tbody tr")
return episodeElements.map { episodeFromElement(it) } return episodeElements.map { episodeFromElement(it) }
} }
@ -228,8 +215,6 @@ class AniWorld : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val redirectlink = document.select("ul.row li") val redirectlink = document.select("ul.row li")
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
val hosterSelection = preferences.getStringSet(AWConstants.HOSTER_SELECTION, null) val hosterSelection = preferences.getStringSet(AWConstants.HOSTER_SELECTION, null)
val redirectInterceptor = client.newBuilder().addInterceptor(RedirectInterceptor()).build()
val jsInterceptor = client.newBuilder().addInterceptor(JsInterceptor()).build()
redirectlink.forEach { redirectlink.forEach {
val langkey = it.attr("data-lang-key") val langkey = it.attr("data-lang-key")
val language = getlanguage(langkey) val language = getlanguage(langkey)
@ -238,19 +223,13 @@ class AniWorld : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
if (hosterSelection != null) { if (hosterSelection != null) {
when { when {
hoster.contains("VOE") && hosterSelection.contains(AWConstants.NAME_VOE) -> { hoster.contains("VOE") && hosterSelection.contains(AWConstants.NAME_VOE) -> {
var url = redirectInterceptor.newCall(GET(redirectgs)).execute().request.url.toString() val url = client.newCall(GET(redirectgs)).execute().request.url.toString()
if (url.contains("payload") || url.contains(redirectgs)) {
url = recapbypass(jsInterceptor, redirectgs)
}
videoList.addAll(VoeExtractor(client).videosFromUrl(url, "($language) ")) videoList.addAll(VoeExtractor(client).videosFromUrl(url, "($language) "))
} }
hoster.contains("Doodstream") && hosterSelection.contains(AWConstants.NAME_DOOD) -> { hoster.contains("Doodstream") && hosterSelection.contains(AWConstants.NAME_DOOD) -> {
val quality = "Doodstream $language" val quality = "Doodstream $language"
var url = redirectInterceptor.newCall(GET(redirectgs)).execute().request.url.toString() val url = client.newCall(GET(redirectgs)).execute().request.url.toString()
if (url.contains("payload") || url.contains(redirectgs)) {
url = recapbypass(jsInterceptor, redirectgs)
}
val video = DoodExtractor(client).videoFromUrl(url, quality) val video = DoodExtractor(client).videoFromUrl(url, quality)
if (video != null) { if (video != null) {
videoList.add(video) videoList.add(video)
@ -259,10 +238,7 @@ class AniWorld : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
hoster.contains("Streamtape") && hosterSelection.contains(AWConstants.NAME_STAPE) -> { hoster.contains("Streamtape") && hosterSelection.contains(AWConstants.NAME_STAPE) -> {
val quality = "Streamtape $language" val quality = "Streamtape $language"
var url = redirectInterceptor.newCall(GET(redirectgs)).execute().request.url.toString() val url = client.newCall(GET(redirectgs)).execute().request.url.toString()
if (url.contains("payload") || url.contains(redirectgs)) {
url = recapbypass(jsInterceptor, redirectgs)
}
val video = StreamTapeExtractor(client).videoFromUrl(url, quality) val video = StreamTapeExtractor(client).videoFromUrl(url, quality)
if (video != null) { if (video != null) {
videoList.add(video) videoList.add(video)
@ -270,10 +246,7 @@ class AniWorld : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
} }
hoster.contains("Vidoza") && hosterSelection.contains(AWConstants.NAME_VIZ) -> { hoster.contains("Vidoza") && hosterSelection.contains(AWConstants.NAME_VIZ) -> {
val quality = "Vidoza $language" val quality = "Vidoza $language"
var url = redirectInterceptor.newCall(GET(redirectgs)).execute().request.url.toString() val url = client.newCall(GET(redirectgs)).execute().request.url.toString()
if (url.contains("payload") || url.contains(redirectgs)) {
url = recapbypass(jsInterceptor, redirectgs)
}
val video = VidozaExtractor(client).videoFromUrl(url, quality) val video = VidozaExtractor(client).videoFromUrl(url, quality)
if (video != null) { if (video != null) {
videoList.add(video) videoList.add(video)
@ -285,12 +258,6 @@ class AniWorld : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
return videoList return videoList
} }
private fun recapbypass(jsInterceptor: OkHttpClient, redirectgs: String): String {
val token = jsInterceptor.newCall(GET(redirectgs)).execute().request.header("url").toString()
val url = client.newCall(GET("$redirectgs?token=$token&original=")).execute().request.url.toString()
return url
}
private fun getlanguage(langkey: String): String? { private fun getlanguage(langkey: String): String? {
when { when {
langkey.contains("${AWConstants.KEY_GER_SUB}") -> { langkey.contains("${AWConstants.KEY_GER_SUB}") -> {
@ -394,37 +361,8 @@ class AniWorld : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
preferences.edit().putStringSet(key, newValue as Set<String>).commit() preferences.edit().putStringSet(key, newValue as Set<String>).commit()
} }
} }
screen.addPreference(screen.editTextPreference(AWConstants.LOGIN_TITLE, AWConstants.LOGIN_DEFAULT, baseLogin, false, ""))
screen.addPreference(screen.editTextPreference(AWConstants.PASSWORD_TITLE, AWConstants.PASSWORD_DEFAULT, basePassword, true, ""))
screen.addPreference(subPref) screen.addPreference(subPref)
screen.addPreference(hosterPref) screen.addPreference(hosterPref)
screen.addPreference(hosterSelection) screen.addPreference(hosterSelection)
} }
private fun PreferenceScreen.editTextPreference(title: String, default: String, value: String, isPassword: Boolean = false, placeholder: String): EditTextPreference {
return EditTextPreference(context).apply {
key = title
this.title = title
summary = value.ifEmpty { placeholder }
this.setDefaultValue(default)
dialogTitle = title
if (isPassword) {
setOnBindEditTextListener {
it.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
}
}
setOnPreferenceChangeListener { _, newValue ->
try {
val res = preferences.edit().putString(title, newValue as String).commit()
Toast.makeText(context, "Starte Aniyomi neu, um die Einstellungen zu übernehmen.", Toast.LENGTH_LONG).show()
res
} catch (e: Exception) {
Log.e("Anicloud", "Fehler beim festlegen der Einstellung.", e)
false
}
}
}
}
} }

View File

@ -1,80 +0,0 @@
package eu.kanade.tachiyomi.animeextension.de.aniworld
import android.content.SharedPreferences
import android.util.Log
import android.webkit.CookieManager
import eu.kanade.tachiyomi.network.POST
import okhttp3.Cookie
import okhttp3.FormBody
import okhttp3.Headers
import okhttp3.HttpUrl
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response
class AniWorldInterceptor(private val client: OkHttpClient, private val preferences: SharedPreferences) : Interceptor {
private val cookieManager by lazy { CookieManager.getInstance() }
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
val cookies = cookieManager.getCookie(originalRequest.url.toString())
val oldCookie = if (cookies != null && cookies.isNotEmpty()) {
cookies.split(";").mapNotNull { Cookie.parse(originalRequest.url, it) }
} else {
emptyList()
}
val sessionCookie = oldCookie.firstOrNull { it.name == "rememberLogin" }
if (!sessionCookie?.value.isNullOrEmpty()) {
return chain.proceed(originalRequest)
}
val newCookie = getNewCookie(originalRequest.url)
// ?: throw Exception("Bitte im Browser oder in den Erweiterungs-Einstellungen einloggen.")
val newCookieHeader = buildString {
(oldCookie + newCookie).forEachIndexed { index, cookie ->
if (index > 0) append("; ")
if (cookie != null) {
append(cookie.name).append('=').append(cookie.value)
}
}
}
return chain.proceed(
originalRequest
.newBuilder()
.addHeader("cookie", newCookieHeader)
.build(),
)
}
private fun getNewCookie(url: HttpUrl): Cookie? {
val cookies = cookieManager.getCookie(url.toString())
val oldCookie = if (cookies != null && cookies.isNotEmpty()) {
cookies.split(";").mapNotNull { Cookie.parse(url, it) }
} else {
emptyList()
}
val sessionCookie = oldCookie.firstOrNull { it.name == "rememberLogin" }
if (!sessionCookie?.value.isNullOrEmpty()) {
return sessionCookie
}
val email = AWConstants.getPrefBaseLogin(preferences)
val password = AWConstants.getPrefBasePassword(preferences)
if (email.isEmpty() || password.isEmpty()) return null
val payload = FormBody.Builder()
.add("email", email)
.add("password", password)
.add("autoLogin", "on")
.build()
val headers = Headers.Builder()
.add("Upgrade-Insecure-Requests", "1")
.add("Referer", "https://aniworld.to")
// .add("user-agent", "Mozilla/5.0 (Linux; Android 12; Pixel 5 Build/SP2A.220405.004; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4896.127 Safari/537.36")
.build()
return client.newCall(POST(AWConstants.LOGIN_URL, body = payload, headers = headers)).execute().header("set-cookie")?.let {
Log.i("bruh", it)
Cookie.parse(url, it)
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,99 +0,0 @@
package eu.kanade.tachiyomi.animeextension.de.aniworld
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 eu.kanade.tachiyomi.network.GET
import okhttp3.Headers.Companion.toHeaders
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
class RedirectInterceptor : Interceptor {
private val context = Injekt.get<Application>()
private val handler by lazy { Handler(Looper.getMainLooper()) }
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
val newRequest = resolveWithWebView(originalRequest) ?: throw Exception("Versuche es später nochmal")
return chain.proceed(newRequest)
}
@SuppressLint("SetJavaScriptEnabled")
private fun resolveWithWebView(request: Request): Request? {
// We need to lock this thread until the WebView finds the challenge solution url, because
// OkHttp doesn't support asynchronous interceptors.
val latch = CountDownLatch(1)
var webView: WebView? = null
val origRequestUrl = request.url.toString()
val headers = request.headers.toMultimap().mapValues { it.value.getOrNull(0) ?: "" }.toMutableMap()
var newRequest: Request? = null
var test = true
handler.post {
val webview = WebView(context)
webView = webview
with(webview.settings) {
javaScriptEnabled = true
domStorageEnabled = true
databaseEnabled = true
useWideViewPort = false
loadWithOverviewMode = false
userAgentString = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:106.0) Gecko/20100101 Firefox/106.0"
}
webview.webViewClient = object : WebViewClient() {
override fun shouldInterceptRequest(
view: WebView,
request: WebResourceRequest,
): WebResourceResponse? {
if (request.url.toString().contains("payload")) {
newRequest = GET(request.url.toString(), request.requestHeaders.toHeaders())
latch.countDown()
} else if (request.url.toString().contains("https://aniworld.to/redirect/") && request.url.toString().contains("token")) {
newRequest = GET(request.url.toString(), request.requestHeaders.toHeaders())
latch.countDown()
} else {
test = false
}
if (test == false) {
newRequest = GET(origRequestUrl, headers.toHeaders())
latch.countDown()
}
return super.shouldInterceptRequest(view, request)
}
}
webView?.loadUrl(origRequestUrl, headers)
}
// Wait a reasonable amount of time to retrieve the solution. The minimum should be
// around 4 seconds but it can take more due to slow networks or server issues.
latch.await(12, TimeUnit.SECONDS)
handler.post {
webView?.stopLoading()
webView?.destroy()
webView = null
}
return newRequest
}
}

View File

@ -1,7 +1,7 @@
ext { ext {
extName = 'Serienstream' extName = 'Serienstream'
extClass = '.Serienstream' extClass = '.Serienstream'
extVersionCode = 17 extVersionCode = 18
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View File

@ -1,7 +1,5 @@
package eu.kanade.tachiyomi.animeextension.de.serienstream package eu.kanade.tachiyomi.animeextension.de.serienstream
import android.content.SharedPreferences
object SConstants { object SConstants {
const val NAME_DOOD = "Doodstream" const val NAME_DOOD = "Doodstream"
const val NAME_STAPE = "Streamtape" const val NAME_STAPE = "Streamtape"
@ -27,14 +25,4 @@ object SConstants {
const val PREFERRED_HOSTER = "preferred_hoster" const val PREFERRED_HOSTER = "preferred_hoster"
const val PREFERRED_LANG = "preferred_lang" const val PREFERRED_LANG = "preferred_lang"
const val HOSTER_SELECTION = "hoster_selection" const val HOSTER_SELECTION = "hoster_selection"
const val LOGIN_TITLE = "E-Mail-Adresse"
const val LOGIN_DEFAULT = ""
const val PASSWORD_TITLE = "Passwort"
const val PASSWORD_DEFAULT = ""
const val LOGIN_URL = "http://186.2.175.5/login"
fun getPrefBaseLogin(preferences: SharedPreferences): String = preferences.getString(LOGIN_TITLE, LOGIN_DEFAULT)!!
fun getPrefBasePassword(preferences: SharedPreferences): String = preferences.getString(PASSWORD_TITLE, PASSWORD_DEFAULT)!!
} }

View File

@ -2,10 +2,6 @@ package eu.kanade.tachiyomi.animeextension.de.serienstream
import android.app.Application import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
import android.text.InputType
import android.util.Log
import android.widget.Toast
import androidx.preference.EditTextPreference
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.MultiSelectListPreference import androidx.preference.MultiSelectListPreference
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
@ -22,7 +18,6 @@ import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
@ -44,9 +39,6 @@ class Serienstream : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val baseUrl = "http://186.2.175.5" override val baseUrl = "http://186.2.175.5"
private val baseLogin by lazy { SConstants.getPrefBaseLogin(preferences) }
private val basePassword by lazy { SConstants.getPrefBasePassword(preferences) }
override val lang = "de" override val lang = "de"
override val supportsLatest = true override val supportsLatest = true
@ -59,14 +51,8 @@ class Serienstream : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
.addInterceptor(DdosGuardInterceptor(network.client)) .addInterceptor(DdosGuardInterceptor(network.client))
.build() .build()
private val authClient = network.client.newBuilder()
.addInterceptor(SerienstreamInterceptor(client, preferences))
.build()
private val json: Json by injectLazy() private val json: Json by injectLazy()
val context = Injekt.get<Application>()
// ===== POPULAR ANIME ===== // ===== POPULAR ANIME =====
override fun popularAnimeSelector(): String = "div.seriesListContainer div" override fun popularAnimeSelector(): String = "div.seriesListContainer div"
@ -77,7 +63,6 @@ class Serienstream : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
} }
override fun popularAnimeFromElement(element: Element): SAnime { override fun popularAnimeFromElement(element: Element): SAnime {
context
val anime = SAnime.create() val anime = SAnime.create()
val linkElement = element.selectFirst("a")!! val linkElement = element.selectFirst("a")!!
anime.url = linkElement.attr("href") anime.url = linkElement.attr("href")
@ -187,14 +172,14 @@ class Serienstream : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
private fun parseEpisodesFromSeries(element: Element): List<SEpisode> { private fun parseEpisodesFromSeries(element: Element): List<SEpisode> {
val seasonId = element.attr("abs:href") val seasonId = element.attr("abs:href")
val episodesHtml = authClient.newCall(GET(seasonId)).execute().asJsoup() val episodesHtml = client.newCall(GET(seasonId)).execute().asJsoup()
val episodeElements = episodesHtml.select("table.seasonEpisodesList tbody tr") val episodeElements = episodesHtml.select("table.seasonEpisodesList tbody tr")
return episodeElements.map { episodeFromElement(it) } return episodeElements.map { episodeFromElement(it) }
} }
private fun parseMoviesFromSeries(element: Element): List<SEpisode> { private fun parseMoviesFromSeries(element: Element): List<SEpisode> {
val seasonId = element.attr("abs:href") val seasonId = element.attr("abs:href")
val episodesHtml = authClient.newCall(GET(seasonId)).execute().asJsoup() val episodesHtml = client.newCall(GET(seasonId)).execute().asJsoup()
val episodeElements = episodesHtml.select("table.seasonEpisodesList tbody tr") val episodeElements = episodesHtml.select("table.seasonEpisodesList tbody tr")
return episodeElements.map { episodeFromElement(it) } return episodeElements.map { episodeFromElement(it) }
} }
@ -222,7 +207,7 @@ class Serienstream : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun videoListParse(response: Response): List<Video> { override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup() val document = response.asJsoup()
val redirectlink = document.select("ul.row li") val redirectlink = document.select("div.hosterSiteVideo ul.row li")
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
val hosterSelection = preferences.getStringSet(SConstants.HOSTER_SELECTION, null) val hosterSelection = preferences.getStringSet(SConstants.HOSTER_SELECTION, null)
redirectlink.forEach { redirectlink.forEach {
@ -363,37 +348,8 @@ class Serienstream : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
preferences.edit().putStringSet(key, newValue as Set<String>).commit() preferences.edit().putStringSet(key, newValue as Set<String>).commit()
} }
} }
screen.addPreference(screen.editTextPreference(SConstants.LOGIN_TITLE, SConstants.LOGIN_DEFAULT, baseLogin, false, ""))
screen.addPreference(screen.editTextPreference(SConstants.PASSWORD_TITLE, SConstants.PASSWORD_DEFAULT, basePassword, true, ""))
screen.addPreference(subPref) screen.addPreference(subPref)
screen.addPreference(hosterPref) screen.addPreference(hosterPref)
screen.addPreference(hosterSelection) screen.addPreference(hosterSelection)
} }
private fun PreferenceScreen.editTextPreference(title: String, default: String, value: String, isPassword: Boolean = false, placeholder: String): EditTextPreference {
return EditTextPreference(context).apply {
key = title
this.title = title
summary = value.ifEmpty { placeholder }
this.setDefaultValue(default)
dialogTitle = title
if (isPassword) {
setOnBindEditTextListener {
it.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
}
}
setOnPreferenceChangeListener { _, newValue ->
try {
val res = preferences.edit().putString(title, newValue as String).commit()
Toast.makeText(context, "Starte Aniyomi neu, um die Einstellungen zu übernehmen.", Toast.LENGTH_LONG).show()
res
} catch (e: Exception) {
Log.e("SerienStream", "Fehler beim festlegen der Einstellung.", e)
false
}
}
}
}
} }

View File

@ -1,80 +0,0 @@
package eu.kanade.tachiyomi.animeextension.de.serienstream
import android.content.SharedPreferences
import android.util.Log
import android.webkit.CookieManager
import eu.kanade.tachiyomi.network.POST
import okhttp3.Cookie
import okhttp3.FormBody
import okhttp3.Headers
import okhttp3.HttpUrl
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response
class SerienstreamInterceptor(private val client: OkHttpClient, private val preferences: SharedPreferences) : Interceptor {
private val cookieManager by lazy { CookieManager.getInstance() }
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
val cookies = cookieManager.getCookie(originalRequest.url.toString())
val oldCookie = if (cookies != null && cookies.isNotEmpty()) {
cookies.split(";").mapNotNull { Cookie.parse(originalRequest.url, it) }
} else {
emptyList()
}
val sessionCookie = oldCookie.firstOrNull { it.name == "rememberLogin" }
if (!sessionCookie?.value.isNullOrEmpty()) {
return chain.proceed(originalRequest)
}
val newCookie = getNewCookie(originalRequest.url)
// ?: throw Exception("Bitte im Browser oder in den Erweiterungs-Einstellungen einloggen.")
val newCookieHeader = buildString {
(oldCookie + newCookie).forEachIndexed { index, cookie ->
if (index > 0) append("; ")
if (cookie != null) {
append(cookie.name).append('=').append(cookie.value)
}
}
}
return chain.proceed(
originalRequest
.newBuilder()
.addHeader("cookie", newCookieHeader)
.build(),
)
}
private fun getNewCookie(url: HttpUrl): Cookie? {
val cookies = cookieManager.getCookie(url.toString())
val oldCookie = if (cookies != null && cookies.isNotEmpty()) {
cookies.split(";").mapNotNull { Cookie.parse(url, it) }
} else {
emptyList()
}
val sessionCookie = oldCookie.firstOrNull { it.name == "rememberLogin" }
if (!sessionCookie?.value.isNullOrEmpty()) {
return sessionCookie
}
val email = SConstants.getPrefBaseLogin(preferences)
val password = SConstants.getPrefBasePassword(preferences)
if (email.isEmpty() || password.isEmpty()) return null
val payload = FormBody.Builder()
.add("email", email)
.add("password", password)
.add("autoLogin", "on")
.build()
val headers = Headers.Builder()
.add("Upgrade-Insecure-Requests", "1")
.add("Referer", "http://186.2.175.5")
// .add("user-agent", "Mozilla/5.0 (Linux; Android 12; Pixel 5 Build/SP2A.220405.004; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4896.127 Safari/537.36")
.build()
return client.newCall(POST(SConstants.LOGIN_URL, body = payload, headers = headers)).execute().header("set-cookie")?.let {
Log.i("bruh", it)
Cookie.parse(url, it)
}
}
}