mirror of
https://github.com/mihonapp/mihon.git
synced 2025-06-28 03:57:50 +02:00
Migrate to new URL import system
This commit is contained in:
@ -2,23 +2,13 @@ package exh
|
||||
|
||||
import android.net.Uri
|
||||
import com.elvishew.xlog.XLog
|
||||
import com.github.salomonbrys.kotson.*
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||
import eu.kanade.tachiyomi.source.online.all.EHentai
|
||||
import eu.kanade.tachiyomi.util.syncChaptersWithSource
|
||||
import exh.metadata.metadata.EHentaiSearchMetadata
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.Request
|
||||
import okhttp3.RequestBody
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.net.URI
|
||||
import java.net.URISyntaxException
|
||||
|
||||
class GalleryAdder {
|
||||
|
||||
@ -26,133 +16,55 @@ class GalleryAdder {
|
||||
|
||||
private val sourceManager: SourceManager by injectLazy()
|
||||
|
||||
private val networkHelper: NetworkHelper by injectLazy()
|
||||
|
||||
companion object {
|
||||
const val EH_API_BASE = "https://api.e-hentai.org/api.php"
|
||||
val JSON = MediaType.parse("application/json; charset=utf-8")!!
|
||||
}
|
||||
|
||||
fun getGalleryUrlFromPage(url: String): String {
|
||||
val uri = Uri.parse(url)
|
||||
val lastSplit = uri.pathSegments.last().split("-")
|
||||
val pageNum = lastSplit.last()
|
||||
val gallery = lastSplit.first()
|
||||
val pageToken = uri.pathSegments.elementAt(1)
|
||||
|
||||
val json = JsonObject()
|
||||
json["method"] = "gtoken"
|
||||
json["pagelist"] = JsonArray().apply {
|
||||
add(JsonArray().apply {
|
||||
add(gallery.toInt())
|
||||
add(pageToken)
|
||||
add(pageNum.toInt())
|
||||
})
|
||||
}
|
||||
|
||||
val outJson = JsonParser().parse(networkHelper.client.newCall(Request.Builder()
|
||||
.url(EH_API_BASE)
|
||||
.post(RequestBody.create(JSON, json.toString()))
|
||||
.build()).execute().body()!!.string()).obj
|
||||
|
||||
val obj = outJson["tokenlist"].array.first()
|
||||
return "${uri.scheme}://${uri.host}/g/${obj["gid"].int}/${obj["token"].string}/"
|
||||
}
|
||||
|
||||
fun addGallery(url: String,
|
||||
fav: Boolean = false,
|
||||
forceSource: Long? = null,
|
||||
forceSource: UrlImportableSource? = null,
|
||||
throttleFunc: () -> Unit = {}): GalleryAddEvent {
|
||||
XLog.d("Importing gallery (url: %s, fav: %s, forceSource: %s)...", url, fav, forceSource)
|
||||
try {
|
||||
val urlObj = Uri.parse(url)
|
||||
val lowercasePs = urlObj.pathSegments.map(String::toLowerCase)
|
||||
val lcFirstPathSegment = lowercasePs[0]
|
||||
val source = when (urlObj.host.toLowerCase()) {
|
||||
"g.e-hentai.org", "e-hentai.org" -> EH_SOURCE_ID
|
||||
"exhentai.org" -> EXH_SOURCE_ID
|
||||
"nhentai.net" -> NHENTAI_SOURCE_ID
|
||||
"www.perveden.com" -> {
|
||||
when(lowercasePs[1]) {
|
||||
"en-manga" -> PERV_EDEN_EN_SOURCE_ID
|
||||
"it-manga" -> PERV_EDEN_IT_SOURCE_ID
|
||||
else -> return GalleryAddEvent.Fail.UnknownType(url)
|
||||
}
|
||||
val uri = Uri.parse(url)
|
||||
|
||||
// Find matching source
|
||||
val source = if(forceSource != null) {
|
||||
try {
|
||||
if (forceSource.matchesUri(uri)) forceSource
|
||||
else return GalleryAddEvent.Fail.UnknownType(url)
|
||||
} catch(e: Exception) {
|
||||
XLog.e("Source URI match check error!", e)
|
||||
return GalleryAddEvent.Fail.UnknownType(url)
|
||||
}
|
||||
"hentai.cafe" -> HENTAI_CAFE_SOURCE_ID
|
||||
"www.tsumino.com" -> TSUMINO_SOURCE_ID
|
||||
"hitomi.la" -> HITOMI_SOURCE_ID
|
||||
else -> return GalleryAddEvent.Fail.UnknownType(url)
|
||||
} else {
|
||||
sourceManager.getVisibleCatalogueSources()
|
||||
.filterIsInstance<UrlImportableSource>()
|
||||
.find {
|
||||
try {
|
||||
it.matchesUri(uri)
|
||||
} catch(e: Exception) {
|
||||
XLog.e("Source URI match check error!", e)
|
||||
false
|
||||
}
|
||||
} ?: return GalleryAddEvent.Fail.UnknownType(url)
|
||||
}
|
||||
|
||||
if(forceSource != null && source != forceSource) {
|
||||
return GalleryAddEvent.Fail.UnknownType(url)
|
||||
}
|
||||
// Map URL to manga URL
|
||||
val realUrl = try {
|
||||
source.mapUrlToMangaUrl(uri)
|
||||
} catch(e: Exception) {
|
||||
XLog.e("Source URI map-to-manga error!", e)
|
||||
null
|
||||
} ?: return GalleryAddEvent.Fail.UnknownType(url)
|
||||
|
||||
val sourceObj = sourceManager.get(source)
|
||||
?: return GalleryAddEvent.Fail.Error(url, "Source not installed!")
|
||||
|
||||
val realUrl = when(source) {
|
||||
EH_SOURCE_ID, EXH_SOURCE_ID -> when (lcFirstPathSegment) {
|
||||
"g" -> {
|
||||
//Is already gallery page, do nothing
|
||||
url
|
||||
}
|
||||
"s" -> {
|
||||
//Is page, fetch gallery token and use that
|
||||
getGalleryUrlFromPage(url)
|
||||
}
|
||||
else -> return GalleryAddEvent.Fail.UnknownType(url)
|
||||
}
|
||||
NHENTAI_SOURCE_ID -> {
|
||||
if(lcFirstPathSegment != "g")
|
||||
return GalleryAddEvent.Fail.UnknownType(url)
|
||||
|
||||
"https://nhentai.net/g/${urlObj.pathSegments[1]}/"
|
||||
}
|
||||
PERV_EDEN_EN_SOURCE_ID,
|
||||
PERV_EDEN_IT_SOURCE_ID -> {
|
||||
val uri = Uri.parse("http://www.perveden.com/").buildUpon()
|
||||
urlObj.pathSegments.take(3).forEach {
|
||||
uri.appendPath(it)
|
||||
}
|
||||
uri.toString()
|
||||
}
|
||||
HENTAI_CAFE_SOURCE_ID -> {
|
||||
if(lcFirstPathSegment == "manga")
|
||||
"https://hentai.cafe/${urlObj.pathSegments[2]}"
|
||||
|
||||
"https://hentai.cafe/$lcFirstPathSegment"
|
||||
}
|
||||
TSUMINO_SOURCE_ID -> {
|
||||
if(lcFirstPathSegment != "read" && lcFirstPathSegment != "book")
|
||||
return GalleryAddEvent.Fail.UnknownType(url)
|
||||
|
||||
"https://tsumino.com/Book/Info/${urlObj.pathSegments[2]}"
|
||||
}
|
||||
HITOMI_SOURCE_ID -> {
|
||||
if(lcFirstPathSegment != "galleries" && lcFirstPathSegment != "reader")
|
||||
return GalleryAddEvent.Fail.UnknownType(url)
|
||||
|
||||
"https://hitomi.la/galleries/${urlObj.pathSegments[1].substringBefore('.')}.html"
|
||||
}
|
||||
else -> return GalleryAddEvent.Fail.UnknownType(url)
|
||||
}
|
||||
|
||||
val cleanedUrl = when(source) {
|
||||
EH_SOURCE_ID, EXH_SOURCE_ID -> EHentaiSearchMetadata.normalizeUrl(getUrlWithoutDomain(realUrl))
|
||||
NHENTAI_SOURCE_ID -> getUrlWithoutDomain(realUrl)
|
||||
PERV_EDEN_EN_SOURCE_ID,
|
||||
PERV_EDEN_IT_SOURCE_ID -> getUrlWithoutDomain(realUrl)
|
||||
HENTAI_CAFE_SOURCE_ID -> getUrlWithoutDomain(realUrl)
|
||||
TSUMINO_SOURCE_ID -> getUrlWithoutDomain(realUrl)
|
||||
HITOMI_SOURCE_ID -> getUrlWithoutDomain(realUrl)
|
||||
else -> return GalleryAddEvent.Fail.UnknownType(url)
|
||||
}
|
||||
// Clean URL
|
||||
val cleanedUrl = try {
|
||||
source.cleanMangaUrl(realUrl)
|
||||
} catch(e: Exception) {
|
||||
XLog.e("Source URI clean error!", e)
|
||||
null
|
||||
} ?: return GalleryAddEvent.Fail.UnknownType(url)
|
||||
|
||||
//Use manga in DB if possible, otherwise, make a new manga
|
||||
val manga = db.getManga(cleanedUrl, source).executeAsBlocking()
|
||||
?: Manga.create(source).apply {
|
||||
val manga = db.getManga(cleanedUrl, source.id).executeAsBlocking()
|
||||
?: Manga.create(source.id).apply {
|
||||
this.url = cleanedUrl
|
||||
title = realUrl
|
||||
}
|
||||
@ -166,7 +78,7 @@ class GalleryAdder {
|
||||
}
|
||||
|
||||
// Fetch and copy details
|
||||
val newManga = sourceObj.fetchMangaDetails(manga).toBlocking().first()
|
||||
val newManga = source.fetchMangaDetails(manga).toBlocking().first()
|
||||
manga.copyFrom(newManga)
|
||||
manga.initialized = true
|
||||
|
||||
@ -176,13 +88,13 @@ class GalleryAdder {
|
||||
|
||||
//Fetch and copy chapters
|
||||
try {
|
||||
val chapterListObs = if(sourceObj is EHentai) {
|
||||
sourceObj.fetchChapterList(manga, throttleFunc)
|
||||
val chapterListObs = if(source is EHentai) {
|
||||
source.fetchChapterList(manga, throttleFunc)
|
||||
} else {
|
||||
sourceObj.fetchChapterList(manga)
|
||||
source.fetchChapterList(manga)
|
||||
}
|
||||
chapterListObs.map {
|
||||
syncChaptersWithSource(db, it, manga, sourceObj)
|
||||
syncChaptersWithSource(db, it, manga, source)
|
||||
}.toBlocking().first()
|
||||
} catch (e: Exception) {
|
||||
XLog.w("Failed to update chapters for gallery: ${manga.title}!", e)
|
||||
@ -201,20 +113,6 @@ class GalleryAdder {
|
||||
((e.message ?: "Unknown error!") + " (Gallery: $url)").trim())
|
||||
}
|
||||
}
|
||||
|
||||
private fun getUrlWithoutDomain(orig: String): String {
|
||||
return try {
|
||||
val uri = URI(orig)
|
||||
var out = uri.path
|
||||
if (uri.query != null)
|
||||
out += "?" + uri.query
|
||||
if (uri.fragment != null)
|
||||
out += "#" + uri.fragment
|
||||
out
|
||||
} catch (e: URISyntaxException) {
|
||||
orig
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class GalleryAddEvent {
|
||||
@ -224,9 +122,8 @@ sealed class GalleryAddEvent {
|
||||
|
||||
class Success(override val galleryUrl: String,
|
||||
val manga: Manga): GalleryAddEvent() {
|
||||
override val galleryTitle = manga.title
|
||||
override val logMessage = "Added gallery: $galleryTitle"
|
||||
override val galleryTitle: String
|
||||
get() = manga.title
|
||||
}
|
||||
|
||||
sealed class Fail: GalleryAddEvent() {
|
||||
|
Reference in New Issue
Block a user