Link resolver implementation
parent
797a91a037
commit
1d040e8291
@ -0,0 +1,80 @@
|
|||||||
|
package org.koitharu.kotatsu.parsers.util
|
||||||
|
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.runInterruptible
|
||||||
|
import okhttp3.HttpUrl
|
||||||
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||||
|
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||||
|
import org.koitharu.kotatsu.parsers.MangaParser
|
||||||
|
import org.koitharu.kotatsu.parsers.model.*
|
||||||
|
|
||||||
|
public class LinkResolver internal constructor(
|
||||||
|
private val context: MangaLoaderContext,
|
||||||
|
public val link: HttpUrl,
|
||||||
|
) {
|
||||||
|
|
||||||
|
private val source = SuspendLazy(::resolveSource)
|
||||||
|
|
||||||
|
public suspend fun getSource(): MangaParserSource? = source.get()
|
||||||
|
|
||||||
|
public suspend fun getManga(): Manga? {
|
||||||
|
val parser = context.newParserInstance(source.get() ?: return null)
|
||||||
|
return parser.resolveLink(link) ?: parser.resolveLinkLongPath()
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun resolveSource(): MangaParserSource? = runInterruptible(Dispatchers.Default) {
|
||||||
|
val domains = setOfNotNull(link.host, link.topPrivateDomain())
|
||||||
|
for (s in MangaParserSource.entries) {
|
||||||
|
val parser = context.newParserInstance(s)
|
||||||
|
for (d in parser.configKeyDomain.presetValues) {
|
||||||
|
if (d in domains) {
|
||||||
|
return@runInterruptible s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun MangaParser.resolveLinkLongPath(): Manga? {
|
||||||
|
val stubTitle = link.pathSegments.lastOrNull().orEmpty()
|
||||||
|
val seed = Manga(
|
||||||
|
id = 0L,
|
||||||
|
title = stubTitle,
|
||||||
|
altTitle = null,
|
||||||
|
url = link.toString().toRelativeUrl(link.host),
|
||||||
|
publicUrl = link.toString(),
|
||||||
|
rating = RATING_UNKNOWN,
|
||||||
|
isNsfw = false,
|
||||||
|
coverUrl = "",
|
||||||
|
tags = emptySet(),
|
||||||
|
state = null,
|
||||||
|
author = null,
|
||||||
|
largeCoverUrl = null,
|
||||||
|
description = null,
|
||||||
|
chapters = null,
|
||||||
|
source = source,
|
||||||
|
).let { manga ->
|
||||||
|
getDetails(manga)
|
||||||
|
}
|
||||||
|
val query = when {
|
||||||
|
seed.title != stubTitle && seed.title.isNotEmpty() -> seed.title
|
||||||
|
!seed.altTitle.isNullOrEmpty() -> seed.altTitle
|
||||||
|
!seed.author.isNullOrEmpty() -> seed.author
|
||||||
|
else -> return seed // unfortunately we do not know a real manga title so unable to find it
|
||||||
|
}
|
||||||
|
return runCatchingCancellable {
|
||||||
|
val order = if (SortOrder.RELEVANCE in availableSortOrders) SortOrder.RELEVANCE else defaultSortOrder
|
||||||
|
val list = getList(0, order, MangaListFilter(query = query))
|
||||||
|
list.single { manga -> isSameUrl(manga.publicUrl) }
|
||||||
|
}.getOrDefault(seed)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isSameUrl(publicUrl: String): Boolean {
|
||||||
|
if (publicUrl == link.toString()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
val httpUrl = publicUrl.toHttpUrlOrNull() ?: return false
|
||||||
|
return link.host == httpUrl.host
|
||||||
|
&& link.encodedPath == httpUrl.encodedPath
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package org.koitharu.kotatsu.parsers.util
|
||||||
|
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.jupiter.api.Assertions
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.koitharu.kotatsu.parsers.MangaLoaderContextMock
|
||||||
|
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||||
|
import kotlin.time.Duration.Companion.minutes
|
||||||
|
|
||||||
|
internal class LinkResolverTest {
|
||||||
|
|
||||||
|
private val context = MangaLoaderContextMock
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun supportedSource() = runTest(timeout = 2.minutes) {
|
||||||
|
val resolver = context.newLinkResolver("REDACTED" /* do not publish links to manga on GitHub */)
|
||||||
|
Assertions.assertEquals(MangaParserSource.MANGADEX, resolver.getSource())
|
||||||
|
val manga = resolver.getManga()
|
||||||
|
Assertions.assertEquals(resolver.link.toString(), manga?.publicUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun unsupportedSource2() = runTest(timeout = 2.minutes) {
|
||||||
|
val resolver = context.newLinkResolver("REDACTED" /* do not publish links to manga on GitHub */)
|
||||||
|
Assertions.assertEquals(MangaParserSource.BATOTO, resolver.getSource())
|
||||||
|
val manga = resolver.getManga()
|
||||||
|
Assertions.assertEquals(resolver.link.toString(), manga?.publicUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue