GoogleDriveIndex: Fix/add stuff (#1450)
* Fix/add stuff * Throw exception for people misusing the extension
This commit is contained in:
@ -6,7 +6,7 @@ ext {
|
|||||||
extName = 'GoogleDriveIndex'
|
extName = 'GoogleDriveIndex'
|
||||||
pkgNameSuffix = 'all.googledriveindex'
|
pkgNameSuffix = 'all.googledriveindex'
|
||||||
extClass = '.GoogleDriveIndex'
|
extClass = '.GoogleDriveIndex'
|
||||||
extVersionCode = 1
|
extVersionCode = 2
|
||||||
libVersion = '13'
|
libVersion = '13'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,10 +17,13 @@ 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.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
import okhttp3.Credentials
|
||||||
|
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.OkHttpClient
|
||||||
@ -31,6 +34,7 @@ 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
|
||||||
|
import java.net.URLEncoder
|
||||||
|
|
||||||
class GoogleDriveIndex : ConfigurableAnimeSource, AnimeHttpSource() {
|
class GoogleDriveIndex : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||||
|
|
||||||
@ -52,7 +56,30 @@ class GoogleDriveIndex : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient
|
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||||
|
.addInterceptor { chain ->
|
||||||
|
var request = chain.request()
|
||||||
|
|
||||||
|
if (request.url.username.isNotBlank() && request.url.password.isNotBlank()) {
|
||||||
|
|
||||||
|
val credential = Credentials.basic(request.url.username, request.url.password)
|
||||||
|
request = request.newBuilder()
|
||||||
|
.header("Authorization", credential)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val newUrl = request.url.newBuilder()
|
||||||
|
.username("")
|
||||||
|
.password("")
|
||||||
|
.build()
|
||||||
|
|
||||||
|
request = request.newBuilder()
|
||||||
|
.url(newUrl)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
chain.proceed(request)
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
|
||||||
// ============================== Popular ===============================
|
// ============================== Popular ===============================
|
||||||
|
|
||||||
@ -61,13 +88,17 @@ class GoogleDriveIndex : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
throw Exception("Enter drive path(s) in extension settings.")
|
throw Exception("Enter drive path(s) in extension settings.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (baseUrl.toHttpUrl().host == "drive.google.com") {
|
||||||
|
throw Exception("This extension is only for Google Drive Index sites, not drive.google.com folders.")
|
||||||
|
}
|
||||||
|
|
||||||
if (page == 1) pageToken = ""
|
if (page == 1) pageToken = ""
|
||||||
val popHeaders = headers.newBuilder()
|
val popHeaders = headers.newBuilder()
|
||||||
.add("Accept", "*/*")
|
.add("Accept", "*/*")
|
||||||
.add("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
|
.add("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
|
||||||
.add("Host", baseUrl.toHttpUrl().host)
|
.add("Host", baseUrl.toHttpUrl().host)
|
||||||
.add("Origin", "https://${baseUrl.toHttpUrl().host}")
|
.add("Origin", "https://${baseUrl.toHttpUrl().host}")
|
||||||
.add("Referer", baseUrl)
|
.add("Referer", URLEncoder.encode(baseUrl, "UTF-8"))
|
||||||
.add("X-Requested-With", "XMLHttpRequest")
|
.add("X-Requested-With", "XMLHttpRequest")
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
@ -88,6 +119,28 @@ class GoogleDriveIndex : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
|
|
||||||
// =============================== Search ===============================
|
// =============================== Search ===============================
|
||||||
|
|
||||||
|
override fun searchAnimeParse(response: Response): AnimesPage = throw Exception("Not used")
|
||||||
|
|
||||||
|
override fun fetchSearchAnime(
|
||||||
|
page: Int,
|
||||||
|
query: String,
|
||||||
|
filters: AnimeFilterList,
|
||||||
|
): Observable<AnimesPage> {
|
||||||
|
val req = searchAnimeRequest(page, query, filters)
|
||||||
|
return Observable.defer {
|
||||||
|
try {
|
||||||
|
client.newCall(req).asObservableSuccess()
|
||||||
|
} 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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
||||||
if (baseUrl.isEmpty()) {
|
if (baseUrl.isEmpty()) {
|
||||||
throw Exception("Enter drive path(s) in extension settings.")
|
throw Exception("Enter drive path(s) in extension settings.")
|
||||||
@ -97,6 +150,10 @@ class GoogleDriveIndex : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
val serverFilter = filterList.find { it is ServerFilter } as ServerFilter
|
val serverFilter = filterList.find { it is ServerFilter } as ServerFilter
|
||||||
val serverUrl = serverFilter.toUriPart()
|
val serverUrl = serverFilter.toUriPart()
|
||||||
|
|
||||||
|
if (serverUrl.toHttpUrl().host == "drive.google.com") {
|
||||||
|
throw Exception("This extension is only for Google Drive Index sites, not drive.google.com folders.")
|
||||||
|
}
|
||||||
|
|
||||||
if (page == 1) pageToken = ""
|
if (page == 1) pageToken = ""
|
||||||
val searchHeaders = headers.newBuilder()
|
val searchHeaders = headers.newBuilder()
|
||||||
.add("Accept", "*/*")
|
.add("Accept", "*/*")
|
||||||
@ -110,11 +167,12 @@ class GoogleDriveIndex : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
POST(
|
POST(
|
||||||
serverUrl,
|
serverUrl,
|
||||||
body = popBody,
|
body = popBody,
|
||||||
headers = searchHeaders.add("Referer", serverUrl).build(),
|
headers = searchHeaders.add("Referer", URLEncoder.encode(serverUrl, "UTF-8")).build(),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
val cleanQuery = query.replace(" ", "+")
|
val cleanQuery = query.replace(" ", "+")
|
||||||
val searchUrl = "https://${serverUrl.toHttpUrl().host}/${serverUrl.toHttpUrl().pathSegments[0]}search"
|
|
||||||
|
val searchUrl = "https://${serverUrl.toHttpUrl().hostAndCred()}/${serverUrl.toHttpUrl().pathSegments[0]}search"
|
||||||
|
|
||||||
val popBody = "q=$cleanQuery&page_token=$pageToken&page_index=${page - 1}".toRequestBody("application/x-www-form-urlencoded".toMediaType())
|
val popBody = "q=$cleanQuery&page_token=$pageToken&page_index=${page - 1}".toRequestBody("application/x-www-form-urlencoded".toMediaType())
|
||||||
|
|
||||||
@ -126,8 +184,8 @@ class GoogleDriveIndex : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun searchAnimeParse(response: Response): AnimesPage {
|
private fun searchAnimeParse(response: Response, url: String): AnimesPage {
|
||||||
return parsePage(response, response.request.url.toString())
|
return parsePage(response, url)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================== FILTERS ===============================
|
// ============================== FILTERS ===============================
|
||||||
@ -177,7 +235,7 @@ class GoogleDriveIndex : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
.add("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
|
.add("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
|
||||||
.add("Host", idParsed.url.toHttpUrl().host)
|
.add("Host", idParsed.url.toHttpUrl().host)
|
||||||
.add("Origin", "https://${idParsed.url.toHttpUrl().host}")
|
.add("Origin", "https://${idParsed.url.toHttpUrl().host}")
|
||||||
.add("Referer", idParsed.referer)
|
.add("Referer", URLEncoder.encode(idParsed.referer, "UTF-8"))
|
||||||
.add("X-Requested-With", "XMLHttpRequest")
|
.add("X-Requested-With", "XMLHttpRequest")
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
@ -219,7 +277,7 @@ class GoogleDriveIndex : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
.add("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
|
.add("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
|
||||||
.add("Host", url.toHttpUrl().host)
|
.add("Host", url.toHttpUrl().host)
|
||||||
.add("Origin", "https://${url.toHttpUrl().host}")
|
.add("Origin", "https://${url.toHttpUrl().host}")
|
||||||
.add("Referer", url)
|
.add("Referer", URLEncoder.encode(url, "UTF-8"))
|
||||||
.add("X-Requested-With", "XMLHttpRequest")
|
.add("X-Requested-With", "XMLHttpRequest")
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
@ -259,11 +317,6 @@ class GoogleDriveIndex : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
val seasonText = if (season.isBlank()) {
|
|
||||||
""
|
|
||||||
} else {
|
|
||||||
"[${season.trimInfo()}] "
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get other info
|
// Get other info
|
||||||
val extraInfo = if (paths.size > basePathCounter) {
|
val extraInfo = if (paths.size > basePathCounter) {
|
||||||
@ -273,7 +326,7 @@ class GoogleDriveIndex : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
val size = item.size?.toLongOrNull()?.let { formatFileSize(it) }
|
val size = item.size?.toLongOrNull()?.let { formatFileSize(it) }
|
||||||
|
|
||||||
episode.name = "$seasonText${item.name.trimInfo()}${if (size == null) "" else " - $size"}"
|
episode.name = "${item.name.trimInfo()}${if (size == null) "" else " - $size"}"
|
||||||
episode.url = epUrl
|
episode.url = epUrl
|
||||||
episode.scanlator = seasonInfo + extraInfo
|
episode.scanlator = seasonInfo + extraInfo
|
||||||
episode.episode_number = counter.toFloat()
|
episode.episode_number = counter.toFloat()
|
||||||
@ -319,6 +372,14 @@ class GoogleDriveIndex : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
|
|
||||||
// ============================= Utilities ==============================
|
// ============================= Utilities ==============================
|
||||||
|
|
||||||
|
private fun HttpUrl.hostAndCred(): String {
|
||||||
|
return if (this.password.isNotBlank() && this.username.isNotBlank()) {
|
||||||
|
"${this.username}:${this.password}@${this.host}"
|
||||||
|
} else {
|
||||||
|
this.host
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun joinUrl(path1: String, path2: String): String {
|
private fun joinUrl(path1: String, path2: String): String {
|
||||||
return path1.removeSuffix("/") + "/" + path2.removePrefix("/")
|
return path1.removeSuffix("/") + "/" + path2.removePrefix("/")
|
||||||
}
|
}
|
||||||
@ -446,7 +507,9 @@ class GoogleDriveIndex : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
""".trimMargin()
|
""".trimMargin()
|
||||||
this.setDefaultValue("")
|
this.setDefaultValue("")
|
||||||
dialogTitle = "Path list"
|
dialogTitle = "Path list"
|
||||||
dialogMessage = "Separate paths with a comma"
|
dialogMessage = """Separate paths with a comma. For password protected sites,
|
||||||
|
|format as: "https://username:password@example.worker.dev/0:/"
|
||||||
|
""".trimMargin()
|
||||||
|
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
try {
|
try {
|
||||||
|
Reference in New Issue
Block a user