refactor(global): Adapt to extlib v14 (#2759)
This commit is contained in:
@ -238,10 +238,10 @@ apply from: "$rootDir/common.gradle"
|
|||||||
| `pkgNameSuffix` | A unique suffix added to `eu.kanade.tachiyomi.animeextension`. The language and the site name should be enough. Remember your extension code implementation must be placed in this package. |
|
| `pkgNameSuffix` | A unique suffix added to `eu.kanade.tachiyomi.animeextension`. The language and the site name should be enough. Remember your extension code implementation must be placed in this package. |
|
||||||
| `extClass` | Points to the class that implements `AnimeSource`. You can use a relative path starting with a dot (the package name is the base path). This is used to find and instantiate the source(s). |
|
| `extClass` | Points to the class that implements `AnimeSource`. You can use a relative path starting with a dot (the package name is the base path). This is used to find and instantiate the source(s). |
|
||||||
| `extVersionCode` | The extension version code. This must be a positive integer and incremented with any change to the code. |
|
| `extVersionCode` | The extension version code. This must be a positive integer and incremented with any change to the code. |
|
||||||
| `libVersion` | (Optional, defaults to `13`) The version of the [extensions library](https://github.com/aniyomiorg/extensions-lib) used. |
|
| `libVersion` | (Optional, defaults to `14`) The version of the [extensions library](https://github.com/aniyomiorg/extensions-lib) used. |
|
||||||
| `containsNsfw` | (Optional, defaults to `false`) Flag to indicate that a source contains NSFW content. |
|
| `containsNsfw` | (Optional, defaults to `false`) Flag to indicate that a source contains NSFW content. |
|
||||||
|
|
||||||
The extension's version name is generated automatically by concatenating `libVersion` and `extVersionCode`. With the example used above, the version would be `13`.
|
The extension's version name is generated automatically by concatenating `libVersion` and `extVersionCode`. With the example used above, the version would be `14`.
|
||||||
|
|
||||||
### Core dependencies
|
### Core dependencies
|
||||||
|
|
||||||
@ -680,7 +680,7 @@ class AnimeSource : AnimeTheme(
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
override val client: OkHttpClient = network.client.newBuilder()
|
||||||
.ignoreAllSSLErrors()
|
.ignoreAllSSLErrors()
|
||||||
.proxy(Proxy(Proxy.Type.HTTP, InetSocketAddress("10.0.2.2", 8080)))
|
.proxy(Proxy(Proxy.Type.HTTP, InetSocketAddress("10.0.2.2", 8080)))
|
||||||
.build()
|
.build()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.android.application) apply false
|
alias(libs.plugins.android.application) apply false
|
||||||
alias(libs.plugins.kotlin.android) apply false
|
alias(libs.plugins.kotlin.android) apply false
|
||||||
alias(libs.plugins.kotlin.serialization) apply false
|
alias(libs.plugins.kotlin.serialization) apply false
|
||||||
alias(libs.plugins.kotlinter) apply false
|
alias(libs.plugins.kotlinter) apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,6 @@ class BurstCloudExtractor(private val client: OkHttpClient) {
|
|||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
}.getOrNull().orEmpty()
|
}.getOrNull().orEmpty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ class ChillxExtractor(private val client: OkHttpClient, private val headers: Hea
|
|||||||
private val REGEX_EVAL_KEY by lazy { Regex("""eval\(\S+\("(\S+)",\d+,"(\S+)",(\d+),(\d+),""") }
|
private val REGEX_EVAL_KEY by lazy { Regex("""eval\(\S+\("(\S+)",\d+,"(\S+)",(\d+),(\d+),""") }
|
||||||
private val REGEX_SOURCES by lazy { Regex("""sources:\s*\[\{"file":"([^"]+)""") }
|
private val REGEX_SOURCES by lazy { Regex("""sources:\s*\[\{"file":"([^"]+)""") }
|
||||||
private val REGEX_FILE by lazy { Regex("""file: ?"([^"]+)"""") }
|
private val REGEX_FILE by lazy { Regex("""file: ?"([^"]+)"""") }
|
||||||
private val REGEX_SOURCE by lazy { Regex("""source = ?"([^"]+)"""")}
|
private val REGEX_SOURCE by lazy { Regex("""source = ?"([^"]+)"""") }
|
||||||
|
|
||||||
// matches "[language]https://...,"
|
// matches "[language]https://...,"
|
||||||
private val REGEX_SUBS by lazy { Regex("""\[(.*?)\](.*?)"?\,""") }
|
private val REGEX_SUBS by lazy { Regex("""\[(.*?)\](.*?)"?\,""") }
|
||||||
@ -100,7 +100,6 @@ class ChillxExtractor(private val client: OkHttpClient, private val headers: Hea
|
|||||||
return bits.joinToString("") { Char(it.toInt(index) - offset).toString() }
|
return bits.joinToString("") { Char(it.toInt(index) - offset).toString() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class CryptoInfo(
|
data class CryptoInfo(
|
||||||
@SerialName("ct")
|
@SerialName("ct")
|
||||||
|
@ -5,7 +5,7 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
|||||||
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
|
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
|
||||||
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 kotlinx.serialization.decodeFromString
|
import eu.kanade.tachiyomi.util.parseAs
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.FormBody
|
import okhttp3.FormBody
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
@ -13,7 +13,6 @@ import okhttp3.HttpUrl.Companion.toHttpUrl
|
|||||||
import okhttp3.MediaType.Companion.toMediaType
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.RequestBody.Companion.toRequestBody
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
import okhttp3.Response
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
class DailymotionExtractor(private val client: OkHttpClient, private val headers: Headers) {
|
class DailymotionExtractor(private val client: OkHttpClient, private val headers: Headers) {
|
||||||
@ -133,8 +132,4 @@ class DailymotionExtractor(private val client: OkHttpClient, private val headers
|
|||||||
videoNameGen = { "$prefix$it" },
|
videoNameGen = { "$prefix$it" },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <reified T> Response.parseAs(): T {
|
|
||||||
return use { it.body.string() }.let(json::decodeFromString)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
package eu.kanade.tachiyomi.lib.fastreamextractor
|
package eu.kanade.tachiyomi.lib.fastreamextractor
|
||||||
|
|
||||||
|
import dev.datlag.jsunpacker.JsUnpacker
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
import eu.kanade.tachiyomi.animesource.model.Video
|
||||||
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
|
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
|
||||||
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 okhttp3.FormBody
|
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import okhttp3.FormBody
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.internal.commonEmptyHeaders
|
import okhttp3.internal.commonEmptyHeaders
|
||||||
import dev.datlag.jsunpacker.JsUnpacker
|
|
||||||
|
|
||||||
class FastreamExtractor(private val client: OkHttpClient, private val headers: Headers = commonEmptyHeaders) {
|
class FastreamExtractor(private val client: OkHttpClient, private val headers: Headers = commonEmptyHeaders) {
|
||||||
private val videoHeaders by lazy {
|
private val videoHeaders by lazy {
|
||||||
@ -35,8 +35,7 @@ class FastreamExtractor(private val client: OkHttpClient, private val headers: H
|
|||||||
}.build()
|
}.build()
|
||||||
val doc = client.newCall(POST(url, videoHeaders, body = form)).execute().use { it.asJsoup() }
|
val doc = client.newCall(POST(url, videoHeaders, body = form)).execute().use { it.asJsoup() }
|
||||||
doc.selectFirst("script:containsData(jwplayer):containsData(vplayer)") ?: return emptyList()
|
doc.selectFirst("script:containsData(jwplayer):containsData(vplayer)") ?: return emptyList()
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
firstDoc.selectFirst("script:containsData(jwplayer):containsData(vplayer)") ?: return emptyList()
|
firstDoc.selectFirst("script:containsData(jwplayer):containsData(vplayer)") ?: return emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,11 +3,11 @@ package eu.kanade.tachiyomi.lib.filemoonextractor
|
|||||||
import dev.datlag.jsunpacker.JsUnpacker
|
import dev.datlag.jsunpacker.JsUnpacker
|
||||||
import eu.kanade.tachiyomi.animesource.model.Track
|
import eu.kanade.tachiyomi.animesource.model.Track
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
import eu.kanade.tachiyomi.animesource.model.Video
|
||||||
|
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
|
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package eu.kanade.tachiyomi.lib.fusevideoextractor
|
package eu.kanade.tachiyomi.lib.fusevideoextractor
|
||||||
|
|
||||||
|
import android.util.Base64
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
import eu.kanade.tachiyomi.animesource.model.Video
|
||||||
|
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import android.util.Base64
|
|
||||||
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
|
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
@ -28,5 +28,4 @@ class FusevideoExtractor(private val client: OkHttpClient, private val headers:
|
|||||||
PlaylistUtils(client, newHeaders).extractFromHls(videoUrl, videoNameGen = { "${prefix}Fusevideo - $it" })
|
PlaylistUtils(client, newHeaders).extractFromHls(videoUrl, videoNameGen = { "${prefix}Fusevideo - $it" })
|
||||||
}.getOrDefault(emptyList())
|
}.getOrDefault(emptyList())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,20 +2,19 @@ package eu.kanade.tachiyomi.lib.gogostreamextractor
|
|||||||
|
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
import eu.kanade.tachiyomi.animesource.model.Video
|
||||||
|
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
|
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import java.lang.Exception
|
|
||||||
import java.util.Locale
|
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.lang.Exception
|
||||||
import javax.crypto.Cipher
|
import javax.crypto.Cipher
|
||||||
import javax.crypto.spec.IvParameterSpec
|
import javax.crypto.spec.IvParameterSpec
|
||||||
import javax.crypto.spec.SecretKeySpec
|
import javax.crypto.spec.SecretKeySpec
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
|
|
||||||
class GogoStreamExtractor(private val client: OkHttpClient) {
|
class GogoStreamExtractor(private val client: OkHttpClient) {
|
||||||
private val json: Json by injectLazy()
|
private val json: Json by injectLazy()
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package eu.kanade.tachiyomi.lib.gogostreamextractor
|
package eu.kanade.tachiyomi.lib.gogostreamextractor
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
@ -7,8 +7,8 @@ import eu.kanade.tachiyomi.util.asJsoup
|
|||||||
import okhttp3.Cookie
|
import okhttp3.Cookie
|
||||||
import okhttp3.CookieJar
|
import okhttp3.CookieJar
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.internal.commonEmptyRequestBody
|
import okhttp3.internal.commonEmptyRequestBody
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ class GoogleDriveExtractor(private val client: OkHttpClient, private val headers
|
|||||||
}.build()
|
}.build()
|
||||||
|
|
||||||
val docResp = noRedirectClient.newCall(
|
val docResp = noRedirectClient.newCall(
|
||||||
GET(itemUrl, headers = docHeaders)
|
GET(itemUrl, headers = docHeaders),
|
||||||
).execute()
|
).execute()
|
||||||
|
|
||||||
if (docResp.isRedirect) {
|
if (docResp.isRedirect) {
|
||||||
@ -60,7 +60,7 @@ class GoogleDriveExtractor(private val client: OkHttpClient, private val headers
|
|||||||
}.build()
|
}.build()
|
||||||
|
|
||||||
val newUrl = noRedirectClient.newCall(
|
val newUrl = noRedirectClient.newCall(
|
||||||
POST(downloadUrl, headers = postHeaders, body = commonEmptyRequestBody)
|
POST(downloadUrl, headers = postHeaders, body = commonEmptyRequestBody),
|
||||||
).execute().use { it.headers["location"] ?: downloadUrl }
|
).execute().use { it.headers["location"] ?: downloadUrl }
|
||||||
|
|
||||||
return videoFromRedirect(newUrl, videoName, itemSize, cookieJar)
|
return videoFromRedirect(newUrl, videoName, itemSize, cookieJar)
|
||||||
@ -70,7 +70,7 @@ class GoogleDriveExtractor(private val client: OkHttpClient, private val headers
|
|||||||
downloadUrl: String,
|
downloadUrl: String,
|
||||||
videoName: String,
|
videoName: String,
|
||||||
itemSize: String,
|
itemSize: String,
|
||||||
cookieJar: GDriveCookieJar
|
cookieJar: GDriveCookieJar,
|
||||||
): List<Video> {
|
): List<Video> {
|
||||||
var newUrl = downloadUrl
|
var newUrl = downloadUrl
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ class GoogleDriveExtractor(private val client: OkHttpClient, private val headers
|
|||||||
}.build()
|
}.build()
|
||||||
|
|
||||||
var newResp = noRedirectClient.newCall(
|
var newResp = noRedirectClient.newCall(
|
||||||
GET(newUrl, headers = newHeaders)
|
GET(newUrl, headers = newHeaders),
|
||||||
).execute()
|
).execute()
|
||||||
|
|
||||||
var redirectCounter = 1
|
var redirectCounter = 1
|
||||||
@ -101,7 +101,7 @@ class GoogleDriveExtractor(private val client: OkHttpClient, private val headers
|
|||||||
}.build()
|
}.build()
|
||||||
|
|
||||||
newResp = noRedirectClient.newCall(
|
newResp = noRedirectClient.newCall(
|
||||||
GET(newUrl, headers = newHeaders)
|
GET(newUrl, headers = newHeaders),
|
||||||
).execute()
|
).execute()
|
||||||
redirectCounter += 1
|
redirectCounter += 1
|
||||||
}
|
}
|
||||||
@ -120,8 +120,8 @@ class GoogleDriveExtractor(private val client: OkHttpClient, private val headers
|
|||||||
videoUrl.toString(),
|
videoUrl.toString(),
|
||||||
videoName + itemSize,
|
videoName + itemSize,
|
||||||
videoUrl.toString(),
|
videoUrl.toString(),
|
||||||
headers = videoHeaders
|
headers = videoHeaders,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,8 @@ package eu.kanade.tachiyomi.lib.javcoverfetcher
|
|||||||
|
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.preference.PreferenceScreen
|
||||||
|
import androidx.preference.SwitchPreferenceCompat
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
import eu.kanade.tachiyomi.network.POST
|
import eu.kanade.tachiyomi.network.POST
|
||||||
@ -13,13 +15,11 @@ import okhttp3.internal.commonEmptyHeaders
|
|||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import androidx.preference.PreferenceScreen
|
|
||||||
import androidx.preference.SwitchPreferenceCompat
|
|
||||||
|
|
||||||
object JavCoverFetcher {
|
object JavCoverFetcher {
|
||||||
|
|
||||||
private val CLIENT by lazy {
|
private val CLIENT by lazy {
|
||||||
Injekt.get<NetworkHelper>().cloudflareClient.newBuilder()
|
Injekt.get<NetworkHelper>().client.newBuilder()
|
||||||
.addInterceptor(::amazonAgeVerifyIntercept)
|
.addInterceptor(::amazonAgeVerifyIntercept)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
@ -149,5 +149,4 @@ object JavCoverFetcher {
|
|||||||
|
|
||||||
val SharedPreferences.fetchHDCovers
|
val SharedPreferences.fetchHDCovers
|
||||||
get() = getBoolean("JavCoverFetcherPref", false)
|
get() = getBoolean("JavCoverFetcherPref", false)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ import uy.kohesive.injekt.injectLazy
|
|||||||
class MegaCloudExtractor(
|
class MegaCloudExtractor(
|
||||||
private val client: OkHttpClient,
|
private val client: OkHttpClient,
|
||||||
private val headers: Headers,
|
private val headers: Headers,
|
||||||
private val preferences: SharedPreferences
|
private val preferences: SharedPreferences,
|
||||||
) {
|
) {
|
||||||
private val json: Json by injectLazy()
|
private val json: Json by injectLazy()
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ class MegaCloudExtractor(
|
|||||||
shouldUpdateKey = false
|
shouldUpdateKey = false
|
||||||
}
|
}
|
||||||
json.decodeFromString<List<List<Int>>>(
|
json.decodeFromString<List<List<Int>>>(
|
||||||
preferences.getString(PREF_KEY_KEY + type, PREF_KEY_DEFAULT)!!
|
preferences.getString(PREF_KEY_KEY + type, PREF_KEY_DEFAULT)!!,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,8 +79,8 @@ class MegaCloudExtractor(
|
|||||||
val var1 = match.groupValues[1]
|
val var1 = match.groupValues[1]
|
||||||
val var2 = match.groupValues[2]
|
val var2 = match.groupValues[2]
|
||||||
|
|
||||||
val regexVar1 = Regex(",${var1}=((?:0x)?([0-9a-fA-F]+))")
|
val regexVar1 = Regex(",$var1=((?:0x)?([0-9a-fA-F]+))")
|
||||||
val regexVar2 = Regex(",${var2}=((?:0x)?([0-9a-fA-F]+))")
|
val regexVar2 = Regex(",$var2=((?:0x)?([0-9a-fA-F]+))")
|
||||||
|
|
||||||
val matchVar1 = regexVar1.find(script)?.groupValues?.get(1)?.removePrefix("0x")
|
val matchVar1 = regexVar1.find(script)?.groupValues?.get(1)?.removePrefix("0x")
|
||||||
val matchVar2 = regexVar2.find(script)?.groupValues?.get(1)?.removePrefix("0x")
|
val matchVar2 = regexVar2.find(script)?.groupValues?.get(1)?.removePrefix("0x")
|
||||||
@ -135,7 +135,7 @@ class MegaCloudExtractor(
|
|||||||
masterUrl,
|
masterUrl,
|
||||||
videoNameGen = { "$name - $it - $type" },
|
videoNameGen = { "$name - $it - $type" },
|
||||||
subtitleList = subs2,
|
subtitleList = subs2,
|
||||||
referer = "https://${url.toHttpUrl().host}/"
|
referer = "https://${url.toHttpUrl().host}/",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,7 +159,6 @@ class MegaCloudExtractor(
|
|||||||
return VideoDto(decrypted, data.tracks)
|
return VideoDto(decrypted, data.tracks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class VideoDto(
|
data class VideoDto(
|
||||||
val sources: List<VideoLink>,
|
val sources: List<VideoLink>,
|
||||||
|
@ -15,7 +15,7 @@ class MixDropExtractor(private val client: OkHttpClient) {
|
|||||||
lang: String = "",
|
lang: String = "",
|
||||||
prefix: String = "",
|
prefix: String = "",
|
||||||
externalSubs: List<Track> = emptyList(),
|
externalSubs: List<Track> = emptyList(),
|
||||||
referer: String = DEFAULT_REFERER
|
referer: String = DEFAULT_REFERER,
|
||||||
): List<Video> {
|
): List<Video> {
|
||||||
val headers = Headers.headersOf("Referer", referer)
|
val headers = Headers.headersOf("Referer", referer)
|
||||||
val doc = client.newCall(GET(url, headers)).execute().use { it.asJsoup() }
|
val doc = client.newCall(GET(url, headers)).execute().use { it.asJsoup() }
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package eu.kanade.tachiyomi.lib.mp4uploadextractor
|
package eu.kanade.tachiyomi.lib.mp4uploadextractor
|
||||||
|
|
||||||
|
import dev.datlag.jsunpacker.JsUnpacker
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
import eu.kanade.tachiyomi.animesource.model.Video
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import dev.datlag.jsunpacker.JsUnpacker
|
|
||||||
|
|
||||||
class Mp4uploadExtractor(private val client: OkHttpClient) {
|
class Mp4uploadExtractor(private val client: OkHttpClient) {
|
||||||
fun videosFromUrl(url: String, headers: Headers, prefix: String = "", suffix: String = ""): List<Video> {
|
fun videosFromUrl(url: String, headers: Headers, prefix: String = "", suffix: String = ""): List<Video> {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package eu.kanade.tachiyomi.lib.okruextractor
|
package eu.kanade.tachiyomi.lib.okruextractor
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
import eu.kanade.tachiyomi.animesource.model.Video
|
||||||
|
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
|
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
|
|
||||||
class OkruExtractor(private val client: OkHttpClient) {
|
class OkruExtractor(private val client: OkHttpClient) {
|
||||||
@ -37,7 +37,6 @@ class OkruExtractor(private val client: OkHttpClient) {
|
|||||||
"ondemandDash" in videoString -> {
|
"ondemandDash" in videoString -> {
|
||||||
val playlistUrl = videoString.extractLink("ondemandDash")
|
val playlistUrl = videoString.extractLink("ondemandDash")
|
||||||
playlistUtils.extractFromDash(playlistUrl, videoNameGen = { it -> "Okru:$it".addPrefix(prefix) })
|
playlistUtils.extractFromDash(playlistUrl, videoNameGen = { it -> "Okru:$it".addPrefix(prefix) })
|
||||||
|
|
||||||
}
|
}
|
||||||
else -> videosFromJson(videoString, prefix, fixQualities)
|
else -> videosFromJson(videoString, prefix, fixQualities)
|
||||||
}
|
}
|
||||||
@ -53,7 +52,6 @@ class OkruExtractor(private val client: OkHttpClient) {
|
|||||||
.substringBefore("\\\"")
|
.substringBefore("\\\"")
|
||||||
.replace("\\\\u0026", "&")
|
.replace("\\\\u0026", "&")
|
||||||
|
|
||||||
|
|
||||||
private fun videosFromJson(videoString: String, prefix: String = "", fixQualities: Boolean = true): List<Video> {
|
private fun videosFromJson(videoString: String, prefix: String = "", fixQualities: Boolean = true): List<Video> {
|
||||||
val arrayData = videoString.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
val arrayData = videoString.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||||
.substringBefore("]")
|
.substringBefore("]")
|
||||||
|
@ -43,7 +43,7 @@ class PlaylistUtils(private val client: OkHttpClient, private val headers: Heade
|
|||||||
{ _, _, _ -> videoHeaders },
|
{ _, _, _ -> videoHeaders },
|
||||||
videoNameGen,
|
videoNameGen,
|
||||||
subtitleList,
|
subtitleList,
|
||||||
audioList
|
audioList,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,8 +90,13 @@ class PlaylistUtils(private val client: OkHttpClient, private val headers: Heade
|
|||||||
if (PLAYLIST_SEPARATOR !in masterPlaylist) {
|
if (PLAYLIST_SEPARATOR !in masterPlaylist) {
|
||||||
return listOf(
|
return listOf(
|
||||||
Video(
|
Video(
|
||||||
playlistUrl, videoNameGen("Video"), playlistUrl, headers = masterHeaders, subtitleTracks = subtitleList, audioTracks = audioList
|
playlistUrl,
|
||||||
)
|
videoNameGen("Video"),
|
||||||
|
playlistUrl,
|
||||||
|
headers = masterHeaders,
|
||||||
|
subtitleTracks = subtitleList,
|
||||||
|
audioTracks = audioList,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,16 +112,16 @@ class PlaylistUtils(private val client: OkHttpClient, private val headers: Heade
|
|||||||
// Get subtitles
|
// Get subtitles
|
||||||
val subtitleTracks = subtitleList + SUBTITLE_REGEX.findAll(masterPlaylist).mapNotNull {
|
val subtitleTracks = subtitleList + SUBTITLE_REGEX.findAll(masterPlaylist).mapNotNull {
|
||||||
Track(
|
Track(
|
||||||
getAbsoluteUrl(it.groupValues[2], playlistUrl, masterUrlBasePath ) ?: return@mapNotNull null,
|
getAbsoluteUrl(it.groupValues[2], playlistUrl, masterUrlBasePath) ?: return@mapNotNull null,
|
||||||
it.groupValues[1]
|
it.groupValues[1],
|
||||||
)
|
)
|
||||||
}.toList()
|
}.toList()
|
||||||
|
|
||||||
// Get audio tracks
|
// Get audio tracks
|
||||||
val audioTracks = audioList + AUDIO_REGEX.findAll(masterPlaylist).mapNotNull {
|
val audioTracks = audioList + AUDIO_REGEX.findAll(masterPlaylist).mapNotNull {
|
||||||
Track(
|
Track(
|
||||||
getAbsoluteUrl(it.groupValues[2], playlistUrl, masterUrlBasePath ) ?: return@mapNotNull null,
|
getAbsoluteUrl(it.groupValues[2], playlistUrl, masterUrlBasePath) ?: return@mapNotNull null,
|
||||||
it.groupValues[1]
|
it.groupValues[1],
|
||||||
)
|
)
|
||||||
}.toList()
|
}.toList()
|
||||||
|
|
||||||
@ -127,15 +132,16 @@ class PlaylistUtils(private val client: OkHttpClient, private val headers: Heade
|
|||||||
.substringBefore(",") + "p"
|
.substringBefore(",") + "p"
|
||||||
|
|
||||||
val videoUrl = it.substringAfter("\n").substringBefore("\n").let { url ->
|
val videoUrl = it.substringAfter("\n").substringBefore("\n").let { url ->
|
||||||
getAbsoluteUrl(url, playlistUrl, masterUrlBasePath )
|
getAbsoluteUrl(url, playlistUrl, masterUrlBasePath)
|
||||||
} ?: return@mapNotNull null
|
} ?: return@mapNotNull null
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Video(
|
Video(
|
||||||
videoUrl, videoNameGen(resolution), videoUrl,
|
videoUrl,
|
||||||
|
videoNameGen(resolution),
|
||||||
|
videoUrl,
|
||||||
headers = videoHeadersGen(headers, referer, videoUrl),
|
headers = videoHeadersGen(headers, referer, videoUrl),
|
||||||
subtitleTracks = subtitleTracks, audioTracks = audioTracks
|
subtitleTracks = subtitleTracks,
|
||||||
|
audioTracks = audioTracks,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -146,7 +152,7 @@ class PlaylistUtils(private val client: OkHttpClient, private val headers: Heade
|
|||||||
url.startsWith("http") -> url
|
url.startsWith("http") -> url
|
||||||
url.startsWith("//") -> "https:$url"
|
url.startsWith("//") -> "https:$url"
|
||||||
url.startsWith("/") -> playlistUrl.toHttpUrl().newBuilder().encodedPath("/").build().toString()
|
url.startsWith("/") -> playlistUrl.toHttpUrl().newBuilder().encodedPath("/").build().toString()
|
||||||
.substringBeforeLast("/") + url
|
.substringBeforeLast("/") + url
|
||||||
else -> masterBase + url
|
else -> masterBase + url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,10 +198,10 @@ class PlaylistUtils(private val client: OkHttpClient, private val headers: Heade
|
|||||||
videoNameGen(videoRes) + " - ${formatBytes(bandwidth.toLongOrNull())}"
|
videoNameGen(videoRes) + " - ${formatBytes(bandwidth.toLongOrNull())}"
|
||||||
},
|
},
|
||||||
referer,
|
referer,
|
||||||
{ _, _ -> mpdHeaders},
|
{ _, _ -> mpdHeaders },
|
||||||
{ _, _, _ -> videoHeaders},
|
{ _, _, _ -> videoHeaders },
|
||||||
subtitleList,
|
subtitleList,
|
||||||
audioList
|
audioList,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,7 +248,7 @@ class PlaylistUtils(private val client: OkHttpClient, private val headers: Heade
|
|||||||
mpdHeadersGen,
|
mpdHeadersGen,
|
||||||
videoHeadersGen,
|
videoHeadersGen,
|
||||||
subtitleList,
|
subtitleList,
|
||||||
audioList
|
audioList,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,5 +36,4 @@ class SibnetExtractor(private val client: OkHttpClient) {
|
|||||||
|
|
||||||
return videoList
|
return videoList
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,8 @@ class StreamHubExtractor(private val client: OkHttpClient) {
|
|||||||
val document = client.newCall(GET(url)).execute().use { it.body.string() }
|
val document = client.newCall(GET(url)).execute().use { it.body.string() }
|
||||||
val id = REGEX_ID.find(document)?.groupValues?.get(1)
|
val id = REGEX_ID.find(document)?.groupValues?.get(1)
|
||||||
val sub = REGEX_SUB.find(document)?.groupValues?.get(1)
|
val sub = REGEX_SUB.find(document)?.groupValues?.get(1)
|
||||||
val masterUrl = "https://${sub}.streamhub.ink/hls/,${id},.urlset/master.m3u8"
|
val masterUrl = "https://$sub.streamhub.ink/hls/,$id,.urlset/master.m3u8"
|
||||||
return playlistUtils.extractFromHls(masterUrl, videoNameGen = { "${prefix}StreamHub - (${it})" })
|
return playlistUtils.extractFromHls(masterUrl, videoNameGen = { "${prefix}StreamHub - ($it)" })
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -15,7 +15,7 @@ class StreamVidExtractor(private val client: OkHttpClient) {
|
|||||||
val script = doc.selectFirst("script:containsData(eval):containsData(p,a,c,k,e,d)")?.data()
|
val script = doc.selectFirst("script:containsData(eval):containsData(p,a,c,k,e,d)")?.data()
|
||||||
?.let(JsUnpacker::unpackAndCombine)
|
?.let(JsUnpacker::unpackAndCombine)
|
||||||
?: return emptyList()
|
?: return emptyList()
|
||||||
val masterUrl = if(!sourceChange) {
|
val masterUrl = if (!sourceChange) {
|
||||||
script.substringAfter("sources:[{src:\"").substringBefore("\",")
|
script.substringAfter("sources:[{src:\"").substringBefore("\",")
|
||||||
} else {
|
} else {
|
||||||
script.substringAfter("sources:[{file:\"").substringBefore("\"")
|
script.substringAfter("sources:[{file:\"").substringBefore("\"")
|
||||||
|
@ -21,7 +21,9 @@ class StreamWishExtractor(private val client: OkHttpClient, private val headers:
|
|||||||
?.let { script ->
|
?.let { script ->
|
||||||
if (script.contains("eval(function(p,a,c")) {
|
if (script.contains("eval(function(p,a,c")) {
|
||||||
JsUnpacker.unpackAndCombine(script)
|
JsUnpacker.unpackAndCombine(script)
|
||||||
} else script
|
} else {
|
||||||
|
script
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val masterUrl = scriptBody
|
val masterUrl = scriptBody
|
||||||
|
@ -5,15 +5,13 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
|||||||
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
|
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import okhttp3.Headers
|
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.internal.commonEmptyHeaders
|
|
||||||
|
|
||||||
class UpstreamExtractor(private val client: OkHttpClient) {
|
class UpstreamExtractor(private val client: OkHttpClient) {
|
||||||
fun videosFromUrl(url: String, prefix: String = ""): List<Video> =
|
fun videosFromUrl(url: String, prefix: String = ""): List<Video> =
|
||||||
runCatching {
|
runCatching {
|
||||||
val jsE = client.newCall(GET(url)).execute().asJsoup().selectFirst("script:containsData(eval)")!!.data()
|
val jsE = client.newCall(GET(url)).execute().asJsoup().selectFirst("script:containsData(eval)")!!.data()
|
||||||
val masterUrl = JsUnpacker.unpackAndCombine(jsE)!!.substringAfter("{file:\"").substringBefore("\"}")
|
val masterUrl = JsUnpacker.unpackAndCombine(jsE)!!.substringAfter("{file:\"").substringBefore("\"}")
|
||||||
PlaylistUtils(client).extractFromHls(masterUrl, videoNameGen = { "${prefix}Upstream - $it" } )
|
PlaylistUtils(client).extractFromHls(masterUrl, videoNameGen = { "${prefix}Upstream - $it" })
|
||||||
}.getOrDefault(emptyList())
|
}.getOrDefault(emptyList())
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ class VidoExtractor(private val client: OkHttpClient) {
|
|||||||
fun videosFromUrl(url: String, prefix: String = ""): List<Video> {
|
fun videosFromUrl(url: String, prefix: String = ""): List<Video> {
|
||||||
val document = client.newCall(GET(url)).execute().use { it.body.string() }
|
val document = client.newCall(GET(url)).execute().use { it.body.string() }
|
||||||
val id = REGEX_ID.find(document)?.groupValues?.get(1)
|
val id = REGEX_ID.find(document)?.groupValues?.get(1)
|
||||||
val masterUrl = "$VIDO_URL/hls/${id}/master.m3u8"
|
val masterUrl = "$VIDO_URL/hls/$id/master.m3u8"
|
||||||
return playlistUtils.extractFromHls(masterUrl, videoNameGen = { "${prefix}Vido - (${it})" })
|
return playlistUtils.extractFromHls(masterUrl, videoNameGen = { "${prefix}Vido - ($it)" })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.lib.vkextractor
|
|||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
import eu.kanade.tachiyomi.animesource.model.Video
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
|
|
||||||
class VkExtractor(private val client: OkHttpClient, private val headers: Headers) {
|
class VkExtractor(private val client: OkHttpClient, private val headers: Headers) {
|
||||||
|
@ -4,6 +4,7 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
|||||||
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 eu.kanade.tachiyomi.util.parseAs
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
@ -16,7 +17,6 @@ import okhttp3.HttpUrl.Companion.toHttpUrl
|
|||||||
import okhttp3.MediaType.Companion.toMediaType
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.RequestBody.Companion.toRequestBody
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
import okhttp3.Response
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
class CDAExtractor(private val client: OkHttpClient, private val headers: Headers, private val referer: String) {
|
class CDAExtractor(private val client: OkHttpClient, private val headers: Headers, private val referer: String) {
|
||||||
@ -102,9 +102,4 @@ class CDAExtractor(private val client: OkHttpClient, private val headers: Header
|
|||||||
val resp: String,
|
val resp: String,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <reified T> Response.parseAs(transform: (String) -> String = { it }): T {
|
|
||||||
val responseBody = use { transform(it.body.string()) }
|
|
||||||
return json.decodeFromString(responseBody)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,12 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
|||||||
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
|
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import eu.kanade.tachiyomi.util.parseAs
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Response
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
class StreamPlayExtractor(private val client: OkHttpClient, private val headers: Headers) {
|
class StreamPlayExtractor(private val client: OkHttpClient, private val headers: Headers) {
|
||||||
@ -68,9 +68,4 @@ class StreamPlayExtractor(private val client: OkHttpClient, private val headers:
|
|||||||
val label: String,
|
val label: String,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <reified T> Response.parseAs(transform: (String) -> String = { it }): T {
|
|
||||||
val responseBody = use { transform(it.body.string()) }
|
|
||||||
return json.decodeFromString(responseBody)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import eu.kanade.tachiyomi.lib.mp4uploadextractor.Mp4uploadExtractor
|
|||||||
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
|
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
|
||||||
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStream
|
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStream
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
|
|
||||||
class LMAnime : AnimeStream(
|
class LMAnime : AnimeStream(
|
||||||
@ -27,11 +28,11 @@ class LMAnime : AnimeStream(
|
|||||||
.filter { element ->
|
.filter { element ->
|
||||||
val text = element.text()
|
val text = element.text()
|
||||||
allowed.any { it in text }
|
allowed.any { it in text }
|
||||||
}.parallelMap {
|
}.parallelCatchingFlatMapBlocking {
|
||||||
val language = it.text().substringBefore(" ")
|
val language = it.text().substringBefore(" ")
|
||||||
val url = getHosterUrl(it)
|
val url = getHosterUrl(it)
|
||||||
getVideoList(url, language)
|
getVideoList(url, language)
|
||||||
}.flatten().ifEmpty { throw Exception("Empty video list!") }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val streamwishExtractor by lazy { StreamWishExtractor(client, headers) }
|
private val streamwishExtractor by lazy { StreamWishExtractor(client, headers) }
|
||||||
|
@ -15,11 +15,11 @@ import eu.kanade.tachiyomi.lib.vudeoextractor.VudeoExtractor
|
|||||||
import eu.kanade.tachiyomi.multisrc.datalifeengine.DataLifeEngine
|
import eu.kanade.tachiyomi.multisrc.datalifeengine.DataLifeEngine
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMap
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import rx.Observable
|
|
||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
|
|
||||||
class FrenchAnime : DataLifeEngine(
|
class FrenchAnime : DataLifeEngine(
|
||||||
@ -87,8 +87,7 @@ class FrenchAnime : DataLifeEngine(
|
|||||||
override fun episodeFromElement(element: Element): SEpisode = throw Exception("not used")
|
override fun episodeFromElement(element: Element): SEpisode = throw Exception("not used")
|
||||||
|
|
||||||
// ============================ Video Links =============================
|
// ============================ Video Links =============================
|
||||||
|
override suspend fun getVideoList(episode: SEpisode): List<Video> {
|
||||||
override fun fetchVideoList(episode: SEpisode): Observable<List<Video>> {
|
|
||||||
val list = episode.url.split(",").filter { it.isNotBlank() }.parallelCatchingFlatMap {
|
val list = episode.url.split(",").filter { it.isNotBlank() }.parallelCatchingFlatMap {
|
||||||
with(it) {
|
with(it) {
|
||||||
when {
|
when {
|
||||||
@ -107,8 +106,7 @@ class FrenchAnime : DataLifeEngine(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.sort()
|
}.sort()
|
||||||
if (list.isEmpty()) throw Exception("no player found")
|
return list
|
||||||
return Observable.just(list)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun videoFromElement(element: Element): Video = throw Exception("Not Used")
|
override fun videoFromElement(element: Element): Video = throw Exception("Not Used")
|
||||||
|
@ -12,11 +12,11 @@ import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
|
|||||||
import eu.kanade.tachiyomi.lib.vudeoextractor.VudeoExtractor
|
import eu.kanade.tachiyomi.lib.vudeoextractor.VudeoExtractor
|
||||||
import eu.kanade.tachiyomi.multisrc.datalifeengine.DataLifeEngine
|
import eu.kanade.tachiyomi.multisrc.datalifeengine.DataLifeEngine
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMap
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import rx.Observable
|
|
||||||
|
|
||||||
class Wiflix : DataLifeEngine(
|
class Wiflix : DataLifeEngine(
|
||||||
"Wiflix",
|
"Wiflix",
|
||||||
@ -74,8 +74,7 @@ class Wiflix : DataLifeEngine(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================ Video Links =============================
|
// ============================ Video Links =============================
|
||||||
|
override suspend fun getVideoList(episode: SEpisode): List<Video> {
|
||||||
override fun fetchVideoList(episode: SEpisode): Observable<List<Video>> {
|
|
||||||
val list = episode.url.split(",").filter { it.isNotBlank() }.parallelCatchingFlatMap {
|
val list = episode.url.split(",").filter { it.isNotBlank() }.parallelCatchingFlatMap {
|
||||||
with(it) {
|
with(it) {
|
||||||
when {
|
when {
|
||||||
@ -93,7 +92,7 @@ class Wiflix : DataLifeEngine(
|
|||||||
}
|
}
|
||||||
}.sort()
|
}.sort()
|
||||||
if (list.isEmpty()) throw Exception("no player found")
|
if (list.isEmpty()) throw Exception("no player found")
|
||||||
return Observable.just(list)
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun videoFromElement(element: Element): Video = throw Exception("Not Used")
|
override fun videoFromElement(element: Element): Video = throw Exception("Not Used")
|
||||||
|
@ -26,11 +26,11 @@ class AnimeOnlineNinja : DooPlay(
|
|||||||
) {
|
) {
|
||||||
override val client by lazy {
|
override val client by lazy {
|
||||||
if (preferences.getBoolean(PREF_VRF_INTERCEPT_KEY, PREF_VRF_INTERCEPT_DEFAULT)) {
|
if (preferences.getBoolean(PREF_VRF_INTERCEPT_KEY, PREF_VRF_INTERCEPT_DEFAULT)) {
|
||||||
network.cloudflareClient.newBuilder()
|
network.client.newBuilder()
|
||||||
.addInterceptor(VrfInterceptor())
|
.addInterceptor(VrfInterceptor())
|
||||||
.build()
|
.build()
|
||||||
} else {
|
} else {
|
||||||
network.cloudflareClient
|
network.client
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@ class AnimePlayer : DooPlay(
|
|||||||
"AnimePlayer",
|
"AnimePlayer",
|
||||||
"https://animeplayer.com.br",
|
"https://animeplayer.com.br",
|
||||||
) {
|
) {
|
||||||
override val client = network.cloudflareClient
|
|
||||||
|
|
||||||
// ============================== Popular ===============================
|
// ============================== Popular ===============================
|
||||||
override fun popularAnimeSelector() = "div#featured-titles article div.poster"
|
override fun popularAnimeSelector() = "div#featured-titles article div.poster"
|
||||||
|
@ -13,10 +13,7 @@ import eu.kanade.tachiyomi.multisrc.dooplay.DooPlay
|
|||||||
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.coroutines.Dispatchers
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import okhttp3.FormBody
|
import okhttp3.FormBody
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
@ -60,7 +57,7 @@ class AnimesOnline : DooPlay(
|
|||||||
override fun videoListParse(response: Response): List<Video> {
|
override fun videoListParse(response: Response): List<Video> {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
val players = document.select("ul#playeroptionsul li")
|
val players = document.select("ul#playeroptionsul li")
|
||||||
return players.parallelMap(::getPlayerVideos).flatten()
|
return players.parallelCatchingFlatMapBlocking(::getPlayerVideos)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val prefQualityValues = arrayOf("360p", "480p", "720p", "1080p")
|
override val prefQualityValues = arrayOf("360p", "480p", "720p", "1080p")
|
||||||
@ -138,11 +135,6 @@ class AnimesOnline : DooPlay(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================= Utilities ==============================
|
// ============================= Utilities ==============================
|
||||||
private inline fun <A, B> Iterable<A>.parallelMap(crossinline f: suspend (A) -> B): List<B> =
|
|
||||||
runBlocking {
|
|
||||||
map { async(Dispatchers.Default) { f(it) } }.awaitAll()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getRealAnimeDoc(document: Document): Document {
|
override fun getRealAnimeDoc(document: Document): Document {
|
||||||
if (!document.location().contains("/episodio/")) return document
|
if (!document.location().contains("/episodio/")) return document
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ class AnimesHouse : DooPlay(
|
|||||||
// ============================== Popular ===============================
|
// ============================== Popular ===============================
|
||||||
// This source does not have a "popular" animes page, so we're going to
|
// This source does not have a "popular" animes page, so we're going to
|
||||||
// use latest updates page instead.
|
// use latest updates page instead.
|
||||||
override fun fetchPopularAnime(page: Int) = fetchLatestUpdates(page)
|
override suspend fun getPopularAnime(page: Int) = getLatestUpdates(page)
|
||||||
|
|
||||||
// =============================== Latest ===============================
|
// =============================== Latest ===============================
|
||||||
override fun latestUpdatesNextPageSelector(): String = "div.resppages > a > span.icon-chevron-right"
|
override fun latestUpdatesNextPageSelector(): String = "div.resppages > a > span.icon-chevron-right"
|
||||||
|
@ -11,11 +11,9 @@ import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
|
|||||||
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
|
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
|
||||||
import eu.kanade.tachiyomi.multisrc.dooplay.DooPlay
|
import eu.kanade.tachiyomi.multisrc.dooplay.DooPlay
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.network.await
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.coroutines.Dispatchers
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
@ -49,21 +47,19 @@ class Cinemathek : DooPlay(
|
|||||||
override fun videoListParse(response: Response): List<Video> {
|
override fun videoListParse(response: Response): List<Video> {
|
||||||
val players = response.use { it.asJsoup().select("ul#playeroptionsul li") }
|
val players = response.use { it.asJsoup().select("ul#playeroptionsul li") }
|
||||||
val hosterSelection = preferences.getStringSet(PREF_HOSTER_SELECTION_KEY, PREF_HOSTER_SELECTION_DEFAULT)!!
|
val hosterSelection = preferences.getStringSet(PREF_HOSTER_SELECTION_KEY, PREF_HOSTER_SELECTION_DEFAULT)!!
|
||||||
return players.parallelMapNotNull { player ->
|
return players.parallelCatchingFlatMapBlocking { player ->
|
||||||
runCatching {
|
val url = getPlayerUrl(player).takeUnless(String::isEmpty)!!
|
||||||
val url = getPlayerUrl(player).ifEmpty { return@parallelMapNotNull null }
|
getPlayerVideos(url, hosterSelection)
|
||||||
getPlayerVideos(url, hosterSelection)
|
}
|
||||||
}.getOrNull()
|
|
||||||
}.flatten()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getPlayerUrl(player: Element): String {
|
private suspend fun getPlayerUrl(player: Element): String {
|
||||||
val type = player.attr("data-type")
|
val type = player.attr("data-type")
|
||||||
val id = player.attr("data-post")
|
val id = player.attr("data-post")
|
||||||
val num = player.attr("data-nume")
|
val num = player.attr("data-nume")
|
||||||
if (num == "trailer") return ""
|
if (num == "trailer") return ""
|
||||||
return client.newCall(GET("$baseUrl/wp-json/dooplayer/v2/$id/$type/$num"))
|
return client.newCall(GET("$baseUrl/wp-json/dooplayer/v2/$id/$type/$num"))
|
||||||
.execute()
|
.await()
|
||||||
.use { it.body.string() }
|
.use { it.body.string() }
|
||||||
.substringAfter("\"embed_url\":\"")
|
.substringAfter("\"embed_url\":\"")
|
||||||
.substringBefore("\",")
|
.substringBefore("\",")
|
||||||
@ -76,7 +72,7 @@ class Cinemathek : DooPlay(
|
|||||||
private val streamtapeExtractor by lazy { StreamTapeExtractor(client) }
|
private val streamtapeExtractor by lazy { StreamTapeExtractor(client) }
|
||||||
private val streamwishExtractor by lazy { StreamWishExtractor(client, headers) }
|
private val streamwishExtractor by lazy { StreamWishExtractor(client, headers) }
|
||||||
|
|
||||||
private fun getPlayerVideos(url: String, hosterSelection: Set<String>): List<Video>? {
|
private fun getPlayerVideos(url: String, hosterSelection: Set<String>): List<Video> {
|
||||||
return when {
|
return when {
|
||||||
url.contains("https://streamlare.com") && hosterSelection.contains("slare") -> {
|
url.contains("https://streamlare.com") && hosterSelection.contains("slare") -> {
|
||||||
streamlareExtractor.videosFromUrl(url)
|
streamlareExtractor.videosFromUrl(url)
|
||||||
@ -95,7 +91,7 @@ class Cinemathek : DooPlay(
|
|||||||
streamwishExtractor.videosFromUrl(url)
|
streamwishExtractor.videosFromUrl(url)
|
||||||
}
|
}
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}.orEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================== Settings ==============================
|
// ============================== Settings ==============================
|
||||||
@ -163,11 +159,6 @@ class Cinemathek : DooPlay(
|
|||||||
).reversed()
|
).reversed()
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <A, B> Iterable<A>.parallelMapNotNull(crossinline f: suspend (A) -> B?): List<B> =
|
|
||||||
runBlocking {
|
|
||||||
map { async(Dispatchers.Default) { f(it) } }.awaitAll().filterNotNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val PREF_HOSTER_KEY = "preferred_hoster"
|
private const val PREF_HOSTER_KEY = "preferred_hoster"
|
||||||
private const val PREF_HOSTER_TITLE = "Standard-Hoster"
|
private const val PREF_HOSTER_TITLE = "Standard-Hoster"
|
||||||
|
@ -10,11 +10,9 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
|||||||
import eu.kanade.tachiyomi.lib.bloggerextractor.BloggerExtractor
|
import eu.kanade.tachiyomi.lib.bloggerextractor.BloggerExtractor
|
||||||
import eu.kanade.tachiyomi.multisrc.dooplay.DooPlay
|
import eu.kanade.tachiyomi.multisrc.dooplay.DooPlay
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.network.await
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.coroutines.Dispatchers
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
|
|
||||||
@ -76,10 +74,10 @@ class GoAnimes : DooPlay(
|
|||||||
override fun videoListParse(response: Response): List<Video> {
|
override fun videoListParse(response: Response): List<Video> {
|
||||||
val document = response.use { it.asJsoup() }
|
val document = response.use { it.asJsoup() }
|
||||||
val players = document.select("ul#playeroptionsul li")
|
val players = document.select("ul#playeroptionsul li")
|
||||||
return players.parallelCatchingFlatMap(::getPlayerVideos)
|
return players.parallelCatchingFlatMapBlocking(::getPlayerVideos)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getPlayerVideos(player: Element): List<Video> {
|
private suspend fun getPlayerVideos(player: Element): List<Video> {
|
||||||
val url = getPlayerUrl(player)
|
val url = getPlayerUrl(player)
|
||||||
return when {
|
return when {
|
||||||
"player5.goanimes.net" in url -> goanimesExtractor.videosFromUrl(url)
|
"player5.goanimes.net" in url -> goanimesExtractor.videosFromUrl(url)
|
||||||
@ -88,7 +86,7 @@ class GoAnimes : DooPlay(
|
|||||||
.set("referer", url)
|
.set("referer", url)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val script = client.newCall(GET(url, headers)).execute()
|
val script = client.newCall(GET(url, headers)).await()
|
||||||
.use { it.body.string() }
|
.use { it.body.string() }
|
||||||
.let { JsDecoder.decodeScript(it, false) }
|
.let { JsDecoder.decodeScript(it, false) }
|
||||||
|
|
||||||
@ -111,7 +109,7 @@ class GoAnimes : DooPlay(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
listOf("/bloggerjwplayer", "/m3u8", "/multivideo").any { it in url } -> {
|
listOf("/bloggerjwplayer", "/m3u8", "/multivideo").any { it in url } -> {
|
||||||
val script = client.newCall(GET(url)).execute()
|
val script = client.newCall(GET(url)).await()
|
||||||
.use { it.body.string() }
|
.use { it.body.string() }
|
||||||
.let(JsDecoder::decodeScript)
|
.let(JsDecoder::decodeScript)
|
||||||
when {
|
when {
|
||||||
@ -132,12 +130,12 @@ class GoAnimes : DooPlay(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getPlayerUrl(player: Element): String {
|
private suspend fun getPlayerUrl(player: Element): String {
|
||||||
val type = player.attr("data-type")
|
val type = player.attr("data-type")
|
||||||
val id = player.attr("data-post")
|
val id = player.attr("data-post")
|
||||||
val num = player.attr("data-nume")
|
val num = player.attr("data-nume")
|
||||||
val url = client.newCall(GET("$baseUrl/wp-json/dooplayer/v2/$id/$type/$num"))
|
val url = client.newCall(GET("$baseUrl/wp-json/dooplayer/v2/$id/$type/$num"))
|
||||||
.execute()
|
.await()
|
||||||
.use { it.body.string() }
|
.use { it.body.string() }
|
||||||
.substringAfter("\"embed_url\":\"")
|
.substringAfter("\"embed_url\":\"")
|
||||||
.substringBefore("\",")
|
.substringBefore("\",")
|
||||||
@ -145,24 +143,14 @@ class GoAnimes : DooPlay(
|
|||||||
|
|
||||||
return when {
|
return when {
|
||||||
"/protetorlinks/" in url -> {
|
"/protetorlinks/" in url -> {
|
||||||
val link = client.newCall(GET(url)).execute()
|
val link = client.newCall(GET(url)).await()
|
||||||
.use { it.asJsoup() }
|
.use { it.asJsoup() }
|
||||||
.selectFirst("a[href]")!!.attr("href")
|
.selectFirst("a[href]")!!.attr("href")
|
||||||
|
|
||||||
client.newCall(GET(link)).execute()
|
client.newCall(GET(link)).await()
|
||||||
.use(linkfunBypasser::getIframeUrl)
|
.use(linkfunBypasser::getIframeUrl)
|
||||||
}
|
}
|
||||||
else -> url
|
else -> url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================= Utilities ==============================
|
|
||||||
private inline fun <A, B> Iterable<A>.parallelCatchingFlatMap(crossinline f: suspend (A) -> Iterable<B>): List<B> =
|
|
||||||
runBlocking {
|
|
||||||
map {
|
|
||||||
async(Dispatchers.Default) {
|
|
||||||
runCatching { f(it) }.getOrElse { emptyList() }
|
|
||||||
}
|
|
||||||
}.awaitAll().flatten()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,6 @@ class Kinoking : DooPlay(
|
|||||||
override val videoSortPrefKey = PREF_HOSTER_KEY
|
override val videoSortPrefKey = PREF_HOSTER_KEY
|
||||||
override val videoSortPrefDefault = PREF_HOSTER_DEFAULT
|
override val videoSortPrefDefault = PREF_HOSTER_DEFAULT
|
||||||
|
|
||||||
override val client = network.cloudflareClient
|
|
||||||
|
|
||||||
// ============================== Popular ===============================
|
// ============================== Popular ===============================
|
||||||
override fun popularAnimeSelector(): String = "div#featured-titles div.poster"
|
override fun popularAnimeSelector(): String = "div#featured-titles div.poster"
|
||||||
|
|
||||||
|
@ -30,7 +30,6 @@ class Multimovies : DooPlay(
|
|||||||
"Multimovies",
|
"Multimovies",
|
||||||
"https://multimovies.live",
|
"https://multimovies.live",
|
||||||
) {
|
) {
|
||||||
override val client = network.cloudflareClient
|
|
||||||
|
|
||||||
private val defaultBaseUrl = "https://multimovies.live"
|
private val defaultBaseUrl = "https://multimovies.live"
|
||||||
|
|
||||||
|
@ -689,10 +689,7 @@ 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.coroutines.Dispatchers
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
@ -733,51 +730,47 @@ class AutoEmbedExtractor(private val client: OkHttpClient) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get video servers from containers
|
// Get video servers from containers
|
||||||
val serverList = containerList.parallelMap { container ->
|
val serverList = containerList.parallelCatchingFlatMapBlocking { container ->
|
||||||
runCatching {
|
when (container.name) {
|
||||||
when (container.name) {
|
"2embed" -> {
|
||||||
"2embed" -> {
|
getTwoEmbedServers(container.url, headers = headers)
|
||||||
getTwoEmbedServers(container.url, headers = headers)
|
|
||||||
}
|
|
||||||
"gomostream" -> {
|
|
||||||
getGomoStreamServers(container.url, headers = headers)
|
|
||||||
}
|
|
||||||
else -> null
|
|
||||||
}
|
}
|
||||||
}.getOrNull() ?: emptyList()
|
"gomostream" -> {
|
||||||
}.flatten()
|
getGomoStreamServers(container.url, headers = headers)
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}.orEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
val videoHeaders = headers.newBuilder()
|
val videoHeaders = headers.newBuilder()
|
||||||
.add("Referer", "https://www.2embed.to/")
|
.add("Referer", "https://www.2embed.to/")
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
return serverList.parallelMap { server ->
|
return serverList.parallelCatchingFlatMapBlocking { server ->
|
||||||
runCatching {
|
val prefix = server.name
|
||||||
val prefix = server.name
|
val videoUrl = server.url
|
||||||
val videoUrl = server.url
|
|
||||||
|
|
||||||
when {
|
when {
|
||||||
videoUrl.contains("streamlare") -> {
|
videoUrl.contains("streamlare") -> {
|
||||||
StreamlareExtractor(client).videosFromUrl(videoUrl, prefix = prefix)
|
StreamlareExtractor(client).videosFromUrl(videoUrl, prefix = prefix)
|
||||||
}
|
|
||||||
videoUrl.contains("mixdrop") -> {
|
|
||||||
MixDropExtractor(client).videoFromUrl(videoUrl, prefix = prefix)
|
|
||||||
}
|
|
||||||
videoUrl.contains("https://voe") -> {
|
|
||||||
VoeExtractor(client).videoFromUrl(videoUrl, server.name)
|
|
||||||
?.let(::listOf)
|
|
||||||
}
|
|
||||||
videoUrl.contains("rabbitstream") -> {
|
|
||||||
RabbitStreamExtractor(client).videosFromUrl(videoUrl, headers = videoHeaders, prefix = prefix)
|
|
||||||
}
|
|
||||||
videoUrl.contains("https://dood") -> {
|
|
||||||
DoodExtractor(client).videoFromUrl(videoUrl, server.name, false)
|
|
||||||
?.let(::listOf)
|
|
||||||
}
|
|
||||||
else -> null
|
|
||||||
}
|
}
|
||||||
}.getOrNull() ?: emptyList()
|
videoUrl.contains("mixdrop") -> {
|
||||||
}.flatten()
|
MixDropExtractor(client).videoFromUrl(videoUrl, prefix = prefix)
|
||||||
|
}
|
||||||
|
videoUrl.contains("https://voe") -> {
|
||||||
|
VoeExtractor(client).videoFromUrl(videoUrl, server.name)
|
||||||
|
?.let(::listOf)
|
||||||
|
}
|
||||||
|
videoUrl.contains("rabbitstream") -> {
|
||||||
|
RabbitStreamExtractor(client).videosFromUrl(videoUrl, headers = videoHeaders, prefix = prefix)
|
||||||
|
}
|
||||||
|
videoUrl.contains("https://dood") -> {
|
||||||
|
DoodExtractor(client).videoFromUrl(videoUrl, server.name, false)
|
||||||
|
?.let(::listOf)
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}.orEmpty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Server(
|
data class Server(
|
||||||
@ -892,10 +885,4 @@ class AutoEmbedExtractor(private val client: OkHttpClient) {
|
|||||||
}
|
}
|
||||||
}.getOrNull()
|
}.getOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
// From Dopebox
|
|
||||||
private fun <A, B> Iterable<A>.parallelMap(f: suspend (A) -> B): List<B> =
|
|
||||||
runBlocking {
|
|
||||||
map { async(Dispatchers.Default) { f(it) } }.awaitAll()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,11 @@ package eu.kanade.tachiyomi.animeextension.pt.pifansubs.extractors
|
|||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
import eu.kanade.tachiyomi.animesource.model.Video
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import eu.kanade.tachiyomi.util.parseAs
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.decodeFromStream
|
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Response
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
class BlembedExtractor(private val client: OkHttpClient, private val headers: Headers) {
|
class BlembedExtractor(private val client: OkHttpClient, private val headers: Headers) {
|
||||||
@ -32,10 +31,6 @@ class BlembedExtractor(private val client: OkHttpClient, private val headers: He
|
|||||||
|
|
||||||
return res.sources.map { Video(it.file, "Blembed - ${it.label}", it.file, headers) }
|
return res.sources.map { Video(it.file, "Blembed - ${it.label}", it.file, headers) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <reified T> Response.parseAs(): T = use {
|
|
||||||
json.decodeFromStream(it.body.byteStream())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
@ -3,11 +3,9 @@ package eu.kanade.tachiyomi.animeextension.pt.pobreflix.extractors
|
|||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
import eu.kanade.tachiyomi.animesource.model.Video
|
||||||
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.network.await
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.coroutines.Dispatchers
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.FormBody
|
import okhttp3.FormBody
|
||||||
@ -26,7 +24,7 @@ class SuperFlixExtractor(
|
|||||||
fun videosFromUrl(url: String): List<Video> {
|
fun videosFromUrl(url: String): List<Video> {
|
||||||
val links = linksFromUrl(url)
|
val links = linksFromUrl(url)
|
||||||
|
|
||||||
val fixedLinks = links.parallelCatchingFlatMap {
|
val fixedLinks = links.parallelCatchingFlatMapBlocking {
|
||||||
val (language, linkUrl) = it
|
val (language, linkUrl) = it
|
||||||
when {
|
when {
|
||||||
linkUrl.contains("?vid=") -> linksFromPlayer(linkUrl, language)
|
linkUrl.contains("?vid=") -> linksFromPlayer(linkUrl, language)
|
||||||
@ -34,10 +32,10 @@ class SuperFlixExtractor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fixedLinks.parallelCatchingFlatMap { genericExtractor(it.second, it.first) }
|
return fixedLinks.parallelCatchingFlatMapBlocking { genericExtractor(it.second, it.first) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun linksFromPlayer(url: String, language: String): List<Pair<String, String>> {
|
private suspend fun linksFromPlayer(url: String, language: String): List<Pair<String, String>> {
|
||||||
val httpUrl = url.toHttpUrl()
|
val httpUrl = url.toHttpUrl()
|
||||||
val id = httpUrl.queryParameter("vid")!!
|
val id = httpUrl.queryParameter("vid")!!
|
||||||
val headers = defaultHeaders.newBuilder()
|
val headers = defaultHeaders.newBuilder()
|
||||||
@ -45,7 +43,7 @@ class SuperFlixExtractor(
|
|||||||
.set("origin", API_DOMAIN)
|
.set("origin", API_DOMAIN)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val doc = client.newCall(GET(url, headers)).execute().use { it.asJsoup() }
|
val doc = client.newCall(GET(url, headers)).await().use { it.asJsoup() }
|
||||||
|
|
||||||
val baseUrl = "https://" + httpUrl.host
|
val baseUrl = "https://" + httpUrl.host
|
||||||
val apiUrl = "$baseUrl/ajax_sources.php"
|
val apiUrl = "$baseUrl/ajax_sources.php"
|
||||||
@ -66,7 +64,7 @@ class SuperFlixExtractor(
|
|||||||
.add("ord", order)
|
.add("ord", order)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val req = client.newCall(POST(apiUrl, apiHeaders, formBody)).execute()
|
val req = client.newCall(POST(apiUrl, apiHeaders, formBody)).await()
|
||||||
.use { it.body.string() }
|
.use { it.body.string() }
|
||||||
|
|
||||||
runCatching {
|
runCatching {
|
||||||
@ -125,15 +123,6 @@ class SuperFlixExtractor(
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class DataDto(val video_url: String? = null)
|
data class DataDto(val video_url: String? = null)
|
||||||
|
|
||||||
private inline fun <A, B> Iterable<A>.parallelCatchingFlatMap(crossinline f: suspend (A) -> Iterable<B>): List<B> =
|
|
||||||
runBlocking {
|
|
||||||
map {
|
|
||||||
async(Dispatchers.Default) {
|
|
||||||
runCatching { f(it) }.getOrElse { emptyList() }
|
|
||||||
}
|
|
||||||
}.awaitAll().flatten()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val API_DOMAIN = "https://superflixapi.top"
|
private const val API_DOMAIN = "https://superflixapi.top"
|
||||||
|
@ -16,7 +16,6 @@ import okhttp3.MediaType.Companion.toMediaType
|
|||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.RequestBody.Companion.toRequestBody
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import rx.Observable
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
class UniqueStream : DooPlay(
|
class UniqueStream : DooPlay(
|
||||||
@ -24,7 +23,6 @@ class UniqueStream : DooPlay(
|
|||||||
"UniqueStream",
|
"UniqueStream",
|
||||||
"https://uniquestream.net",
|
"https://uniquestream.net",
|
||||||
) {
|
) {
|
||||||
override val client = network.cloudflareClient
|
|
||||||
|
|
||||||
private val json: Json by injectLazy()
|
private val json: Json by injectLazy()
|
||||||
|
|
||||||
@ -183,7 +181,7 @@ class UniqueStream : DooPlay(
|
|||||||
|
|
||||||
// ============================ Video Links =============================
|
// ============================ Video Links =============================
|
||||||
|
|
||||||
override fun fetchVideoList(episode: SEpisode): Observable<List<Video>> {
|
override suspend fun getVideoList(episode: SEpisode): List<Video> {
|
||||||
val videoList = mutableListOf<Video>()
|
val videoList = mutableListOf<Video>()
|
||||||
val document = client.newCall(
|
val document = client.newCall(
|
||||||
GET(baseUrl + episode.url, headers = headers),
|
GET(baseUrl + episode.url, headers = headers),
|
||||||
@ -290,7 +288,7 @@ class UniqueStream : DooPlay(
|
|||||||
|
|
||||||
require(videoList.isNotEmpty()) { "Failed to fetch videos" }
|
require(videoList.isNotEmpty()) { "Failed to fetch videos" }
|
||||||
|
|
||||||
return Observable.just(videoList.sort())
|
return videoList.sort()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================== Settings ==============================
|
// ============================== Settings ==============================
|
||||||
|
@ -21,11 +21,10 @@ import eu.kanade.tachiyomi.multisrc.animestream.AnimeStreamFilters.StudioFilter
|
|||||||
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStreamFilters.SubFilter
|
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStreamFilters.SubFilter
|
||||||
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStreamFilters.TypeFilter
|
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStreamFilters.TypeFilter
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.awaitSuccess
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||||
@ -34,7 +33,6 @@ import okhttp3.Response
|
|||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import rx.Observable
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
@ -48,8 +46,6 @@ abstract class AnimeStream(
|
|||||||
|
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
override val client = network.cloudflareClient
|
|
||||||
|
|
||||||
protected open val preferences by lazy {
|
protected open val preferences by lazy {
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
}
|
}
|
||||||
@ -81,9 +77,9 @@ abstract class AnimeStream(
|
|||||||
protected open val animeListUrl = "$baseUrl/anime"
|
protected open val animeListUrl = "$baseUrl/anime"
|
||||||
|
|
||||||
// ============================== Popular ===============================
|
// ============================== Popular ===============================
|
||||||
override fun fetchPopularAnime(page: Int): Observable<AnimesPage> {
|
override suspend fun getPopularAnime(page: Int): AnimesPage {
|
||||||
fetchFilterList()
|
fetchFilterList()
|
||||||
return super.fetchPopularAnime(page)
|
return super.getPopularAnime(page)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun popularAnimeRequest(page: Int) = GET("$animeListUrl/?page=$page&order=popular")
|
override fun popularAnimeRequest(page: Int) = GET("$animeListUrl/?page=$page&order=popular")
|
||||||
@ -95,9 +91,9 @@ abstract class AnimeStream(
|
|||||||
override fun popularAnimeNextPageSelector(): String? = searchAnimeNextPageSelector()
|
override fun popularAnimeNextPageSelector(): String? = searchAnimeNextPageSelector()
|
||||||
|
|
||||||
// =============================== Latest ===============================
|
// =============================== Latest ===============================
|
||||||
override fun fetchLatestUpdates(page: Int): Observable<AnimesPage> {
|
override suspend fun getLatestUpdates(page: Int): AnimesPage {
|
||||||
fetchFilterList()
|
fetchFilterList()
|
||||||
return super.fetchLatestUpdates(page)
|
return super.getLatestUpdates(page)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int) = GET("$animeListUrl/?page=$page&order=update")
|
override fun latestUpdatesRequest(page: Int) = GET("$animeListUrl/?page=$page&order=update")
|
||||||
@ -109,14 +105,14 @@ abstract class AnimeStream(
|
|||||||
override fun latestUpdatesNextPageSelector(): String? = searchAnimeNextPageSelector()
|
override fun latestUpdatesNextPageSelector(): String? = searchAnimeNextPageSelector()
|
||||||
|
|
||||||
// =============================== Search ===============================
|
// =============================== Search ===============================
|
||||||
override fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable<AnimesPage> {
|
override suspend fun getSearchAnime(page: Int, query: String, filters: AnimeFilterList): AnimesPage {
|
||||||
return if (query.startsWith(PREFIX_SEARCH)) { // URL intent handler
|
return if (query.startsWith(PREFIX_SEARCH)) { // URL intent handler
|
||||||
val path = query.removePrefix(PREFIX_SEARCH)
|
val path = query.removePrefix(PREFIX_SEARCH)
|
||||||
client.newCall(GET("$baseUrl/$path"))
|
client.newCall(GET("$baseUrl/$path"))
|
||||||
.asObservableSuccess()
|
.awaitSuccess()
|
||||||
.map(::searchAnimeByPathParse)
|
.use(::searchAnimeByPathParse)
|
||||||
} else {
|
} else {
|
||||||
super.fetchSearchAnime(page, query, filters)
|
super.getSearchAnime(page, query, filters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,13 +316,11 @@ abstract class AnimeStream(
|
|||||||
|
|
||||||
override fun videoListParse(response: Response): List<Video> {
|
override fun videoListParse(response: Response): List<Video> {
|
||||||
val items = response.use { it.asJsoup() }.select(videoListSelector())
|
val items = response.use { it.asJsoup() }.select(videoListSelector())
|
||||||
return items.parallelMap { element ->
|
return items.parallelCatchingFlatMapBlocking { element ->
|
||||||
runCatching {
|
val name = element.text()
|
||||||
val name = element.text()
|
val url = getHosterUrl(element)
|
||||||
val url = getHosterUrl(element)
|
getVideoList(url, name)
|
||||||
getVideoList(url, name)
|
}
|
||||||
}.onFailure { it.printStackTrace() }.getOrElse { emptyList() }
|
|
||||||
}.flatten()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun getHosterUrl(element: Element): String {
|
protected open fun getHosterUrl(element: Element): String {
|
||||||
@ -422,11 +416,6 @@ abstract class AnimeStream(
|
|||||||
} ?: 0L
|
} ?: 0L
|
||||||
}
|
}
|
||||||
|
|
||||||
protected inline fun <A, B> Iterable<A>.parallelMap(crossinline f: suspend (A) -> B): List<B> =
|
|
||||||
runBlocking {
|
|
||||||
map { async(Dispatchers.Default) { f(it) } }.awaitAll()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tries to get the image url via various possible attributes.
|
* Tries to get the image url via various possible attributes.
|
||||||
* Taken from Tachiyomi's Madara multisrc.
|
* Taken from Tachiyomi's Madara multisrc.
|
||||||
|
@ -12,21 +12,15 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
|||||||
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
|
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
|
||||||
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.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.awaitSuccess
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.MediaType.Companion.toMediaType
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.RequestBody.Companion.toRequestBody
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import rx.Observable
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
@ -38,8 +32,6 @@ abstract class DataLifeEngine(
|
|||||||
|
|
||||||
override val supportsLatest = false
|
override val supportsLatest = false
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient
|
|
||||||
|
|
||||||
private val preferences by lazy { Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) }
|
private val preferences by lazy { Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) }
|
||||||
|
|
||||||
// ============================== Popular ===============================
|
// ============================== Popular ===============================
|
||||||
@ -139,10 +131,10 @@ abstract class DataLifeEngine(
|
|||||||
}
|
}
|
||||||
// =========================== Anime Details ============================
|
// =========================== Anime Details ============================
|
||||||
|
|
||||||
override fun fetchAnimeDetails(anime: SAnime): Observable<SAnime> {
|
override suspend fun getAnimeDetails(anime: SAnime): SAnime {
|
||||||
return client.newCall(animeDetailsRequest(anime))
|
return client.newCall(animeDetailsRequest(anime))
|
||||||
.asObservableSuccess()
|
.awaitSuccess()
|
||||||
.map { response ->
|
.use { response ->
|
||||||
animeDetailsParse(response, anime).apply { initialized = true }
|
animeDetailsParse(response, anime).apply { initialized = true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -183,11 +175,6 @@ abstract class DataLifeEngine(
|
|||||||
).reversed()
|
).reversed()
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <A, B> Iterable<A>.parallelCatchingFlatMap(crossinline f: suspend (A) -> Iterable<B>): List<B> =
|
|
||||||
runBlocking {
|
|
||||||
map { async(Dispatchers.Default) { runCatching { f(it) }.getOrElse { emptyList() } } }.awaitAll().flatten()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||||
val videoQualityPref = ListPreference(screen.context).apply {
|
val videoQualityPref = ListPreference(screen.context).apply {
|
||||||
key = "preferred_quality"
|
key = "preferred_quality"
|
||||||
|
@ -13,14 +13,12 @@ import eu.kanade.tachiyomi.animesource.model.SEpisode
|
|||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
import eu.kanade.tachiyomi.animesource.model.Video
|
||||||
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
|
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.awaitSuccess
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
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
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import rx.Observable
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
@ -39,8 +37,6 @@ abstract class DooPlay(
|
|||||||
|
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
override val client: OkHttpClient = network.client
|
|
||||||
|
|
||||||
override fun headersBuilder() = super.headersBuilder().add("Referer", baseUrl)
|
override fun headersBuilder() = super.headersBuilder().add("Referer", baseUrl)
|
||||||
|
|
||||||
protected open val preferences: SharedPreferences by lazy {
|
protected open val preferences: SharedPreferences by lazy {
|
||||||
@ -185,16 +181,14 @@ abstract class DooPlay(
|
|||||||
return AnimesPage(animes, hasNextPage)
|
return AnimesPage(animes, hasNextPage)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable<AnimesPage> {
|
override suspend fun getSearchAnime(page: Int, query: String, filters: AnimeFilterList): AnimesPage {
|
||||||
return if (query.startsWith(PREFIX_SEARCH)) {
|
return if (query.startsWith(PREFIX_SEARCH)) {
|
||||||
val path = query.removePrefix(PREFIX_SEARCH)
|
val path = query.removePrefix(PREFIX_SEARCH)
|
||||||
client.newCall(GET("$baseUrl/$path", headers))
|
client.newCall(GET("$baseUrl/$path", headers))
|
||||||
.asObservableSuccess()
|
.awaitSuccess()
|
||||||
.map { response ->
|
.use(::searchAnimeByPathParse)
|
||||||
searchAnimeByPathParse(response)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
super.fetchSearchAnime(page, query, filters)
|
super.getSearchAnime(page, query, filters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,14 +17,10 @@ import eu.kanade.tachiyomi.multisrc.dopeflix.dto.VideoDto
|
|||||||
import eu.kanade.tachiyomi.multisrc.dopeflix.extractors.DopeFlixExtractor
|
import eu.kanade.tachiyomi.multisrc.dopeflix.extractors.DopeFlixExtractor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.coroutines.Dispatchers
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
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
|
||||||
@ -45,8 +41,6 @@ abstract class DopeFlix(
|
|||||||
|
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient
|
|
||||||
|
|
||||||
private val preferences: SharedPreferences by lazy {
|
private val preferences: SharedPreferences by lazy {
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
}
|
}
|
||||||
@ -191,7 +185,7 @@ abstract class DopeFlix(
|
|||||||
val doc = response.asJsoup()
|
val doc = response.asJsoup()
|
||||||
val episodeReferer = Headers.headersOf("Referer", response.request.header("referer")!!)
|
val episodeReferer = Headers.headersOf("Referer", response.request.header("referer")!!)
|
||||||
return doc.select("ul.fss-list a.btn-play")
|
return doc.select("ul.fss-list a.btn-play")
|
||||||
.parallelMap { server ->
|
.parallelCatchingFlatMapBlocking { server ->
|
||||||
val name = server.selectFirst("span")!!.text()
|
val name = server.selectFirst("span")!!.text()
|
||||||
val id = server.attr("data-id")
|
val id = server.attr("data-id")
|
||||||
val url = "$baseUrl/ajax/sources/$id"
|
val url = "$baseUrl/ajax/sources/$id"
|
||||||
@ -199,19 +193,17 @@ abstract class DopeFlix(
|
|||||||
.use { it.body.string() }
|
.use { it.body.string() }
|
||||||
val sourceUrl = reqBody.substringAfter("\"link\":\"")
|
val sourceUrl = reqBody.substringAfter("\"link\":\"")
|
||||||
.substringBefore("\"")
|
.substringBefore("\"")
|
||||||
runCatching {
|
when {
|
||||||
when {
|
"DoodStream" in name ->
|
||||||
"DoodStream" in name ->
|
DoodExtractor(client).videoFromUrl(sourceUrl)
|
||||||
DoodExtractor(client).videoFromUrl(sourceUrl)
|
?.let(::listOf)
|
||||||
?.let(::listOf)
|
"Vidcloud" in name || "UpCloud" in name -> {
|
||||||
"Vidcloud" in name || "UpCloud" in name -> {
|
val video = extractor.getVideoDto(sourceUrl)
|
||||||
val video = extractor.getVideoDto(sourceUrl)
|
getVideosFromServer(video, name)
|
||||||
getVideosFromServer(video, name)
|
|
||||||
}
|
|
||||||
else -> null
|
|
||||||
}
|
}
|
||||||
}.getOrNull() ?: emptyList()
|
else -> null
|
||||||
}.flatten()
|
}.orEmpty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getVideosFromServer(video: VideoDto, name: String): List<Video> {
|
private fun getVideosFromServer(video: VideoDto, name: String): List<Video> {
|
||||||
@ -343,11 +335,6 @@ abstract class DopeFlix(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================= Utilities ==============================
|
// ============================= Utilities ==============================
|
||||||
private inline fun <A, B> Iterable<A>.parallelMap(crossinline f: suspend (A) -> B): List<B> =
|
|
||||||
runBlocking {
|
|
||||||
map { async(Dispatchers.Default) { f(it) } }.awaitAll()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun HttpUrl.Builder.addIfNotBlank(query: String, value: String): HttpUrl.Builder {
|
private fun HttpUrl.Builder.addIfNotBlank(query: String, value: String): HttpUrl.Builder {
|
||||||
if (value.isNotBlank()) {
|
if (value.isNotBlank()) {
|
||||||
addQueryParameter(query, value)
|
addQueryParameter(query, value)
|
||||||
|
@ -16,13 +16,14 @@ import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
|
|||||||
import eu.kanade.tachiyomi.multisrc.zorotheme.dto.HtmlResponse
|
import eu.kanade.tachiyomi.multisrc.zorotheme.dto.HtmlResponse
|
||||||
import eu.kanade.tachiyomi.multisrc.zorotheme.dto.SourcesResponse
|
import eu.kanade.tachiyomi.multisrc.zorotheme.dto.SourcesResponse
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.network.await
|
||||||
import eu.kanade.tachiyomi.util.parallelCatchingFlatMap
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMap
|
||||||
import eu.kanade.tachiyomi.util.parallelMapNotNull
|
import eu.kanade.tachiyomi.util.parallelMapNotNull
|
||||||
|
import eu.kanade.tachiyomi.util.parseAs
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
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
|
||||||
@ -39,8 +40,6 @@ abstract class ZoroTheme(
|
|||||||
|
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
override val client: OkHttpClient = network.client
|
|
||||||
|
|
||||||
private val json: Json by injectLazy()
|
private val json: Json by injectLazy()
|
||||||
|
|
||||||
val preferences: SharedPreferences by lazy {
|
val preferences: SharedPreferences by lazy {
|
||||||
@ -210,7 +209,7 @@ abstract class ZoroTheme(
|
|||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getVideoList(episode: SEpisode): List<Video> {
|
override suspend fun getVideoList(episode: SEpisode): List<Video> {
|
||||||
val response = client.newCall(videoListRequest(episode)).execute()
|
val response = client.newCall(videoListRequest(episode)).await()
|
||||||
|
|
||||||
val episodeReferer = response.request.header("referer")!!
|
val episodeReferer = response.request.header("referer")!!
|
||||||
val typeSelection = preferences.typeToggle
|
val typeSelection = preferences.typeToggle
|
||||||
@ -230,7 +229,7 @@ abstract class ZoroTheme(
|
|||||||
|
|
||||||
val link = client.newCall(
|
val link = client.newCall(
|
||||||
GET("$baseUrl/ajax$ajaxRoute/episode/sources?id=$id", apiHeaders(episodeReferer)),
|
GET("$baseUrl/ajax$ajaxRoute/episode/sources?id=$id", apiHeaders(episodeReferer)),
|
||||||
).execute().parseAs<SourcesResponse>().link ?: ""
|
).await().parseAs<SourcesResponse>().link ?: ""
|
||||||
|
|
||||||
VideoData(type, link, name)
|
VideoData(type, link, name)
|
||||||
}
|
}
|
||||||
@ -250,11 +249,6 @@ abstract class ZoroTheme(
|
|||||||
override fun videoUrlParse(document: Document) = throw Exception("not used")
|
override fun videoUrlParse(document: Document) = throw Exception("not used")
|
||||||
|
|
||||||
// ============================= Utilities ==============================
|
// ============================= Utilities ==============================
|
||||||
|
|
||||||
private inline fun <reified T> Response.parseAs(): T {
|
|
||||||
return use { it.body.string() }.let(json::decodeFromString)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Set<String>.contains(s: String, ignoreCase: Boolean): Boolean {
|
private fun Set<String>.contains(s: String, ignoreCase: Boolean): Boolean {
|
||||||
return any { it.equals(s, ignoreCase) }
|
return any { it.equals(s, ignoreCase) }
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,6 @@ interface ThemeSourceGenerator {
|
|||||||
| extClass = '.${source.className}'
|
| extClass = '.${source.className}'
|
||||||
| extFactory = '$themePkg'
|
| extFactory = '$themePkg'
|
||||||
| extVersionCode = ${baseVersionCode + source.overrideVersionCode + MULTISRC_LIBRARY_VERSION}
|
| extVersionCode = ${baseVersionCode + source.overrideVersionCode + MULTISRC_LIBRARY_VERSION}
|
||||||
| libVersion = '13'
|
|
||||||
| ${if (source.isNsfw) "containsNsfw = true\n" else ""}
|
| ${if (source.isNsfw) "containsNsfw = true\n" else ""}
|
||||||
|}
|
|}
|
||||||
|$defaultAdditionalGradleText
|
|$defaultAdditionalGradleText
|
||||||
|
@ -9,7 +9,6 @@ ext {
|
|||||||
pkgNameSuffix = 'all.animeonsen'
|
pkgNameSuffix = 'all.animeonsen'
|
||||||
extClass = '.AnimeOnsen'
|
extClass = '.AnimeOnsen'
|
||||||
extVersionCode = 7
|
extVersionCode = 7
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
@ -18,14 +18,12 @@ import eu.kanade.tachiyomi.animesource.model.Track
|
|||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
import eu.kanade.tachiyomi.animesource.model.Video
|
||||||
import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource
|
import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.util.parseAs
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.boolean
|
import kotlinx.serialization.json.boolean
|
||||||
import kotlinx.serialization.json.jsonPrimitive
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import rx.Observable
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
@ -43,11 +41,9 @@ class AnimeOnsen : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
|
|
||||||
override val supportsLatest = false
|
override val supportsLatest = false
|
||||||
|
|
||||||
private val cfClient = network.cloudflareClient
|
|
||||||
|
|
||||||
override val client by lazy {
|
override val client by lazy {
|
||||||
network.client.newBuilder()
|
network.client.newBuilder()
|
||||||
.addInterceptor(AOAPIInterceptor(cfClient))
|
.addInterceptor(AOAPIInterceptor(network.client))
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,15 +84,9 @@ class AnimeOnsen : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// =========================== Anime Details ============================
|
// =========================== Anime Details ============================
|
||||||
override fun fetchAnimeDetails(anime: SAnime): Observable<SAnime> {
|
override fun animeDetailsRequest(anime: SAnime) = GET("$apiUrl/content/${anime.url}/extensive")
|
||||||
return client.newCall(GET("$apiUrl/content/${anime.url}/extensive"))
|
|
||||||
.asObservableSuccess()
|
|
||||||
.map { response ->
|
|
||||||
animeDetailsParse(response).apply { initialized = true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun animeDetailsRequest(anime: SAnime) = GET("$baseUrl/details/${anime.url}")
|
override fun getAnimeUrl(anime: SAnime) = "$baseUrl/details/${anime.url}"
|
||||||
|
|
||||||
override fun animeDetailsParse(response: Response) = SAnime.create().apply {
|
override fun animeDetailsParse(response: Response) = SAnime.create().apply {
|
||||||
val details = response.parseAs<AnimeDetails>()
|
val details = response.parseAs<AnimeDetails>()
|
||||||
@ -165,10 +155,6 @@ class AnimeOnsen : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================= Utilities ==============================
|
// ============================= Utilities ==============================
|
||||||
private inline fun <reified T> Response.parseAs(): T {
|
|
||||||
return use { it.body.string() }.let(json::decodeFromString)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseStatus(statusString: String?): Int {
|
private fun parseStatus(statusString: String?): Int {
|
||||||
return when (statusString?.trim()) {
|
return when (statusString?.trim()) {
|
||||||
"finished_airing" -> SAnime.COMPLETED
|
"finished_airing" -> SAnime.COMPLETED
|
||||||
|
@ -9,7 +9,6 @@ ext {
|
|||||||
pkgNameSuffix = 'all.animeworldindia'
|
pkgNameSuffix = 'all.animeworldindia'
|
||||||
extClass = '.AnimeWorldIndiaFactory'
|
extClass = '.AnimeWorldIndiaFactory'
|
||||||
extVersionCode = 7
|
extVersionCode = 7
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -34,8 +34,6 @@ class AnimeWorldIndia(
|
|||||||
|
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
override val client = network.cloudflareClient
|
|
||||||
|
|
||||||
private val json: Json by injectLazy()
|
private val json: Json by injectLazy()
|
||||||
|
|
||||||
private val preferences by lazy {
|
private val preferences by lazy {
|
||||||
|
@ -9,7 +9,6 @@ ext {
|
|||||||
pkgNameSuffix = 'all.googledrive'
|
pkgNameSuffix = 'all.googledrive'
|
||||||
extClass = '.GoogleDrive'
|
extClass = '.GoogleDrive'
|
||||||
extVersionCode = 13
|
extVersionCode = 13
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -22,18 +22,17 @@ import eu.kanade.tachiyomi.lib.googledriveextractor.GoogleDriveExtractor
|
|||||||
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 eu.kanade.tachiyomi.util.parseAs
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.MediaType.Companion.toMediaType
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import okhttp3.ProtocolException
|
import okhttp3.ProtocolException
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.RequestBody.Companion.toRequestBody
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import okhttp3.internal.commonEmptyRequestBody
|
import okhttp3.internal.commonEmptyRequestBody
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import rx.Observable
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
@ -63,8 +62,6 @@ class GoogleDrive : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val client: OkHttpClient = network.client
|
|
||||||
|
|
||||||
// Overriding headersBuilder() seems to cause issues with webview
|
// Overriding headersBuilder() seems to cause issues with webview
|
||||||
private val getHeaders = headers.newBuilder().apply {
|
private val getHeaders = headers.newBuilder().apply {
|
||||||
add("Accept", "*/*")
|
add("Accept", "*/*")
|
||||||
@ -77,8 +74,8 @@ class GoogleDrive : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
|
|
||||||
// ============================== Popular ===============================
|
// ============================== Popular ===============================
|
||||||
|
|
||||||
override fun fetchPopularAnime(page: Int): Observable<AnimesPage> =
|
override suspend fun getPopularAnime(page: Int): AnimesPage =
|
||||||
Observable.just(parsePage(popularAnimeRequest(page), page))
|
parsePage(popularAnimeRequest(page), page)
|
||||||
|
|
||||||
override fun popularAnimeRequest(page: Int): Request {
|
override fun popularAnimeRequest(page: Int): Request {
|
||||||
require(!baseUrlInternal.isNullOrEmpty()) { "Enter drive path(s) in extension settings." }
|
require(!baseUrlInternal.isNullOrEmpty()) { "Enter drive path(s) in extension settings." }
|
||||||
@ -106,11 +103,11 @@ class GoogleDrive : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
|
|
||||||
override fun searchAnimeParse(response: Response): AnimesPage = throw Exception("Not used")
|
override fun searchAnimeParse(response: Response): AnimesPage = throw Exception("Not used")
|
||||||
|
|
||||||
override fun fetchSearchAnime(
|
override suspend fun getSearchAnime(
|
||||||
page: Int,
|
page: Int,
|
||||||
query: String,
|
query: String,
|
||||||
filters: AnimeFilterList,
|
filters: AnimeFilterList,
|
||||||
): Observable<AnimesPage> {
|
): AnimesPage {
|
||||||
val filterList = if (filters.isEmpty()) getFilterList() else filters
|
val filterList = if (filters.isEmpty()) getFilterList() else filters
|
||||||
val urlFilter = filterList.find { it is URLFilter } as URLFilter
|
val urlFilter = filterList.find { it is URLFilter } as URLFilter
|
||||||
|
|
||||||
@ -118,16 +115,16 @@ class GoogleDrive : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
val req = searchAnimeRequest(page, query, filters)
|
val req = searchAnimeRequest(page, query, filters)
|
||||||
|
|
||||||
if (query.isEmpty()) {
|
if (query.isEmpty()) {
|
||||||
Observable.just(parsePage(req, page))
|
parsePage(req, page)
|
||||||
} else {
|
} else {
|
||||||
val parentId = req.url.pathSegments.last()
|
val parentId = req.url.pathSegments.last()
|
||||||
val cleanQuery = URLEncoder.encode(query, "UTF-8")
|
val cleanQuery = URLEncoder.encode(query, "UTF-8")
|
||||||
val genMultiFormReq = searchReq(parentId, cleanQuery)
|
val genMultiFormReq = searchReq(parentId, cleanQuery)
|
||||||
|
|
||||||
Observable.just(parsePage(req, page, genMultiFormReq))
|
parsePage(req, page, genMultiFormReq)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Observable.just(addSinglePage(urlFilter.state))
|
addSinglePage(urlFilter.state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,10 +184,10 @@ class GoogleDrive : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
return GET(parsed.url, headers = getHeaders)
|
return GET(parsed.url, headers = getHeaders)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fetchAnimeDetails(anime: SAnime): Observable<SAnime> {
|
override suspend fun getAnimeDetails(anime: SAnime): SAnime {
|
||||||
val parsed = json.decodeFromString<LinkData>(anime.url)
|
val parsed = json.decodeFromString<LinkData>(anime.url)
|
||||||
|
|
||||||
if (parsed.type == "single") return Observable.just(anime)
|
if (parsed.type == "single") return anime
|
||||||
|
|
||||||
val folderId = DRIVE_FOLDER_REGEX.matchEntire(parsed.url)!!.groups["id"]!!.value
|
val folderId = DRIVE_FOLDER_REGEX.matchEntire(parsed.url)!!.groups["id"]!!.value
|
||||||
|
|
||||||
@ -198,7 +195,7 @@ class GoogleDrive : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
client.newCall(GET(parsed.url, headers = getHeaders)).execute().asJsoup()
|
client.newCall(GET(parsed.url, headers = getHeaders)).execute().asJsoup()
|
||||||
} catch (a: ProtocolException) {
|
} catch (a: ProtocolException) {
|
||||||
null
|
null
|
||||||
} ?: return Observable.just(anime)
|
} ?: return anime
|
||||||
|
|
||||||
// Get cover
|
// Get cover
|
||||||
|
|
||||||
@ -251,28 +248,26 @@ class GoogleDrive : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Observable.just(anime)
|
return anime
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun animeDetailsParse(response: Response): SAnime = throw Exception("Not used")
|
override fun animeDetailsParse(response: Response): SAnime = throw Exception("Not used")
|
||||||
|
|
||||||
// ============================== Episodes ==============================
|
// ============================== Episodes ==============================
|
||||||
|
|
||||||
override fun fetchEpisodeList(anime: SAnime): Observable<List<SEpisode>> {
|
override suspend fun getEpisodeList(anime: SAnime): List<SEpisode> {
|
||||||
val episodeList = mutableListOf<SEpisode>()
|
val episodeList = mutableListOf<SEpisode>()
|
||||||
val parsed = json.decodeFromString<LinkData>(anime.url)
|
val parsed = json.decodeFromString<LinkData>(anime.url)
|
||||||
|
|
||||||
if (parsed.type == "single") {
|
if (parsed.type == "single") {
|
||||||
return Observable.just(
|
return listOf(
|
||||||
listOf(
|
SEpisode.create().apply {
|
||||||
SEpisode.create().apply {
|
name = "Video"
|
||||||
name = "Video"
|
scanlator = parsed.info!!.size
|
||||||
scanlator = parsed.info!!.size
|
url = parsed.url
|
||||||
url = parsed.url
|
episode_number = 1F
|
||||||
episode_number = 1F
|
date_upload = -1L
|
||||||
date_upload = -1L
|
},
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,15 +349,15 @@ class GoogleDrive : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
|
|
||||||
traverseFolder(parsed.url, "")
|
traverseFolder(parsed.url, "")
|
||||||
|
|
||||||
return Observable.just(episodeList.reversed())
|
return episodeList.reversed()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun episodeListParse(response: Response): List<SEpisode> = throw Exception("Not used")
|
override fun episodeListParse(response: Response): List<SEpisode> = throw Exception("Not used")
|
||||||
|
|
||||||
// ============================ Video Links =============================
|
// ============================ Video Links =============================
|
||||||
|
|
||||||
override fun fetchVideoList(episode: SEpisode): Observable<List<Video>> =
|
override suspend fun getVideoList(episode: SEpisode): List<Video> =
|
||||||
Observable.just(GoogleDriveExtractor(client, headers).videosFromUrl(episode.url))
|
GoogleDriveExtractor(client, headers).videosFromUrl(episode.url)
|
||||||
|
|
||||||
// ============================= Utilities ==============================
|
// ============================= Utilities ==============================
|
||||||
|
|
||||||
@ -508,11 +503,6 @@ class GoogleDrive : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
return AnimesPage(animeList, nextPageToken != null)
|
return AnimesPage(animeList, nextPageToken != null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <reified T> Response.parseAs(transform: (String) -> String = { it }): T {
|
|
||||||
val responseBody = use { transform(it.body.string()) }
|
|
||||||
return json.decodeFromString(responseBody)
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://github.com/yt-dlp/yt-dlp/blob/8f0be90ecb3b8d862397177bb226f17b245ef933/yt_dlp/extractor/youtube.py#L573
|
// https://github.com/yt-dlp/yt-dlp/blob/8f0be90ecb3b8d862397177bb226f17b245ef933/yt_dlp/extractor/youtube.py#L573
|
||||||
private fun generateSapisidhashHeader(
|
private fun generateSapisidhashHeader(
|
||||||
SAPISID: String,
|
SAPISID: String,
|
||||||
|
@ -7,7 +7,6 @@ ext {
|
|||||||
pkgNameSuffix = 'all.googledriveindex'
|
pkgNameSuffix = 'all.googledriveindex'
|
||||||
extClass = '.GoogleDriveIndex'
|
extClass = '.GoogleDriveIndex'
|
||||||
extVersionCode = 7
|
extVersionCode = 7
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
@ -21,19 +21,18 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
|||||||
import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource
|
import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource
|
||||||
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.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.awaitSuccess
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import eu.kanade.tachiyomi.util.parseAs
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.Credentials
|
import okhttp3.Credentials
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.MediaType.Companion.toMediaType
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.RequestBody.Companion.toRequestBody
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import rx.Observable
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
@ -59,7 +58,7 @@ class GoogleDriveIndex : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
override val client = network.client.newBuilder()
|
||||||
.addInterceptor { chain ->
|
.addInterceptor { chain ->
|
||||||
var request = chain.request()
|
var request = chain.request()
|
||||||
|
|
||||||
@ -119,29 +118,22 @@ class GoogleDriveIndex : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
|
|
||||||
override fun searchAnimeParse(response: Response): AnimesPage = throw Exception("Not used")
|
override fun searchAnimeParse(response: Response): AnimesPage = throw Exception("Not used")
|
||||||
|
|
||||||
override fun fetchSearchAnime(
|
override suspend fun getSearchAnime(
|
||||||
page: Int,
|
page: Int,
|
||||||
query: String,
|
query: String,
|
||||||
filters: AnimeFilterList,
|
filters: AnimeFilterList,
|
||||||
): Observable<AnimesPage> {
|
): AnimesPage {
|
||||||
val filterList = if (filters.isEmpty()) getFilterList() else filters
|
val filterList = if (filters.isEmpty()) getFilterList() else filters
|
||||||
val urlFilter = filterList.find { it is URLFilter } as URLFilter
|
val urlFilter = filterList.find { it is URLFilter } as URLFilter
|
||||||
|
|
||||||
return if (urlFilter.state.isEmpty()) {
|
return if (urlFilter.state.isEmpty()) {
|
||||||
val req = searchAnimeRequest(page, query, filters)
|
val req = searchAnimeRequest(page, query, filters)
|
||||||
Observable.defer {
|
client.newCall(req).awaitSuccess()
|
||||||
try {
|
.use { response ->
|
||||||
client.newCall(req).asObservableSuccess()
|
searchAnimeParse(response, req.url.toString())
|
||||||
} catch (e: NoClassDefFoundError) {
|
|
||||||
// RxJava doesn't handle Errors, which tends to happen during global searches
|
|
||||||
// if an old extension using non-existent classes is still around
|
|
||||||
throw RuntimeException(e)
|
|
||||||
}
|
}
|
||||||
}.map { response ->
|
|
||||||
searchAnimeParse(response, req.url.toString())
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Observable.just(addSinglePage(urlFilter.state))
|
addSinglePage(urlFilter.state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,7 +229,7 @@ class GoogleDriveIndex : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
|
|
||||||
// =========================== Anime Details ============================
|
// =========================== Anime Details ============================
|
||||||
|
|
||||||
override fun fetchAnimeDetails(anime: SAnime): Observable<SAnime> {
|
override suspend fun getAnimeDetails(anime: SAnime): SAnime {
|
||||||
val parsed = json.decodeFromString<LinkData>(anime.url)
|
val parsed = json.decodeFromString<LinkData>(anime.url)
|
||||||
val newParsed = if (parsed.type != "search") {
|
val newParsed = if (parsed.type != "search") {
|
||||||
parsed
|
parsed
|
||||||
@ -265,7 +257,7 @@ class GoogleDriveIndex : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (newParsed.type == "single") {
|
if (newParsed.type == "single") {
|
||||||
return Observable.just(anime)
|
return anime
|
||||||
}
|
}
|
||||||
|
|
||||||
var newToken: String? = ""
|
var newToken: String? = ""
|
||||||
@ -309,14 +301,14 @@ class GoogleDriveIndex : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
newPageIndex += 1
|
newPageIndex += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return Observable.just(anime)
|
return anime
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun animeDetailsParse(response: Response): SAnime = throw Exception("Not used")
|
override fun animeDetailsParse(response: Response): SAnime = throw Exception("Not used")
|
||||||
|
|
||||||
// ============================== Episodes ==============================
|
// ============================== Episodes ==============================
|
||||||
|
|
||||||
override fun fetchEpisodeList(anime: SAnime): Observable<List<SEpisode>> {
|
override suspend fun getEpisodeList(anime: SAnime): List<SEpisode> {
|
||||||
val episodeList = mutableListOf<SEpisode>()
|
val episodeList = mutableListOf<SEpisode>()
|
||||||
val parsed = json.decodeFromString<LinkData>(anime.url)
|
val parsed = json.decodeFromString<LinkData>(anime.url)
|
||||||
var counter = 1
|
var counter = 1
|
||||||
@ -446,14 +438,14 @@ class GoogleDriveIndex : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
traverseDirectory(newParsed.url)
|
traverseDirectory(newParsed.url)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Observable.just(episodeList.reversed())
|
return episodeList.reversed()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun episodeListParse(response: Response): List<SEpisode> = throw Exception("Not used")
|
override fun episodeListParse(response: Response): List<SEpisode> = throw Exception("Not used")
|
||||||
|
|
||||||
// ============================ Video Links =============================
|
// ============================ Video Links =============================
|
||||||
|
|
||||||
override fun fetchVideoList(episode: SEpisode): Observable<List<Video>> {
|
override suspend fun getVideoList(episode: SEpisode): List<Video> {
|
||||||
val url = episode.url
|
val url = episode.url
|
||||||
|
|
||||||
val doc = client.newCall(
|
val doc = client.newCall(
|
||||||
@ -462,10 +454,10 @@ class GoogleDriveIndex : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
|
|
||||||
val script = doc.selectFirst("script:containsData(videodomain)")?.data()
|
val script = doc.selectFirst("script:containsData(videodomain)")?.data()
|
||||||
?: doc.selectFirst("script:containsData(downloaddomain)")?.data()
|
?: doc.selectFirst("script:containsData(downloaddomain)")?.data()
|
||||||
?: return Observable.just(listOf(Video(url, "Video", url)))
|
?: return listOf(Video(url, "Video", url))
|
||||||
|
|
||||||
if (script.contains("\"second_domain_for_dl\":false")) {
|
if (script.contains("\"second_domain_for_dl\":false")) {
|
||||||
return Observable.just(listOf(Video(url, "Video", url)))
|
return listOf(Video(url, "Video", url))
|
||||||
}
|
}
|
||||||
|
|
||||||
val domainUrl = if (script.contains("videodomain", true)) {
|
val domainUrl = if (script.contains("videodomain", true)) {
|
||||||
@ -484,18 +476,10 @@ class GoogleDriveIndex : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
domainUrl + url.toHttpUrl().encodedPath
|
domainUrl + url.toHttpUrl().encodedPath
|
||||||
}
|
}
|
||||||
|
|
||||||
return Observable.just(
|
return listOf(Video(videoUrl, "Video", videoUrl))
|
||||||
listOf(Video(videoUrl, "Video", videoUrl)),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================= Utilities ==============================
|
// ============================= Utilities ==============================
|
||||||
|
|
||||||
private inline fun <reified T> Response.parseAs(transform: (String) -> String = { it }): T {
|
|
||||||
val responseBody = use { transform(it.body.string()) }
|
|
||||||
return json.decodeFromString(responseBody)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun HttpUrl.hostAndCred(): String {
|
private fun HttpUrl.hostAndCred(): String {
|
||||||
return if (this.password.isNotBlank() && this.username.isNotBlank()) {
|
return if (this.password.isNotBlank() && this.username.isNotBlank()) {
|
||||||
"${this.username}:${this.password}@${this.host}"
|
"${this.username}:${this.password}@${this.host}"
|
||||||
|
@ -8,7 +8,6 @@ ext {
|
|||||||
pkgNameSuffix = 'all.javguru'
|
pkgNameSuffix = 'all.javguru'
|
||||||
extClass = '.JavGuru'
|
extClass = '.JavGuru'
|
||||||
extVersionCode = 9
|
extVersionCode = 9
|
||||||
libVersion = '13'
|
|
||||||
containsNsfw = true
|
containsNsfw = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,20 +20,16 @@ import eu.kanade.tachiyomi.lib.mixdropextractor.MixDropExtractor
|
|||||||
import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
|
import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
|
||||||
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
|
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.asObservable
|
import eu.kanade.tachiyomi.network.await
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.awaitSuccess
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.coroutines.Dispatchers
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import okhttp3.Call
|
import okhttp3.Call
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.jsoup.select.Elements
|
import org.jsoup.select.Elements
|
||||||
import rx.Observable
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
@ -48,8 +44,6 @@ class JavGuru : AnimeHttpSource(), ConfigurableAnimeSource {
|
|||||||
|
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
override val client = network.cloudflareClient
|
|
||||||
|
|
||||||
private val noRedirectClient = client.newBuilder()
|
private val noRedirectClient = client.newBuilder()
|
||||||
.followRedirects(false)
|
.followRedirects(false)
|
||||||
.build()
|
.build()
|
||||||
@ -60,13 +54,13 @@ class JavGuru : AnimeHttpSource(), ConfigurableAnimeSource {
|
|||||||
|
|
||||||
private lateinit var popularElements: Elements
|
private lateinit var popularElements: Elements
|
||||||
|
|
||||||
override fun fetchPopularAnime(page: Int): Observable<AnimesPage> {
|
override suspend fun getPopularAnime(page: Int): AnimesPage {
|
||||||
return if (page == 1) {
|
return if (page == 1) {
|
||||||
client.newCall(popularAnimeRequest(page))
|
client.newCall(popularAnimeRequest(page))
|
||||||
.asObservableSuccess()
|
.awaitSuccess()
|
||||||
.map(::popularAnimeParse)
|
.use(::popularAnimeParse)
|
||||||
} else {
|
} else {
|
||||||
Observable.just(cachedPopularAnimeParse(page))
|
cachedPopularAnimeParse(page)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,22 +120,22 @@ class JavGuru : AnimeHttpSource(), ConfigurableAnimeSource {
|
|||||||
return AnimesPage(entries, page < lastPage)
|
return AnimesPage(entries, page < lastPage)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable<AnimesPage> {
|
override suspend fun getSearchAnime(page: Int, query: String, filters: AnimeFilterList): AnimesPage {
|
||||||
if (query.startsWith(PREFIX_ID)) {
|
if (query.startsWith(PREFIX_ID)) {
|
||||||
val id = query.substringAfter(PREFIX_ID)
|
val id = query.substringAfter(PREFIX_ID)
|
||||||
if (id.toIntOrNull() == null) {
|
if (id.toIntOrNull() == null) {
|
||||||
return Observable.just(AnimesPage(emptyList(), false))
|
return AnimesPage(emptyList(), false)
|
||||||
}
|
}
|
||||||
val url = "/$id/"
|
val url = "/$id/"
|
||||||
val tempAnime = SAnime.create().apply { this.url = url }
|
val tempAnime = SAnime.create().apply { this.url = url }
|
||||||
return fetchAnimeDetails(tempAnime).map {
|
return getAnimeDetails(tempAnime).let {
|
||||||
val anime = it.apply { this.url = url }
|
val anime = it.apply { this.url = url }
|
||||||
AnimesPage(listOf(anime), false)
|
AnimesPage(listOf(anime), false)
|
||||||
}
|
}
|
||||||
} else if (query.isNotEmpty()) {
|
} else if (query.isNotEmpty()) {
|
||||||
return client.newCall(searchAnimeRequest(page, query, filters))
|
return client.newCall(searchAnimeRequest(page, query, filters))
|
||||||
.asObservableSuccess()
|
.awaitSuccess()
|
||||||
.map(::searchAnimeParse)
|
.use(::searchAnimeParse)
|
||||||
} else {
|
} else {
|
||||||
filters.forEach { filter ->
|
filters.forEach { filter ->
|
||||||
when (filter) {
|
when (filter) {
|
||||||
@ -152,8 +146,8 @@ class JavGuru : AnimeHttpSource(), ConfigurableAnimeSource {
|
|||||||
val url = "$baseUrl${filter.toUrlPart()}" + if (page > 1) "page/$page/" else ""
|
val url = "$baseUrl${filter.toUrlPart()}" + if (page > 1) "page/$page/" else ""
|
||||||
val request = GET(url, headers)
|
val request = GET(url, headers)
|
||||||
return client.newCall(request)
|
return client.newCall(request)
|
||||||
.asObservableSuccess()
|
.awaitSuccess()
|
||||||
.map(::searchAnimeParse)
|
.use(::searchAnimeParse)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is ActressFilter,
|
is ActressFilter,
|
||||||
@ -165,8 +159,8 @@ class JavGuru : AnimeHttpSource(), ConfigurableAnimeSource {
|
|||||||
val url = "$baseUrl${filter.toUrlPart()}" + if (page > 1) "page/$page/" else ""
|
val url = "$baseUrl${filter.toUrlPart()}" + if (page > 1) "page/$page/" else ""
|
||||||
val request = GET(url, headers)
|
val request = GET(url, headers)
|
||||||
return client.newCall(request)
|
return client.newCall(request)
|
||||||
.asObservableIgnoreCode(404)
|
.awaitIgnoreCode(404)
|
||||||
.map(::searchAnimeParse)
|
.use(::searchAnimeParse)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> { }
|
else -> { }
|
||||||
@ -218,14 +212,12 @@ class JavGuru : AnimeHttpSource(), ConfigurableAnimeSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fetchEpisodeList(anime: SAnime): Observable<List<SEpisode>> {
|
override suspend fun getEpisodeList(anime: SAnime): List<SEpisode> {
|
||||||
return Observable.just(
|
return listOf(
|
||||||
listOf(
|
SEpisode.create().apply {
|
||||||
SEpisode.create().apply {
|
url = anime.url
|
||||||
url = anime.url
|
name = "Episode"
|
||||||
name = "Episode"
|
},
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,8 +234,7 @@ class JavGuru : AnimeHttpSource(), ConfigurableAnimeSource {
|
|||||||
|
|
||||||
return iframeUrls
|
return iframeUrls
|
||||||
.mapNotNull(::resolveHosterUrl)
|
.mapNotNull(::resolveHosterUrl)
|
||||||
.parallelMap(::getVideos)
|
.parallelCatchingFlatMapBlocking(::getVideos)
|
||||||
.flatten()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveHosterUrl(iframeUrl: String): String? {
|
private fun resolveHosterUrl(iframeUrl: String): String? {
|
||||||
@ -289,37 +280,33 @@ class JavGuru : AnimeHttpSource(), ConfigurableAnimeSource {
|
|||||||
private val emTurboExtractor by lazy { EmTurboExtractor(client, headers) }
|
private val emTurboExtractor by lazy { EmTurboExtractor(client, headers) }
|
||||||
|
|
||||||
private fun getVideos(hosterUrl: String): List<Video> {
|
private fun getVideos(hosterUrl: String): List<Video> {
|
||||||
return runCatching {
|
return when {
|
||||||
when {
|
hosterUrl.contains("javplaya") -> {
|
||||||
hosterUrl.contains("javplaya") -> {
|
streamWishExtractor.videosFromUrl(hosterUrl)
|
||||||
streamWishExtractor.videosFromUrl(hosterUrl)
|
|
||||||
}
|
|
||||||
|
|
||||||
hosterUrl.contains("streamtape") -> {
|
|
||||||
streamTapeExtractor.videoFromUrl(hosterUrl).let(::listOfNotNull)
|
|
||||||
}
|
|
||||||
|
|
||||||
hosterUrl.contains("dood") -> {
|
|
||||||
doodExtractor.videosFromUrl(hosterUrl)
|
|
||||||
}
|
|
||||||
|
|
||||||
MIXDROP_DOMAINS.any { it in hosterUrl } -> {
|
|
||||||
mixDropExtractor.videoFromUrl(hosterUrl)
|
|
||||||
}
|
|
||||||
|
|
||||||
hosterUrl.contains("maxstream") -> {
|
|
||||||
maxStreamExtractor.videoFromUrl(hosterUrl)
|
|
||||||
}
|
|
||||||
|
|
||||||
hosterUrl.contains("emturbovid") -> {
|
|
||||||
emTurboExtractor.getVideos(hosterUrl)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}.getOrDefault(emptyList())
|
|
||||||
|
hosterUrl.contains("streamtape") -> {
|
||||||
|
streamTapeExtractor.videoFromUrl(hosterUrl).let(::listOfNotNull)
|
||||||
|
}
|
||||||
|
|
||||||
|
hosterUrl.contains("dood") -> {
|
||||||
|
doodExtractor.videosFromUrl(hosterUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
MIXDROP_DOMAINS.any { it in hosterUrl } -> {
|
||||||
|
mixDropExtractor.videoFromUrl(hosterUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
hosterUrl.contains("maxstream") -> {
|
||||||
|
maxStreamExtractor.videoFromUrl(hosterUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
hosterUrl.contains("emturbovid") -> {
|
||||||
|
emTurboExtractor.getVideos(hosterUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> emptyList()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun List<Video>.sort(): List<Video> {
|
override fun List<Video>.sort(): List<Video> {
|
||||||
@ -330,11 +317,6 @@ class JavGuru : AnimeHttpSource(), ConfigurableAnimeSource {
|
|||||||
).reversed()
|
).reversed()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <A, B> Iterable<A>.parallelMap(f: suspend (A) -> B): List<B> =
|
|
||||||
runBlocking {
|
|
||||||
map { async(Dispatchers.Default) { f(it) } }.awaitAll()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getIDFromUrl(element: Elements): String? {
|
private fun getIDFromUrl(element: Elements): String? {
|
||||||
return element.attr("abs:href")
|
return element.attr("abs:href")
|
||||||
.toHttpUrlOrNull()
|
.toHttpUrlOrNull()
|
||||||
@ -353,8 +335,8 @@ class JavGuru : AnimeHttpSource(), ConfigurableAnimeSource {
|
|||||||
?.last()
|
?.last()
|
||||||
?.toIntOrNull()
|
?.toIntOrNull()
|
||||||
|
|
||||||
private fun Call.asObservableIgnoreCode(code: Int): Observable<Response> {
|
private suspend fun Call.awaitIgnoreCode(code: Int): Response {
|
||||||
return asObservable().doOnNext { response ->
|
return await().also { response ->
|
||||||
if (!response.isSuccessful && response.code != code) {
|
if (!response.isSuccessful && response.code != code) {
|
||||||
response.close()
|
response.close()
|
||||||
throw Exception("HTTP error ${response.code}")
|
throw Exception("HTTP error ${response.code}")
|
||||||
|
@ -9,7 +9,6 @@ ext {
|
|||||||
pkgNameSuffix = 'all.jellyfin'
|
pkgNameSuffix = 'all.jellyfin'
|
||||||
extClass = '.JellyfinFactory'
|
extClass = '.JellyfinFactory'
|
||||||
extVersionCode = 11
|
extVersionCode = 11
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
@ -19,7 +19,8 @@ import eu.kanade.tachiyomi.animesource.model.Track
|
|||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
import eu.kanade.tachiyomi.animesource.model.Video
|
||||||
import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource
|
import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.awaitSuccess
|
||||||
|
import eu.kanade.tachiyomi.util.parseAs
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@ -31,7 +32,6 @@ import okhttp3.OkHttpClient
|
|||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
import rx.Observable
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
@ -135,10 +135,10 @@ class Jellyfin(private val suffix: String) : ConfigurableAnimeSource, AnimeHttpS
|
|||||||
|
|
||||||
override fun popularAnimeParse(response: Response): AnimesPage = throw Exception("Not used")
|
override fun popularAnimeParse(response: Response): AnimesPage = throw Exception("Not used")
|
||||||
|
|
||||||
override fun fetchPopularAnime(page: Int): Observable<AnimesPage> {
|
override suspend fun getPopularAnime(page: Int): AnimesPage {
|
||||||
return client.newCall(popularAnimeRequest(page))
|
return client.newCall(popularAnimeRequest(page))
|
||||||
.asObservableSuccess()
|
.awaitSuccess()
|
||||||
.map { response ->
|
.use { response ->
|
||||||
popularAnimeParsePage(response, page)
|
popularAnimeParsePage(response, page)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,10 +175,10 @@ class Jellyfin(private val suffix: String) : ConfigurableAnimeSource, AnimeHttpS
|
|||||||
|
|
||||||
override fun latestUpdatesParse(response: Response) = throw Exception("Not used")
|
override fun latestUpdatesParse(response: Response) = throw Exception("Not used")
|
||||||
|
|
||||||
override fun fetchLatestUpdates(page: Int): Observable<AnimesPage> {
|
override suspend fun getLatestUpdates(page: Int): AnimesPage {
|
||||||
return client.newCall(latestUpdatesRequest(page))
|
return client.newCall(latestUpdatesRequest(page))
|
||||||
.asObservableSuccess()
|
.awaitSuccess()
|
||||||
.map { response ->
|
.use { response ->
|
||||||
latestUpdatesParsePage(response, page)
|
latestUpdatesParsePage(response, page)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -211,7 +211,7 @@ class Jellyfin(private val suffix: String) : ConfigurableAnimeSource, AnimeHttpS
|
|||||||
|
|
||||||
override fun searchAnimeParse(response: Response) = throw Exception("Not used")
|
override fun searchAnimeParse(response: Response) = throw Exception("Not used")
|
||||||
|
|
||||||
override fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable<AnimesPage> {
|
override suspend fun getSearchAnime(page: Int, query: String, filters: AnimeFilterList): AnimesPage {
|
||||||
require(parentId.isNotEmpty()) { "Select library in the extension settings." }
|
require(parentId.isNotEmpty()) { "Select library in the extension settings." }
|
||||||
val startIndex = (page - 1) * 5
|
val startIndex = (page - 1) * 5
|
||||||
|
|
||||||
@ -240,7 +240,7 @@ class Jellyfin(private val suffix: String) : ConfigurableAnimeSource, AnimeHttpS
|
|||||||
getAnimeFromId(it.Id)
|
getAnimeFromId(it.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Observable.just(AnimesPage(animeList, 5 * page < items.TotalRecordCount))
|
return AnimesPage(animeList, 5 * page < items.TotalRecordCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getAnimeFromMovie(movieList: List<ItemsResponse.Item>): List<SAnime> {
|
private fun getAnimeFromMovie(movieList: List<ItemsResponse.Item>): List<SAnime> {
|
||||||
@ -557,11 +557,6 @@ class Jellyfin(private val suffix: String) : ConfigurableAnimeSource, AnimeHttpS
|
|||||||
return json.encodeToString(this)
|
return json.encodeToString(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <reified T> Response.parseAs(transform: (String) -> String = { it }): T {
|
|
||||||
val responseBody = use { transform(it.body.string()) }
|
|
||||||
return json.decodeFromString(responseBody)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||||
val mediaLibPref = medialibPreference(screen)
|
val mediaLibPref = medialibPreference(screen)
|
||||||
screen.addPreference(
|
screen.addPreference(
|
||||||
|
@ -5,6 +5,7 @@ import android.os.Build
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import eu.kanade.tachiyomi.AppInfo
|
import eu.kanade.tachiyomi.AppInfo
|
||||||
import eu.kanade.tachiyomi.network.POST
|
import eu.kanade.tachiyomi.network.POST
|
||||||
|
import eu.kanade.tachiyomi.util.parseAs
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.buildJsonObject
|
import kotlinx.serialization.json.buildJsonObject
|
||||||
@ -13,7 +14,6 @@ import okhttp3.Headers
|
|||||||
import okhttp3.MediaType.Companion.toMediaType
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.RequestBody.Companion.toRequestBody
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
import okhttp3.Response
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
class JellyfinAuthenticator(
|
class JellyfinAuthenticator(
|
||||||
@ -84,11 +84,6 @@ class JellyfinAuthenticator(
|
|||||||
value,
|
value,
|
||||||
).apply()
|
).apply()
|
||||||
|
|
||||||
private inline fun <reified T> Response.parseAs(transform: (String) -> String = { it }): T {
|
|
||||||
val responseBody = use { transform(it.body.string()) }
|
|
||||||
return json.decodeFromString(responseBody)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val DEVICEID_KEY = "device_id"
|
private const val DEVICEID_KEY = "device_id"
|
||||||
private const val CLIENT = "Aniyomi"
|
private const val CLIENT = "Aniyomi"
|
||||||
|
@ -9,7 +9,6 @@ ext {
|
|||||||
pkgNameSuffix = 'all.kamyroll'
|
pkgNameSuffix = 'all.kamyroll'
|
||||||
extClass = '.Yomiroll'
|
extClass = '.Yomiroll'
|
||||||
extVersionCode = 29
|
extVersionCode = 29
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
@ -16,12 +16,12 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
|||||||
import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource
|
import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource
|
||||||
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.parallelCatchingFlatMap
|
||||||
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
|
||||||
|
import eu.kanade.tachiyomi.util.parallelMapNotNullBlocking
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.MainScope
|
import kotlinx.coroutines.MainScope
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
@ -30,7 +30,6 @@ import kotlinx.serialization.json.jsonObject
|
|||||||
import okhttp3.FormBody
|
import okhttp3.FormBody
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import rx.Observable
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
@ -176,7 +175,7 @@ class Yomiroll : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fetchAnimeDetails(anime: SAnime): Observable<SAnime> {
|
override suspend fun getAnimeDetails(anime: SAnime): SAnime {
|
||||||
val mediaId = json.decodeFromString<LinkData>(anime.url)
|
val mediaId = json.decodeFromString<LinkData>(anime.url)
|
||||||
val resp = client.newCall(
|
val resp = client.newCall(
|
||||||
if (mediaId.media_type == "series") {
|
if (mediaId.media_type == "series") {
|
||||||
@ -186,9 +185,7 @@ class Yomiroll : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
},
|
},
|
||||||
).execute().use { it.body.string() }
|
).execute().use { it.body.string() }
|
||||||
val info = json.decodeFromString<AnimeResult>(resp)
|
val info = json.decodeFromString<AnimeResult>(resp)
|
||||||
return Observable.just(
|
return info.data.first().toSAnimeOrNull(anime) ?: anime
|
||||||
info.data.first().toSAnimeOrNull(anime) ?: anime,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun animeDetailsParse(response: Response): SAnime = throw Exception("not used")
|
override fun animeDetailsParse(response: Response): SAnime = throw Exception("not used")
|
||||||
@ -210,11 +207,7 @@ class Yomiroll : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
val chunkSize = Runtime.getRuntime().availableProcessors()
|
val chunkSize = Runtime.getRuntime().availableProcessors()
|
||||||
return if (series) {
|
return if (series) {
|
||||||
seasons.data.sortedBy { it.season_number }.chunked(chunkSize).flatMap { chunk ->
|
seasons.data.sortedBy { it.season_number }.chunked(chunkSize).flatMap { chunk ->
|
||||||
chunk.parallelMap { seasonData ->
|
chunk.parallelCatchingFlatMapBlocking(::getEpisodes)
|
||||||
runCatching {
|
|
||||||
getEpisodes(seasonData)
|
|
||||||
}.getOrNull()
|
|
||||||
}.filterNotNull().flatten()
|
|
||||||
}.reversed()
|
}.reversed()
|
||||||
} else {
|
} else {
|
||||||
seasons.data.mapIndexed { index, movie ->
|
seasons.data.mapIndexed { index, movie ->
|
||||||
@ -263,7 +256,7 @@ class Yomiroll : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
|
|
||||||
// ============================ Video Links =============================
|
// ============================ Video Links =============================
|
||||||
|
|
||||||
override fun fetchVideoList(episode: SEpisode): Observable<List<Video>> {
|
override suspend fun getVideoList(episode: SEpisode): List<Video> {
|
||||||
val urlJson = json.decodeFromString<EpisodeData>(episode.url)
|
val urlJson = json.decodeFromString<EpisodeData>(episode.url)
|
||||||
val dubLocale = preferences.getString(PREF_AUD_KEY, PREF_AUD_DEFAULT)!!
|
val dubLocale = preferences.getString(PREF_AUD_KEY, PREF_AUD_DEFAULT)!!
|
||||||
|
|
||||||
@ -276,13 +269,9 @@ class Yomiroll : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
it.second == "en-US" ||
|
it.second == "en-US" ||
|
||||||
it.second == "" ||
|
it.second == "" ||
|
||||||
if (isUsingLocalToken) it.second == urlJson.ids.first().second else false
|
if (isUsingLocalToken) it.second == urlJson.ids.first().second else false
|
||||||
}.parallelMap { media ->
|
}.parallelCatchingFlatMap(::extractVideo)
|
||||||
runCatching {
|
|
||||||
extractVideo(media)
|
|
||||||
}.getOrNull()
|
|
||||||
}.filterNotNull().flatten()
|
|
||||||
|
|
||||||
return Observable.just(videoList.sort())
|
return videoList.sort()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================= Utilities ==============================
|
// ============================= Utilities ==============================
|
||||||
@ -314,11 +303,11 @@ class Yomiroll : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
audLang: String,
|
audLang: String,
|
||||||
subsList: List<Track>,
|
subsList: List<Track>,
|
||||||
): List<Video> {
|
): List<Video> {
|
||||||
return streams.streams?.adaptive_hls?.entries?.parallelMap { (_, value) ->
|
return streams.streams?.adaptive_hls?.entries?.parallelMapNotNullBlocking { (_, value) ->
|
||||||
val stream = json.decodeFromString<HlsLinks>(value.jsonObject.toString())
|
val stream = json.decodeFromString<HlsLinks>(value.jsonObject.toString())
|
||||||
runCatching {
|
runCatching {
|
||||||
val playlist = client.newCall(GET(stream.url)).execute()
|
val playlist = client.newCall(GET(stream.url)).execute()
|
||||||
if (playlist.code != 200) return@parallelMap null
|
if (playlist.code != 200) return@parallelMapNotNullBlocking null
|
||||||
playlist.use { it.body.string() }.substringAfter("#EXT-X-STREAM-INF:")
|
playlist.use { it.body.string() }.substringAfter("#EXT-X-STREAM-INF:")
|
||||||
.split("#EXT-X-STREAM-INF:").map {
|
.split("#EXT-X-STREAM-INF:").map {
|
||||||
val hardsub = stream.hardsub_locale.let { hs ->
|
val hardsub = stream.hardsub_locale.let { hs ->
|
||||||
@ -342,7 +331,7 @@ class Yomiroll : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.getOrNull()
|
}.getOrNull()
|
||||||
}?.filterNotNull()?.flatten() ?: emptyList()
|
}?.flatten() ?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getVideoRequest(mediaId: String): Request {
|
private fun getVideoRequest(mediaId: String): Request {
|
||||||
@ -421,7 +410,9 @@ class Yomiroll : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
val media = json.decodeFromString<LinkData>(anime.url)
|
val media = json.decodeFromString<LinkData>(anime.url)
|
||||||
if (media.media_type == "series") {
|
if (media.media_type == "series") {
|
||||||
fetchStatusByTitle(this@toSAnime.title)
|
fetchStatusByTitle(this@toSAnime.title)
|
||||||
} else SAnime.COMPLETED
|
} else {
|
||||||
|
SAnime.COMPLETED
|
||||||
|
}
|
||||||
} ?: SAnime.UNKNOWN
|
} ?: SAnime.UNKNOWN
|
||||||
author = content_provider
|
author = content_provider
|
||||||
description = anime?.description ?: StringBuilder().apply {
|
description = anime?.description ?: StringBuilder().apply {
|
||||||
@ -600,12 +591,6 @@ class Yomiroll : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
}.apply { reload() }
|
}.apply { reload() }
|
||||||
|
|
||||||
// From Dopebox
|
|
||||||
private inline fun <A, B> Iterable<A>.parallelMap(crossinline f: suspend (A) -> B): List<B> =
|
|
||||||
runBlocking {
|
|
||||||
map { async(Dispatchers.Default) { f(it) } }.awaitAll()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getTokenDetail(force: Boolean = false): String {
|
private fun getTokenDetail(force: Boolean = false): String {
|
||||||
return runCatching {
|
return runCatching {
|
||||||
val storedToken = tokenInterceptor.getAccessToken(force)
|
val storedToken = tokenInterceptor.getAccessToken(force)
|
||||||
|
@ -20,7 +20,6 @@ import okhttp3.HttpUrl.Companion.toHttpUrl
|
|||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import rx.Observable
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
@ -34,8 +33,6 @@ class MissAV : AnimeHttpSource(), ConfigurableAnimeSource {
|
|||||||
|
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
override val client = network.cloudflareClient
|
|
||||||
|
|
||||||
override fun headersBuilder() = super.headersBuilder()
|
override fun headersBuilder() = super.headersBuilder()
|
||||||
.add("Referer", "$baseUrl/")
|
.add("Referer", "$baseUrl/")
|
||||||
|
|
||||||
@ -136,14 +133,12 @@ class MissAV : AnimeHttpSource(), ConfigurableAnimeSource {
|
|||||||
.joinToString()
|
.joinToString()
|
||||||
.takeIf(String::isNotBlank)
|
.takeIf(String::isNotBlank)
|
||||||
|
|
||||||
override fun fetchEpisodeList(anime: SAnime): Observable<List<SEpisode>> {
|
override suspend fun getEpisodeList(anime: SAnime): List<SEpisode> {
|
||||||
return Observable.just(
|
return listOf(
|
||||||
listOf(
|
SEpisode.create().apply {
|
||||||
SEpisode.create().apply {
|
url = anime.url
|
||||||
url = anime.url
|
name = "Episode"
|
||||||
name = "Episode"
|
},
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ ext {
|
|||||||
pkgNameSuffix = 'all.supjav'
|
pkgNameSuffix = 'all.supjav'
|
||||||
extClass = '.SupJavFactory'
|
extClass = '.SupJavFactory'
|
||||||
extVersionCode = 1
|
extVersionCode = 1
|
||||||
libVersion = '13'
|
|
||||||
containsNsfw = true
|
containsNsfw = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,18 +15,14 @@ import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
|
|||||||
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
|
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
|
||||||
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
|
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.awaitSuccess
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.coroutines.Dispatchers
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import org.jsoup.select.Elements
|
import org.jsoup.select.Elements
|
||||||
import rx.Observable
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
@ -38,8 +34,6 @@ class SupJav(override val lang: String = "en") : ConfigurableAnimeSource, Parsed
|
|||||||
|
|
||||||
override val supportsLatest = false
|
override val supportsLatest = false
|
||||||
|
|
||||||
override val client = network.cloudflareClient
|
|
||||||
|
|
||||||
override fun headersBuilder() = super.headersBuilder()
|
override fun headersBuilder() = super.headersBuilder()
|
||||||
.set("Referer", "$baseUrl/")
|
.set("Referer", "$baseUrl/")
|
||||||
.set("Origin", baseUrl)
|
.set("Origin", baseUrl)
|
||||||
@ -87,14 +81,14 @@ class SupJav(override val lang: String = "en") : ConfigurableAnimeSource, Parsed
|
|||||||
}
|
}
|
||||||
|
|
||||||
// =============================== Search ===============================
|
// =============================== Search ===============================
|
||||||
override fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable<AnimesPage> {
|
override suspend fun getSearchAnime(page: Int, query: String, filters: AnimeFilterList): AnimesPage {
|
||||||
return if (query.startsWith(PREFIX_SEARCH)) { // URL intent handler
|
return if (query.startsWith(PREFIX_SEARCH)) { // URL intent handler
|
||||||
val id = query.removePrefix(PREFIX_SEARCH)
|
val id = query.removePrefix(PREFIX_SEARCH)
|
||||||
client.newCall(GET("$baseUrl/$id"))
|
client.newCall(GET("$baseUrl/$id"))
|
||||||
.asObservableSuccess()
|
.awaitSuccess()
|
||||||
.map(::searchAnimeByIdParse)
|
.use(::searchAnimeByIdParse)
|
||||||
} else {
|
} else {
|
||||||
super.fetchSearchAnime(page, query, filters)
|
super.getSearchAnime(page, query, filters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,14 +123,14 @@ class SupJav(override val lang: String = "en") : ConfigurableAnimeSource, Parsed
|
|||||||
private fun Elements.textsOrNull() = eachText().joinToString().takeUnless(String::isEmpty)
|
private fun Elements.textsOrNull() = eachText().joinToString().takeUnless(String::isEmpty)
|
||||||
|
|
||||||
// ============================== Episodes ==============================
|
// ============================== Episodes ==============================
|
||||||
override fun fetchEpisodeList(anime: SAnime): Observable<List<SEpisode>> {
|
override suspend fun getEpisodeList(anime: SAnime): List<SEpisode> {
|
||||||
val episode = SEpisode.create().apply {
|
val episode = SEpisode.create().apply {
|
||||||
name = "JAV"
|
name = "JAV"
|
||||||
episode_number = 1F
|
episode_number = 1F
|
||||||
url = anime.url
|
url = anime.url
|
||||||
}
|
}
|
||||||
|
|
||||||
return Observable.just(listOf(episode))
|
return listOf(episode)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun episodeListSelector(): String {
|
override fun episodeListSelector(): String {
|
||||||
@ -155,7 +149,7 @@ class SupJav(override val lang: String = "en") : ConfigurableAnimeSource, Parsed
|
|||||||
.filter { it.text() in SUPPORTED_PLAYERS }
|
.filter { it.text() in SUPPORTED_PLAYERS }
|
||||||
.map { it.text() to it.attr("data-link").reversed() }
|
.map { it.text() to it.attr("data-link").reversed() }
|
||||||
|
|
||||||
return players.parallelCatchingFlatMap(::videosFromPlayer)
|
return players.parallelCatchingFlatMapBlocking(::videosFromPlayer)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val playlistUtils by lazy { PlaylistUtils(client, headers) }
|
private val playlistUtils by lazy { PlaylistUtils(client, headers) }
|
||||||
@ -227,15 +221,6 @@ class SupJav(override val lang: String = "en") : ConfigurableAnimeSource, Parsed
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================= Utilities ==============================
|
// ============================= Utilities ==============================
|
||||||
private inline fun <A, B> Iterable<A>.parallelCatchingFlatMap(crossinline f: suspend (A) -> Iterable<B>): List<B> =
|
|
||||||
runBlocking {
|
|
||||||
map {
|
|
||||||
async(Dispatchers.Default) {
|
|
||||||
runCatching { f(it) }.getOrElse { emptyList() }
|
|
||||||
}
|
|
||||||
}.awaitAll().flatten()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun List<Video>.sort(): List<Video> {
|
override fun List<Video>.sort(): List<Video> {
|
||||||
val quality = preferences.getString(PREF_QUALITY_KEY, PREF_QUALITY_DEFAULT)!!
|
val quality = preferences.getString(PREF_QUALITY_KEY, PREF_QUALITY_DEFAULT)!!
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ ext {
|
|||||||
pkgNameSuffix = 'ar.akwam'
|
pkgNameSuffix = 'ar.akwam'
|
||||||
extClass = '.Akwam'
|
extClass = '.Akwam'
|
||||||
extVersionCode = 9
|
extVersionCode = 9
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
@ -15,7 +15,6 @@ import eu.kanade.tachiyomi.network.GET
|
|||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||||
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
|
||||||
@ -34,8 +33,6 @@ class Akwam : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
override val supportsLatest = false
|
override val supportsLatest = false
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient
|
|
||||||
|
|
||||||
private val preferences: SharedPreferences by lazy {
|
private val preferences: SharedPreferences by lazy {
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ ext {
|
|||||||
pkgNameSuffix = 'ar.anime4up'
|
pkgNameSuffix = 'ar.anime4up'
|
||||||
extClass = '.Anime4Up'
|
extClass = '.Anime4Up'
|
||||||
extVersionCode = 52
|
extVersionCode = 52
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -22,10 +22,7 @@ import eu.kanade.tachiyomi.lib.vidbomextractor.VidBomExtractor
|
|||||||
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
|
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.coroutines.Dispatchers
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
@ -48,8 +45,6 @@ class Anime4Up : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
override val supportsLatest = false
|
override val supportsLatest = false
|
||||||
|
|
||||||
override val client = network.cloudflareClient
|
|
||||||
|
|
||||||
private val json: Json by injectLazy()
|
private val json: Json by injectLazy()
|
||||||
|
|
||||||
private val preferences by lazy {
|
private val preferences by lazy {
|
||||||
@ -159,7 +154,7 @@ class Anime4Up : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
val parsedData = json.decodeFromString<Qualities>(base64)
|
val parsedData = json.decodeFromString<Qualities>(base64)
|
||||||
val streamLinks = with(parsedData) { fhd + hd + sd }
|
val streamLinks = with(parsedData) { fhd + hd + sd }
|
||||||
|
|
||||||
return streamLinks.values.distinct().parallelCatchingFlatMap(::extractVideos)
|
return streamLinks.values.distinct().parallelCatchingFlatMapBlocking(::extractVideos)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val uqloadExtractor by lazy { UqloadExtractor(client) }
|
private val uqloadExtractor by lazy { UqloadExtractor(client) }
|
||||||
@ -216,15 +211,6 @@ class Anime4Up : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================= Utilities ==============================
|
// ============================= Utilities ==============================
|
||||||
private inline fun <A, B> Iterable<A>.parallelCatchingFlatMap(crossinline f: suspend (A) -> Iterable<B>): List<B> =
|
|
||||||
runBlocking {
|
|
||||||
map {
|
|
||||||
async(Dispatchers.Default) {
|
|
||||||
runCatching { f(it) }.getOrElse { emptyList() }
|
|
||||||
}
|
|
||||||
}.awaitAll().flatten()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun List<Video>.sort(): List<Video> {
|
override fun List<Video>.sort(): List<Video> {
|
||||||
val quality = preferences.getString(PREF_QUALITY_KEY, PREF_QUALITY_DEFAULT)!!
|
val quality = preferences.getString(PREF_QUALITY_KEY, PREF_QUALITY_DEFAULT)!!
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ ext {
|
|||||||
pkgNameSuffix = 'ar.animeblkom'
|
pkgNameSuffix = 'ar.animeblkom'
|
||||||
extClass = '.AnimeBlkom'
|
extClass = '.AnimeBlkom'
|
||||||
extVersionCode = 16
|
extVersionCode = 16
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -32,8 +32,6 @@ class AnimeBlkom : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
override val supportsLatest = false
|
override val supportsLatest = false
|
||||||
|
|
||||||
override val client = network.cloudflareClient
|
|
||||||
|
|
||||||
override fun headersBuilder() = super.headersBuilder()
|
override fun headersBuilder() = super.headersBuilder()
|
||||||
.add("referer", baseUrl)
|
.add("referer", baseUrl)
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ ext {
|
|||||||
pkgNameSuffix = 'ar.animeiat'
|
pkgNameSuffix = 'ar.animeiat'
|
||||||
extClass = '.Animeiat'
|
extClass = '.Animeiat'
|
||||||
extVersionCode = 1
|
extVersionCode = 1
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
@ -8,7 +8,6 @@ ext {
|
|||||||
pkgNameSuffix = 'ar.animelek'
|
pkgNameSuffix = 'ar.animelek'
|
||||||
extClass = '.AnimeLek'
|
extClass = '.AnimeLek'
|
||||||
extVersionCode = 27
|
extVersionCode = 27
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -17,7 +17,6 @@ import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
|
|||||||
import eu.kanade.tachiyomi.lib.vidbomextractor.VidBomExtractor
|
import eu.kanade.tachiyomi.lib.vidbomextractor.VidBomExtractor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
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
|
||||||
@ -36,8 +35,6 @@ class AnimeLek : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient
|
|
||||||
|
|
||||||
private val preferences: SharedPreferences by lazy {
|
private val preferences: SharedPreferences by lazy {
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ ext {
|
|||||||
pkgNameSuffix = 'ar.animerco'
|
pkgNameSuffix = 'ar.animerco'
|
||||||
extClass = '.Animerco'
|
extClass = '.Animerco'
|
||||||
extVersionCode = 34
|
extVersionCode = 34
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -23,12 +23,8 @@ import eu.kanade.tachiyomi.lib.youruploadextractor.YourUploadExtractor
|
|||||||
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.coroutines.Dispatchers
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import okhttp3.FormBody
|
import okhttp3.FormBody
|
||||||
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
|
||||||
@ -47,8 +43,6 @@ class Animerco : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
override val supportsLatest = false
|
override val supportsLatest = false
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient
|
|
||||||
|
|
||||||
private val preferences: SharedPreferences by lazy {
|
private val preferences: SharedPreferences by lazy {
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
}
|
}
|
||||||
@ -160,9 +154,7 @@ class Animerco : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
override fun videoListParse(response: Response): List<Video> {
|
override fun videoListParse(response: Response): List<Video> {
|
||||||
val document = response.use { it.asJsoup() }
|
val document = response.use { it.asJsoup() }
|
||||||
val players = document.select(videoListSelector())
|
val players = document.select(videoListSelector())
|
||||||
return players.parallelMap {
|
return players.parallelCatchingFlatMapBlocking(::getPlayerVideos)
|
||||||
runCatching { getPlayerVideos(it) }.getOrElse { emptyList() }
|
|
||||||
}.flatten()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun videoListSelector() = "li.dooplay_player_option" // ul#playeroptionsul
|
override fun videoListSelector() = "li.dooplay_player_option" // ul#playeroptionsul
|
||||||
@ -250,11 +242,6 @@ class Animerco : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================= Utilities ==============================
|
// ============================= Utilities ==============================
|
||||||
private inline fun <A, B> Iterable<A>.parallelMap(crossinline f: suspend (A) -> B): List<B> =
|
|
||||||
runBlocking {
|
|
||||||
map { async(Dispatchers.Default) { f(it) } }.awaitAll()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val PREF_QUALITY_KEY = "preferred_quality"
|
private const val PREF_QUALITY_KEY = "preferred_quality"
|
||||||
private const val PREF_QUALITY_TITLE = "Preferred quality"
|
private const val PREF_QUALITY_TITLE = "Preferred quality"
|
||||||
|
@ -9,7 +9,6 @@ ext {
|
|||||||
pkgNameSuffix = 'ar.arabanime'
|
pkgNameSuffix = 'ar.arabanime'
|
||||||
extClass = '.ArabAnime'
|
extClass = '.ArabAnime'
|
||||||
extVersionCode = 2
|
extVersionCode = 2
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
@ -38,8 +38,6 @@ class ArabAnime : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
|
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
override val client = network.cloudflareClient
|
|
||||||
|
|
||||||
private val json: Json by injectLazy()
|
private val json: Json by injectLazy()
|
||||||
|
|
||||||
private val preferences by lazy {
|
private val preferences by lazy {
|
||||||
|
@ -8,7 +8,6 @@ ext {
|
|||||||
pkgNameSuffix = 'ar.arabseed'
|
pkgNameSuffix = 'ar.arabseed'
|
||||||
extClass = '.ArabSeed'
|
extClass = '.ArabSeed'
|
||||||
extVersionCode = 9
|
extVersionCode = 9
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -18,10 +18,7 @@ import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
|
|||||||
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
|
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.coroutines.Dispatchers
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
@ -42,8 +39,6 @@ class ArabSeed : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
override val supportsLatest = false
|
override val supportsLatest = false
|
||||||
|
|
||||||
override val client = network.cloudflareClient
|
|
||||||
|
|
||||||
override fun headersBuilder() = super.headersBuilder().add("Referer", baseUrl)
|
override fun headersBuilder() = super.headersBuilder().add("Referer", baseUrl)
|
||||||
|
|
||||||
private val preferences by lazy {
|
private val preferences by lazy {
|
||||||
@ -97,11 +92,11 @@ class ArabSeed : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
override fun videoListSelector() = "div.containerServers ul li"
|
override fun videoListSelector() = "div.containerServers ul li"
|
||||||
|
|
||||||
private fun videosFromElement(document: Document): List<Video> {
|
private fun videosFromElement(document: Document): List<Video> {
|
||||||
return document.select(videoListSelector()).parallelMap { element ->
|
return document.select(videoListSelector()).parallelCatchingFlatMapBlocking { element ->
|
||||||
val quality = element.text()
|
val quality = element.text()
|
||||||
val embedUrl = element.attr("data-link")
|
val embedUrl = element.attr("data-link")
|
||||||
runCatching { getVideosFromUrl(embedUrl, quality) }.getOrElse { emptyList() }
|
getVideosFromUrl(embedUrl, quality)
|
||||||
}.flatten()
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val doodExtractor by lazy { DoodExtractor(client) }
|
private val doodExtractor by lazy { DoodExtractor(client) }
|
||||||
@ -251,11 +246,6 @@ class ArabSeed : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================= Utilities ==============================
|
// ============================= Utilities ==============================
|
||||||
private inline fun <A, B> Iterable<A>.parallelMap(crossinline f: suspend (A) -> B): List<B> =
|
|
||||||
runBlocking {
|
|
||||||
map { async(Dispatchers.Default) { f(it) } }.awaitAll()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// From egydead(ar)
|
// From egydead(ar)
|
||||||
private const val PREF_DOMAIN_KEY = "default_domain_v${BuildConfig.VERSION_NAME}"
|
private const val PREF_DOMAIN_KEY = "default_domain_v${BuildConfig.VERSION_NAME}"
|
||||||
|
@ -8,7 +8,6 @@ ext {
|
|||||||
pkgNameSuffix = 'ar.asia2tv'
|
pkgNameSuffix = 'ar.asia2tv'
|
||||||
extClass = '.Asia2TV'
|
extClass = '.Asia2TV'
|
||||||
extVersionCode = 15
|
extVersionCode = 15
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -19,12 +19,8 @@ import eu.kanade.tachiyomi.lib.uqloadextractor.UqloadExtractor
|
|||||||
import eu.kanade.tachiyomi.lib.vidbomextractor.VidBomExtractor
|
import eu.kanade.tachiyomi.lib.vidbomextractor.VidBomExtractor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.coroutines.Dispatchers
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||||
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
|
||||||
@ -43,8 +39,6 @@ class Asia2TV : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
override val supportsLatest = false
|
override val supportsLatest = false
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient
|
|
||||||
|
|
||||||
private val preferences: SharedPreferences by lazy {
|
private val preferences: SharedPreferences by lazy {
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
}
|
}
|
||||||
@ -90,7 +84,7 @@ class Asia2TV : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
override fun videoListParse(response: Response): List<Video> {
|
override fun videoListParse(response: Response): List<Video> {
|
||||||
val document = response.use { it.asJsoup() }
|
val document = response.use { it.asJsoup() }
|
||||||
return document.select(videoListSelector()).parallelCatchingFlatMap {
|
return document.select(videoListSelector()).parallelCatchingFlatMapBlocking {
|
||||||
val url = it.attr("data-server")
|
val url = it.attr("data-server")
|
||||||
getVideosFromUrl(url)
|
getVideosFromUrl(url)
|
||||||
}
|
}
|
||||||
@ -265,15 +259,6 @@ class Asia2TV : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================= Utilities ==============================
|
// ============================= Utilities ==============================
|
||||||
private inline fun <A, B> Iterable<A>.parallelCatchingFlatMap(crossinline f: suspend (A) -> Iterable<B>): List<B> =
|
|
||||||
runBlocking {
|
|
||||||
map {
|
|
||||||
async(Dispatchers.Default) {
|
|
||||||
runCatching { f(it) }.getOrElse { emptyList() }
|
|
||||||
}
|
|
||||||
}.awaitAll().flatten()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val STREAM_WISH_DOMAINS by lazy { listOf("wishfast", "fviplions", "filelions", "streamwish", "dwish") }
|
private val STREAM_WISH_DOMAINS by lazy { listOf("wishfast", "fviplions", "filelions", "streamwish", "dwish") }
|
||||||
private val VID_BOM_DOMAINS by lazy { listOf("vidbam", "vadbam", "vidbom", "vidbm") }
|
private val VID_BOM_DOMAINS by lazy { listOf("vidbam", "vadbam", "vidbom", "vidbm") }
|
||||||
|
@ -6,7 +6,6 @@ ext {
|
|||||||
pkgNameSuffix = 'ar.egydead'
|
pkgNameSuffix = 'ar.egydead'
|
||||||
extClass = '.EgyDead'
|
extClass = '.EgyDead'
|
||||||
extVersionCode = 10
|
extVersionCode = 10
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -19,13 +19,10 @@ import eu.kanade.tachiyomi.lib.mixdropextractor.MixDropExtractor
|
|||||||
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
|
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
|
||||||
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.network.await
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.coroutines.Dispatchers
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMap
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import okhttp3.FormBody
|
import okhttp3.FormBody
|
||||||
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
|
||||||
@ -46,8 +43,6 @@ class EgyDead : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient
|
|
||||||
|
|
||||||
private val preferences: SharedPreferences by lazy {
|
private val preferences: SharedPreferences by lazy {
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
}
|
}
|
||||||
@ -132,19 +127,18 @@ class EgyDead : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
// ================================== video urls ==================================
|
// ================================== video urls ==================================
|
||||||
private val streamWishExtractor by lazy { StreamWishExtractor(client, headers) }
|
private val streamWishExtractor by lazy { StreamWishExtractor(client, headers) }
|
||||||
|
|
||||||
override fun videoListParse(response: Response): List<Video> {
|
override suspend fun getVideoList(episode: SEpisode): List<Video> {
|
||||||
val requestBody = FormBody.Builder().add("View", "1").build()
|
val requestBody = FormBody.Builder().add("View", "1").build()
|
||||||
val document = client.newCall(POST(response.request.url.toString(), body = requestBody)).execute().asJsoup()
|
|
||||||
return document.select(videoListSelector()).parallelMap {
|
val document = client.newCall(POST(baseUrl + episode.url, body = requestBody))
|
||||||
|
.await()
|
||||||
|
.use { it.asJsoup() }
|
||||||
|
return document.select(videoListSelector()).parallelCatchingFlatMap {
|
||||||
val url = it.attr("data-link")
|
val url = it.attr("data-link")
|
||||||
runCatching { extractVideos(url) }.getOrElse { emptyList() }
|
extractVideos(url)
|
||||||
}.flatten()
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <A, B> Iterable<A>.parallelMap(crossinline f: suspend (A) -> B): List<B> =
|
|
||||||
runBlocking {
|
|
||||||
map { async(Dispatchers.Default) { f(it) } }.awaitAll()
|
|
||||||
}
|
|
||||||
private fun extractVideos(url: String): List<Video> {
|
private fun extractVideos(url: String): List<Video> {
|
||||||
return when {
|
return when {
|
||||||
DOOD_REGEX.containsMatchIn(url) -> {
|
DOOD_REGEX.containsMatchIn(url) -> {
|
||||||
|
@ -6,7 +6,6 @@ ext {
|
|||||||
pkgNameSuffix = 'ar.faselhd'
|
pkgNameSuffix = 'ar.faselhd'
|
||||||
extClass = '.FASELHD'
|
extClass = '.FASELHD'
|
||||||
extVersionCode = 14
|
extVersionCode = 14
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
@ -15,7 +15,6 @@ import eu.kanade.tachiyomi.network.GET
|
|||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||||
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
|
||||||
@ -34,8 +33,6 @@ class FASELHD : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient
|
|
||||||
|
|
||||||
private val preferences: SharedPreferences by lazy {
|
private val preferences: SharedPreferences by lazy {
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ ext {
|
|||||||
pkgNameSuffix = 'ar.movies4u'
|
pkgNameSuffix = 'ar.movies4u'
|
||||||
extClass = '.Movies4U'
|
extClass = '.Movies4U'
|
||||||
extVersionCode = 4
|
extVersionCode = 4
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
@ -14,7 +14,6 @@ import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
|
|||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
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
|
||||||
@ -34,8 +33,6 @@ class Movies4U : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
override val supportsLatest = false
|
override val supportsLatest = false
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient
|
|
||||||
|
|
||||||
private val preferences: SharedPreferences by lazy {
|
private val preferences: SharedPreferences by lazy {
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ ext {
|
|||||||
pkgNameSuffix = 'ar.mycima'
|
pkgNameSuffix = 'ar.mycima'
|
||||||
extClass = '.MyCima'
|
extClass = '.MyCima'
|
||||||
extVersionCode = 20
|
extVersionCode = 20
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -16,11 +16,7 @@ import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
|
|||||||
import eu.kanade.tachiyomi.lib.uqloadextractor.UqloadExtractor
|
import eu.kanade.tachiyomi.lib.uqloadextractor.UqloadExtractor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.coroutines.Dispatchers
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
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
|
||||||
@ -39,8 +35,6 @@ class MyCima : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient
|
|
||||||
|
|
||||||
private val preferences: SharedPreferences by lazy {
|
private val preferences: SharedPreferences by lazy {
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
}
|
}
|
||||||
@ -124,19 +118,17 @@ class MyCima : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
override fun videoListParse(response: Response): List<Video> {
|
override fun videoListParse(response: Response): List<Video> {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
return document.select("ul.WatchServersList li btn").parallelMap {
|
return document.select("ul.WatchServersList li btn").parallelCatchingFlatMapBlocking {
|
||||||
val frameURL = it.attr("data-url")
|
val frameURL = it.attr("data-url")
|
||||||
runCatching {
|
if (it.parent()?.hasClass("MyCimaServer") == true) {
|
||||||
if (it.parent()?.hasClass("MyCimaServer") == true) {
|
val referer = response.request.url.encodedPath
|
||||||
val referer = response.request.url.encodedPath
|
val newHeader = headers.newBuilder().add("referer", baseUrl + referer).build()
|
||||||
val newHeader = headers.newBuilder().add("referer", baseUrl + referer).build()
|
val iframeResponse = client.newCall(GET(frameURL, newHeader)).execute().asJsoup()
|
||||||
val iframeResponse = client.newCall(GET(frameURL, newHeader)).execute().asJsoup()
|
videosFromElement(iframeResponse.selectFirst(videoListSelector())!!)
|
||||||
videosFromElement(iframeResponse.selectFirst(videoListSelector())!!)
|
} else {
|
||||||
} else {
|
extractVideos(frameURL)
|
||||||
extractVideos(frameURL)
|
}
|
||||||
}
|
}
|
||||||
}.getOrElse { emptyList() }
|
|
||||||
}.flatten()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun extractVideos(url: String): List<Video> {
|
private fun extractVideos(url: String): List<Video> {
|
||||||
@ -367,10 +359,6 @@ class MyCima : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
private fun getPrefBaseUrl(): String = preferences.getString(PREF_BASE_URL_KEY, PREF_BASE_URL_DEFAULT)!!
|
private fun getPrefBaseUrl(): String = preferences.getString(PREF_BASE_URL_KEY, PREF_BASE_URL_DEFAULT)!!
|
||||||
|
|
||||||
// ============================= Utilities ===================================
|
// ============================= Utilities ===================================
|
||||||
private inline fun <A, B> Iterable<A>.parallelMap(crossinline f: suspend (A) -> B): List<B> =
|
|
||||||
runBlocking {
|
|
||||||
map { async(Dispatchers.Default) { f(it) } }.awaitAll()
|
|
||||||
}
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val PREF_QUALITY_KEY = "preferred_quality"
|
private const val PREF_QUALITY_KEY = "preferred_quality"
|
||||||
private const val PREF_QUALITY_TITLE = "Preferred quality"
|
private const val PREF_QUALITY_TITLE = "Preferred quality"
|
||||||
|
@ -8,7 +8,6 @@ ext {
|
|||||||
pkgNameSuffix = 'ar.okanime'
|
pkgNameSuffix = 'ar.okanime'
|
||||||
extClass = '.Okanime'
|
extClass = '.Okanime'
|
||||||
extVersionCode = 5
|
extVersionCode = 5
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -17,16 +17,12 @@ import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
|
|||||||
import eu.kanade.tachiyomi.lib.vidbomextractor.VidBomExtractor
|
import eu.kanade.tachiyomi.lib.vidbomextractor.VidBomExtractor
|
||||||
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
|
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.awaitSuccess
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.coroutines.Dispatchers
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import rx.Observable
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
@ -69,14 +65,14 @@ class Okanime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
override fun latestUpdatesNextPageSelector() = "ul.pagination > li:last-child:not(.disabled)"
|
override fun latestUpdatesNextPageSelector() = "ul.pagination > li:last-child:not(.disabled)"
|
||||||
|
|
||||||
// =============================== Search ===============================
|
// =============================== Search ===============================
|
||||||
override fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable<AnimesPage> {
|
override suspend fun getSearchAnime(page: Int, query: String, filters: AnimeFilterList): AnimesPage {
|
||||||
return if (query.startsWith(PREFIX_SEARCH)) { // URL intent handler
|
return if (query.startsWith(PREFIX_SEARCH)) { // URL intent handler
|
||||||
val id = query.removePrefix(PREFIX_SEARCH)
|
val id = query.removePrefix(PREFIX_SEARCH)
|
||||||
client.newCall(GET("$baseUrl/anime/$id"))
|
client.newCall(GET("$baseUrl/anime/$id"))
|
||||||
.asObservableSuccess()
|
.awaitSuccess()
|
||||||
.map(::searchAnimeByIdParse)
|
.use(::searchAnimeByIdParse)
|
||||||
} else {
|
} else {
|
||||||
super.fetchSearchAnime(page, query, filters)
|
super.getSearchAnime(page, query, filters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +137,7 @@ class Okanime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
val hosterSelection = preferences.getStringSet(PREF_HOSTER_SELECTION_KEY, PREF_HOSTER_SELECTION_DEFAULT)!!
|
val hosterSelection = preferences.getStringSet(PREF_HOSTER_SELECTION_KEY, PREF_HOSTER_SELECTION_DEFAULT)!!
|
||||||
return response.use { it.asJsoup() }
|
return response.use { it.asJsoup() }
|
||||||
.select("a.ep-link")
|
.select("a.ep-link")
|
||||||
.parallelMap { element ->
|
.parallelCatchingFlatMapBlocking { element ->
|
||||||
val quality = element.selectFirst("span")?.text().orEmpty().let {
|
val quality = element.selectFirst("span")?.text().orEmpty().let {
|
||||||
when (it) {
|
when (it) {
|
||||||
"HD" -> "720p"
|
"HD" -> "720p"
|
||||||
@ -152,7 +148,7 @@ class Okanime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
val url = element.attr("data-src")
|
val url = element.attr("data-src")
|
||||||
extractVideosFromUrl(url, quality, hosterSelection)
|
extractVideosFromUrl(url, quality, hosterSelection)
|
||||||
}.flatten()
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inspirated by JavGuru(all)
|
// Inspirated by JavGuru(all)
|
||||||
@ -163,28 +159,26 @@ class Okanime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
private val vidBomExtractor by lazy { VidBomExtractor(client) }
|
private val vidBomExtractor by lazy { VidBomExtractor(client) }
|
||||||
|
|
||||||
private fun extractVideosFromUrl(url: String, quality: String, selection: Set<String>): List<Video> {
|
private fun extractVideosFromUrl(url: String, quality: String, selection: Set<String>): List<Video> {
|
||||||
return runCatching {
|
return when {
|
||||||
when {
|
"https://doo" in url && "/e/" in url && selection.contains("Dood") -> {
|
||||||
"https://doo" in url && "/e/" in url && selection.contains("Dood") -> {
|
doodExtractor.videoFromUrl(url, "DoodStream - $quality")
|
||||||
doodExtractor.videoFromUrl(url, "DoodStream - $quality")
|
?.let(::listOf)
|
||||||
?.let(::listOf)
|
|
||||||
}
|
|
||||||
"mp4upload" in url && selection.contains("Mp4upload") -> {
|
|
||||||
mp4uploadExtractor.videosFromUrl(url, headers)
|
|
||||||
}
|
|
||||||
"ok.ru" in url && selection.contains("Okru") -> {
|
|
||||||
okruExtractor.videosFromUrl(url)
|
|
||||||
}
|
|
||||||
"voe.sx" in url && selection.contains("Voe") -> {
|
|
||||||
voeExtractor.videoFromUrl(url, "VoeSX ($quality)")
|
|
||||||
?.let(::listOf)
|
|
||||||
}
|
|
||||||
VID_BOM_DOMAINS.any(url::contains) && selection.contains("VidBom") -> {
|
|
||||||
vidBomExtractor.videosFromUrl(url)
|
|
||||||
}
|
|
||||||
else -> null
|
|
||||||
}
|
}
|
||||||
}.getOrNull() ?: emptyList()
|
"mp4upload" in url && selection.contains("Mp4upload") -> {
|
||||||
|
mp4uploadExtractor.videosFromUrl(url, headers)
|
||||||
|
}
|
||||||
|
"ok.ru" in url && selection.contains("Okru") -> {
|
||||||
|
okruExtractor.videosFromUrl(url)
|
||||||
|
}
|
||||||
|
"voe.sx" in url && selection.contains("Voe") -> {
|
||||||
|
voeExtractor.videoFromUrl(url, "VoeSX ($quality)")
|
||||||
|
?.let(::listOf)
|
||||||
|
}
|
||||||
|
VID_BOM_DOMAINS.any(url::contains) && selection.contains("VidBom") -> {
|
||||||
|
vidBomExtractor.videosFromUrl(url)
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}.orEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun videoListSelector(): String {
|
override fun videoListSelector(): String {
|
||||||
@ -238,11 +232,6 @@ class Okanime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================= Utilities ==============================
|
// ============================= Utilities ==============================
|
||||||
private inline fun <A, B> Iterable<A>.parallelMap(crossinline f: suspend (A) -> B): List<B> =
|
|
||||||
runBlocking {
|
|
||||||
map { async(Dispatchers.Default) { f(it) } }.awaitAll()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val PREFIX_SEARCH = "id:"
|
const val PREFIX_SEARCH = "id:"
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ ext {
|
|||||||
pkgNameSuffix = 'ar.tuktukcinema'
|
pkgNameSuffix = 'ar.tuktukcinema'
|
||||||
extClass = '.Tuktukcinema'
|
extClass = '.Tuktukcinema'
|
||||||
extVersionCode = 15
|
extVersionCode = 15
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -23,11 +23,7 @@ import eu.kanade.tachiyomi.lib.uqloadextractor.UqloadExtractor
|
|||||||
import eu.kanade.tachiyomi.lib.vidbomextractor.VidBomExtractor
|
import eu.kanade.tachiyomi.lib.vidbomextractor.VidBomExtractor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.coroutines.Dispatchers
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
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
|
||||||
@ -48,8 +44,6 @@ class Tuktukcinema : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient
|
|
||||||
|
|
||||||
private val preferences: SharedPreferences by lazy {
|
private val preferences: SharedPreferences by lazy {
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
}
|
}
|
||||||
@ -149,14 +143,9 @@ class Tuktukcinema : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
override fun videoListParse(response: Response): List<Video> {
|
override fun videoListParse(response: Response): List<Video> {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
return document.select(videoListSelector()).parallelMap {
|
return document.select(videoListSelector())
|
||||||
runCatching { extractVideos(it) }.getOrElse { emptyList() }
|
.parallelCatchingFlatMapBlocking(::extractVideos)
|
||||||
}.flatten()
|
|
||||||
}
|
}
|
||||||
private inline fun <A, B> Iterable<A>.parallelMap(crossinline f: suspend (A) -> B): List<B> =
|
|
||||||
runBlocking {
|
|
||||||
map { async(Dispatchers.Default) { f(it) } }.awaitAll()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun extractVideos(element: Element): List<Video> {
|
private fun extractVideos(element: Element): List<Video> {
|
||||||
val url = element.attr("data-link")
|
val url = element.attr("data-link")
|
||||||
|
@ -8,7 +8,6 @@ ext {
|
|||||||
pkgNameSuffix = 'ar.witanime'
|
pkgNameSuffix = 'ar.witanime'
|
||||||
extClass = '.WitAnime'
|
extClass = '.WitAnime'
|
||||||
extVersionCode = 47
|
extVersionCode = 47
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -19,10 +19,7 @@ import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
|
|||||||
import eu.kanade.tachiyomi.lib.vidbomextractor.VidBomExtractor
|
import eu.kanade.tachiyomi.lib.vidbomextractor.VidBomExtractor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.coroutines.Dispatchers
|
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
@ -40,8 +37,6 @@ class WitAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
override val client = network.cloudflareClient
|
|
||||||
|
|
||||||
override fun headersBuilder() = super.headersBuilder().add("Referer", baseUrl)
|
override fun headersBuilder() = super.headersBuilder().add("Referer", baseUrl)
|
||||||
|
|
||||||
private val preferences by lazy {
|
private val preferences by lazy {
|
||||||
@ -130,7 +125,7 @@ class WitAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
return document.select("ul#episode-servers li a")
|
return document.select("ul#episode-servers li a")
|
||||||
.distinctBy { it.text().substringBefore(" -") } // remove duplicates by server name
|
.distinctBy { it.text().substringBefore(" -") } // remove duplicates by server name
|
||||||
.parallelCatchingFlatMap {
|
.parallelCatchingFlatMapBlocking {
|
||||||
val url = it.attr("data-url")
|
val url = it.attr("data-url")
|
||||||
.takeUnless(String::isBlank)
|
.takeUnless(String::isBlank)
|
||||||
?.let { String(Base64.decode(it, Base64.DEFAULT)) }
|
?.let { String(Base64.decode(it, Base64.DEFAULT)) }
|
||||||
@ -237,15 +232,6 @@ class WitAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================= Utilities ==============================
|
// ============================= Utilities ==============================
|
||||||
private inline fun <A, B> Iterable<A>.parallelCatchingFlatMap(crossinline f: suspend (A) -> Iterable<B>): List<B> =
|
|
||||||
runBlocking {
|
|
||||||
map {
|
|
||||||
async(Dispatchers.Default) {
|
|
||||||
runCatching { f(it) }.getOrElse { emptyList() }
|
|
||||||
}
|
|
||||||
}.awaitAll().flatten()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getRealDoc(document: Document): Document {
|
private fun getRealDoc(document: Document): Document {
|
||||||
return document.selectFirst("div.anime-page-link a")?.let {
|
return document.selectFirst("div.anime-page-link a")?.let {
|
||||||
client.newCall(GET(it.attr("href"), headers)).execute().asJsoup()
|
client.newCall(GET(it.attr("href"), headers)).execute().asJsoup()
|
||||||
|
@ -6,7 +6,6 @@ ext {
|
|||||||
pkgNameSuffix = 'ar.xsanime'
|
pkgNameSuffix = 'ar.xsanime'
|
||||||
extClass = '.XsAnime'
|
extClass = '.XsAnime'
|
||||||
extVersionCode = 10
|
extVersionCode = 10
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
@ -15,7 +15,6 @@ import eu.kanade.tachiyomi.network.GET
|
|||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||||
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
|
||||||
@ -34,8 +33,6 @@ class XsAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
override val supportsLatest = false
|
override val supportsLatest = false
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient
|
|
||||||
|
|
||||||
private val preferences: SharedPreferences by lazy {
|
private val preferences: SharedPreferences by lazy {
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ ext {
|
|||||||
pkgNameSuffix = 'ar.xsmovie'
|
pkgNameSuffix = 'ar.xsmovie'
|
||||||
extClass = '.XsMovie'
|
extClass = '.XsMovie'
|
||||||
extVersionCode = 5
|
extVersionCode = 5
|
||||||
libVersion = '13'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
@ -13,7 +13,6 @@ import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
|
|||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
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
|
||||||
@ -32,8 +31,6 @@ class XsMovie : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
override val supportsLatest = false
|
override val supportsLatest = false
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient
|
|
||||||
|
|
||||||
private val preferences: SharedPreferences by lazy {
|
private val preferences: SharedPreferences by lazy {
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user