|
|
|
@ -1,9 +1,11 @@
|
|
|
|
package org.koitharu.kotatsu.parsers.site.grouple
|
|
|
|
package org.koitharu.kotatsu.parsers.site.grouple
|
|
|
|
|
|
|
|
|
|
|
|
import kotlinx.coroutines.async
|
|
|
|
import kotlinx.coroutines.flow.channelFlow
|
|
|
|
import kotlinx.coroutines.coroutineScope
|
|
|
|
import kotlinx.coroutines.flow.first
|
|
|
|
|
|
|
|
import kotlinx.coroutines.launch
|
|
|
|
import okhttp3.Headers
|
|
|
|
import okhttp3.Headers
|
|
|
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
|
|
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
|
|
|
|
|
|
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
|
|
|
import okhttp3.Interceptor
|
|
|
|
import okhttp3.Interceptor
|
|
|
|
import okhttp3.Response
|
|
|
|
import okhttp3.Response
|
|
|
|
import okhttp3.internal.headersContentLength
|
|
|
|
import okhttp3.internal.headersContentLength
|
|
|
|
@ -236,30 +238,42 @@ internal abstract class GroupleParser(
|
|
|
|
|
|
|
|
|
|
|
|
override suspend fun getPageUrl(page: MangaPage): String {
|
|
|
|
override suspend fun getPageUrl(page: MangaPage): String {
|
|
|
|
val parts = page.url.split('|')
|
|
|
|
val parts = page.url.split('|')
|
|
|
|
|
|
|
|
if (parts.size < 2) {
|
|
|
|
|
|
|
|
throw ParseException("No servers found for page", page.url)
|
|
|
|
|
|
|
|
}
|
|
|
|
val path = parts.last()
|
|
|
|
val path = parts.last()
|
|
|
|
val servers = parts.dropLast(1).toSet()
|
|
|
|
// fast path
|
|
|
|
val cachedServer = cachedPagesServer
|
|
|
|
cachedPagesServer?.let { host ->
|
|
|
|
if (!cachedServer.isNullOrEmpty() && cachedServer in servers && tryHead(concatUrl(cachedServer, path))) {
|
|
|
|
val url = concatUrl("https://$host/", path)
|
|
|
|
return concatUrl(cachedServer, path)
|
|
|
|
if (tryHead(url)) {
|
|
|
|
|
|
|
|
return url
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
cachedPagesServer = null
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (servers.isEmpty()) {
|
|
|
|
// slow path
|
|
|
|
throw ParseException("No servers found for page", page.url)
|
|
|
|
val candidates = HashSet<String>((parts.size - 1) * 2)
|
|
|
|
|
|
|
|
for (i in 0 until parts.size - 1) {
|
|
|
|
|
|
|
|
val server = parts[i].trim().ifEmpty { "https://$domain/" }
|
|
|
|
|
|
|
|
candidates.add(concatUrl(server, path))
|
|
|
|
|
|
|
|
candidates.add(concatUrl(server, path.substringBeforeLast('?')))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
val server = try {
|
|
|
|
return try {
|
|
|
|
coroutineScope {
|
|
|
|
channelFlow {
|
|
|
|
servers.map { server ->
|
|
|
|
for (url in candidates) {
|
|
|
|
async {
|
|
|
|
launch {
|
|
|
|
val host = server.trim().ifEmpty { "https://$domain/" }
|
|
|
|
if (tryHead(url)) {
|
|
|
|
if (tryHead(concatUrl(host, path))) host else null
|
|
|
|
send(url)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}.awaitFirst { it != null }
|
|
|
|
}
|
|
|
|
}.also {
|
|
|
|
}.first().also {
|
|
|
|
cachedPagesServer = it
|
|
|
|
cachedPagesServer = it.toHttpUrlOrNull()?.host
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (e: NoSuchElementException) {
|
|
|
|
} catch (e: NoSuchElementException) {
|
|
|
|
servers.random()
|
|
|
|
assert(false) { e.toString() }
|
|
|
|
|
|
|
|
candidates.random()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return concatUrl(checkNotNull(server).ifEmpty { "https://$domain/" }, path)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
override suspend fun getTags(): Set<MangaTag> {
|
|
|
|
override suspend fun getTags(): Set<MangaTag> {
|
|
|
|
|