Remove unused metadata objects and misc code cleanup
This commit is contained in:
parent
6f36331818
commit
cadd389658
@ -17,7 +17,6 @@ import exh.metadata.metadata.EHentaiSearchMetadata.Companion.EH_GENRE_NAMESPACE
|
|||||||
import exh.metadata.metadata.EHentaiSearchMetadata.Companion.TAG_TYPE_LIGHT
|
import exh.metadata.metadata.EHentaiSearchMetadata.Companion.TAG_TYPE_LIGHT
|
||||||
import exh.metadata.metadata.EHentaiSearchMetadata.Companion.TAG_TYPE_NORMAL
|
import exh.metadata.metadata.EHentaiSearchMetadata.Companion.TAG_TYPE_NORMAL
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL
|
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL
|
||||||
import exh.metadata.models.ExGalleryMetadata
|
|
||||||
import exh.metadata.nullIfBlank
|
import exh.metadata.nullIfBlank
|
||||||
import exh.metadata.parseHumanReadableByteCount
|
import exh.metadata.parseHumanReadableByteCount
|
||||||
import exh.ui.login.LoginController
|
import exh.ui.login.LoginController
|
||||||
@ -253,9 +252,9 @@ class EHentai(override val id: Long,
|
|||||||
override fun parseIntoMetadata(metadata: EHentaiSearchMetadata, input: Response) {
|
override fun parseIntoMetadata(metadata: EHentaiSearchMetadata, input: Response) {
|
||||||
with(metadata) {
|
with(metadata) {
|
||||||
with(input.asJsoup()) {
|
with(input.asJsoup()) {
|
||||||
val url = input.request().url().encodedPath()!!
|
val url = input.request().url().encodedPath()
|
||||||
gId = ExGalleryMetadata.galleryId(url)
|
gId = EHentaiSearchMetadata.galleryId(url)
|
||||||
gToken = ExGalleryMetadata.galleryToken(url)
|
gToken = EHentaiSearchMetadata.galleryToken(url)
|
||||||
|
|
||||||
exh = this@EHentai.exh
|
exh = this@EHentai.exh
|
||||||
title = select("#gn").text().nullIfBlank()?.trim()
|
title = select("#gn").text().nullIfBlank()?.trim()
|
||||||
|
@ -18,7 +18,6 @@ import exh.NHENTAI_SOURCE_ID
|
|||||||
import exh.metadata.metadata.NHentaiSearchMetadata
|
import exh.metadata.metadata.NHentaiSearchMetadata
|
||||||
import exh.metadata.metadata.NHentaiSearchMetadata.Companion.TAG_TYPE_DEFAULT
|
import exh.metadata.metadata.NHentaiSearchMetadata.Companion.TAG_TYPE_DEFAULT
|
||||||
import exh.metadata.metadata.base.RaisedTag
|
import exh.metadata.metadata.base.RaisedTag
|
||||||
import exh.metadata.models.NHentaiMetadata
|
|
||||||
import exh.util.*
|
import exh.util.*
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
@ -226,7 +225,7 @@ class NHentai(context: Context) : HttpSource(), LewdSource<NHentaiSearchMetadata
|
|||||||
|
|
||||||
override fun fetchImageUrl(page: Page) = Observable.just(page.imageUrl!!)!!
|
override fun fetchImageUrl(page: Page) = Observable.just(page.imageUrl!!)!!
|
||||||
|
|
||||||
fun imageUrlFromType(mediaId: String, page: Int, t: String) = NHentaiMetadata.typeToExtension(t)?.let {
|
fun imageUrlFromType(mediaId: String, page: Int, t: String) = NHentaiSearchMetadata.typeToExtension(t)?.let {
|
||||||
"https://i.nhentai.net/galleries/$mediaId/$page.$it"
|
"https://i.nhentai.net/galleries/$mediaId/$page.$it"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@ import exh.metadata.metadata.PervEdenSearchMetadata
|
|||||||
import exh.metadata.metadata.PervEdenSearchMetadata.Companion.TAG_TYPE_DEFAULT
|
import exh.metadata.metadata.PervEdenSearchMetadata.Companion.TAG_TYPE_DEFAULT
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL
|
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL
|
||||||
import exh.metadata.metadata.base.RaisedTag
|
import exh.metadata.metadata.base.RaisedTag
|
||||||
import exh.metadata.models.PervEdenGalleryMetadata
|
|
||||||
import exh.util.UriFilter
|
import exh.util.UriFilter
|
||||||
import exh.util.UriGroup
|
import exh.util.UriGroup
|
||||||
import exh.util.urlImportFetchSearchManga
|
import exh.util.urlImportFetchSearchManga
|
||||||
@ -138,7 +137,7 @@ class PervEden(override val id: Long, val pvLang: PervEdenLang) : ParsedHttpSour
|
|||||||
with(metadata) {
|
with(metadata) {
|
||||||
url = Uri.parse(input.location()).path
|
url = Uri.parse(input.location()).path
|
||||||
|
|
||||||
pvId = PervEdenGalleryMetadata.pvIdFromUrl(url!!)
|
pvId = PervEdenSearchMetadata.pvIdFromUrl(url!!)
|
||||||
|
|
||||||
lang = this@PervEden.lang
|
lang = this@PervEden.lang
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
|||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.util.syncChaptersWithSource
|
import eu.kanade.tachiyomi.util.syncChaptersWithSource
|
||||||
import exh.metadata.models.ExGalleryMetadata
|
import exh.metadata.metadata.EHentaiSearchMetadata
|
||||||
import okhttp3.MediaType
|
import okhttp3.MediaType
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.RequestBody
|
import okhttp3.RequestBody
|
||||||
@ -137,7 +137,7 @@ class GalleryAdder {
|
|||||||
?: return GalleryAddEvent.Fail.Error(url, "Could not find EH source!")
|
?: return GalleryAddEvent.Fail.Error(url, "Could not find EH source!")
|
||||||
|
|
||||||
val cleanedUrl = when(source) {
|
val cleanedUrl = when(source) {
|
||||||
EH_SOURCE_ID, EXH_SOURCE_ID -> ExGalleryMetadata.normalizeUrl(getUrlWithoutDomain(realUrl))
|
EH_SOURCE_ID, EXH_SOURCE_ID -> EHentaiSearchMetadata.normalizeUrl(getUrlWithoutDomain(realUrl))
|
||||||
NHENTAI_SOURCE_ID -> getUrlWithoutDomain(realUrl)
|
NHENTAI_SOURCE_ID -> getUrlWithoutDomain(realUrl)
|
||||||
PERV_EDEN_EN_SOURCE_ID,
|
PERV_EDEN_EN_SOURCE_ID,
|
||||||
PERV_EDEN_IT_SOURCE_ID -> getUrlWithoutDomain(realUrl)
|
PERV_EDEN_IT_SOURCE_ID -> getUrlWithoutDomain(realUrl)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package exh.favorites
|
package exh.favorites
|
||||||
|
|
||||||
import exh.metadata.models.ExGalleryMetadata
|
import exh.metadata.metadata.EHentaiSearchMetadata
|
||||||
import io.realm.RealmObject
|
import io.realm.RealmObject
|
||||||
import io.realm.annotations.Index
|
import io.realm.annotations.Index
|
||||||
import io.realm.annotations.PrimaryKey
|
import io.realm.annotations.PrimaryKey
|
||||||
@ -19,5 +19,5 @@ open class FavoriteEntry : RealmObject() {
|
|||||||
|
|
||||||
@Index var category: Int = -1
|
@Index var category: Int = -1
|
||||||
|
|
||||||
fun getUrl() = ExGalleryMetadata.normalizeUrl(gid, token)
|
fun getUrl() = EHentaiSearchMetadata.idAndTokenToUrl(gid, token)
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
|||||||
import eu.kanade.tachiyomi.source.online.all.EHentai
|
import eu.kanade.tachiyomi.source.online.all.EHentai
|
||||||
import exh.EH_SOURCE_ID
|
import exh.EH_SOURCE_ID
|
||||||
import exh.EXH_SOURCE_ID
|
import exh.EXH_SOURCE_ID
|
||||||
import exh.metadata.models.ExGalleryMetadata
|
import exh.metadata.metadata.EHentaiSearchMetadata
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import io.realm.RealmConfiguration
|
import io.realm.RealmConfiguration
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
@ -111,8 +111,8 @@ class LocalFavoritesStorage {
|
|||||||
}.mapNotNull {
|
}.mapNotNull {
|
||||||
FavoriteEntry().apply {
|
FavoriteEntry().apply {
|
||||||
title = it.second.title
|
title = it.second.title
|
||||||
gid = ExGalleryMetadata.galleryId(it.second.url)
|
gid = EHentaiSearchMetadata.galleryId(it.second.url)
|
||||||
token = ExGalleryMetadata.galleryToken(it.second.url)
|
token = EHentaiSearchMetadata.galleryToken(it.second.url)
|
||||||
category = it.first
|
category = it.first
|
||||||
|
|
||||||
// TODO Throw error here
|
// TODO Throw error here
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
package exh.metadata
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
|
||||||
import eu.kanade.tachiyomi.source.online.LewdSource
|
|
||||||
import eu.kanade.tachiyomi.ui.library.LibraryItem
|
|
||||||
import exh.*
|
|
||||||
import exh.metadata.models.*
|
|
||||||
import io.realm.Realm
|
|
||||||
import io.realm.RealmQuery
|
|
||||||
import io.realm.RealmResults
|
|
||||||
import timber.log.Timber
|
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import kotlin.reflect.KClass
|
|
||||||
|
|
||||||
//fun Realm.loadAllMetadata(): Map<KClass<out SearchableGalleryMetadata>, RealmResults<out SearchableGalleryMetadata>> =
|
|
||||||
// Injekt.get<SourceManager>().getOnlineSources().filterIsInstance<LewdSource<*, *>>().map {
|
|
||||||
// it.queryAll()
|
|
||||||
// }.associate {
|
|
||||||
// it.clazz to it.query(this@loadAllMetadata).sort(SearchableGalleryMetadata::mangaId.name).findAll()
|
|
||||||
// }.toMap()
|
|
||||||
|
|
||||||
//fun Realm.queryMetadataFromManga(manga: Manga,
|
|
||||||
// meta: RealmQuery<SearchableGalleryMetadata>? = null):
|
|
||||||
// RealmQuery<out SearchableGalleryMetadata> =
|
|
||||||
// Injekt.get<SourceManager>().get(manga.source)?.let {
|
|
||||||
// (it as LewdSource<*, *>).queryFromUrl(manga.url) as GalleryQuery<SearchableGalleryMetadata>
|
|
||||||
// }?.query(this, meta) ?: throw IllegalArgumentException("Unknown source type!")
|
|
||||||
|
|
||||||
/*fun Realm.syncMangaIds(mangas: List<LibraryItem>) {
|
|
||||||
Timber.d("--> EH: Begin syncing ${mangas.size} manga IDs...")
|
|
||||||
executeTransaction {
|
|
||||||
mangas.forEach { manga ->
|
|
||||||
if(isLewdSource(manga.manga.source)) {
|
|
||||||
try {
|
|
||||||
manga.hasMetadata =
|
|
||||||
queryMetadataFromManga(manga.manga).findFirst()?.let { meta ->
|
|
||||||
meta.mangaId = manga.manga.id
|
|
||||||
true
|
|
||||||
} ?: false
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Timber.w(e, "Error syncing manga IDs! Ignoring...")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Timber.d("--> EH: Finish syncing ${mangas.size} manga IDs!")
|
|
||||||
}*/
|
|
||||||
|
|
||||||
//val Manga.metadataClass
|
|
||||||
// get() = (Injekt.get<SourceManager>().get(source) as? LewdSource<*, *>)?.queryAll()?.clazz
|
|
@ -1,7 +1,5 @@
|
|||||||
package exh.metadata
|
package exh.metadata
|
||||||
|
|
||||||
import exh.metadata.models.SearchableGalleryMetadata
|
|
||||||
import exh.plusAssign
|
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@ -10,18 +8,18 @@ import java.util.*
|
|||||||
*/
|
*/
|
||||||
fun humanReadableByteCount(bytes: Long, si: Boolean): String {
|
fun humanReadableByteCount(bytes: Long, si: Boolean): String {
|
||||||
val unit = if (si) 1000 else 1024
|
val unit = if (si) 1000 else 1024
|
||||||
if (bytes < unit) return bytes.toString() + " B"
|
if (bytes < unit) return "$bytes B"
|
||||||
val exp = (Math.log(bytes.toDouble()) / Math.log(unit.toDouble())).toInt()
|
val exp = (Math.log(bytes.toDouble()) / Math.log(unit.toDouble())).toInt()
|
||||||
val pre = (if (si) "kMGTPE" else "KMGTPE")[exp - 1] + if (si) "" else "i"
|
val pre = (if (si) "kMGTPE" else "KMGTPE")[exp - 1] + if (si) "" else "i"
|
||||||
return String.format("%.1f %sB", bytes / Math.pow(unit.toDouble(), exp.toDouble()), pre)
|
return String.format("%.1f %sB", bytes / Math.pow(unit.toDouble(), exp.toDouble()), pre)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val KB_FACTOR: Long = 1000
|
private const val KB_FACTOR: Long = 1000
|
||||||
private val KIB_FACTOR: Long = 1024
|
private const val KIB_FACTOR: Long = 1024
|
||||||
private val MB_FACTOR = 1000 * KB_FACTOR
|
private const val MB_FACTOR = 1000 * KB_FACTOR
|
||||||
private val MIB_FACTOR = 1024 * KIB_FACTOR
|
private const val MIB_FACTOR = 1024 * KIB_FACTOR
|
||||||
private val GB_FACTOR = 1000 * MB_FACTOR
|
private const val GB_FACTOR = 1000 * MB_FACTOR
|
||||||
private val GIB_FACTOR = 1024 * MIB_FACTOR
|
private const val GIB_FACTOR = 1024 * MIB_FACTOR
|
||||||
|
|
||||||
fun parseHumanReadableByteCount(arg0: String): Double? {
|
fun parseHumanReadableByteCount(arg0: String): Double? {
|
||||||
val spaceNdx = arg0.indexOf(" ")
|
val spaceNdx = arg0.indexOf(" ")
|
||||||
@ -66,24 +64,3 @@ val ONGOING_SUFFIX = arrayOf(
|
|||||||
)
|
)
|
||||||
|
|
||||||
val EX_DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US)
|
val EX_DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US)
|
||||||
|
|
||||||
fun buildTagsDescription(metadata: SearchableGalleryMetadata)
|
|
||||||
= StringBuilder("Tags:\n").apply {
|
|
||||||
//BiConsumer only available in Java 8, don't bother calling forEach directly on 'tags'
|
|
||||||
metadata.tags.groupBy {
|
|
||||||
it.namespace
|
|
||||||
}.entries.forEach { namespace, tags ->
|
|
||||||
if (tags.isNotEmpty()) {
|
|
||||||
val joinedTags = tags.joinToString(separator = " ", transform = { "<${it.name}>" })
|
|
||||||
this += "▪ $namespace: $joinedTags\n"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun joinTagsToGenreString(metadata: SearchableGalleryMetadata)
|
|
||||||
= metadata.tags.joinToString { "${it.namespace}: ${it.name}" }
|
|
||||||
|
|
||||||
fun joinEmulatedTagsToGenreString(metadata: SearchableGalleryMetadata)
|
|
||||||
= metadata.tags.filter { it.namespace == EMULATED_TAG_NAMESPACE }.joinToString { it.name.toString() }
|
|
||||||
|
|
||||||
val EMULATED_TAG_NAMESPACE = "tag"
|
|
@ -47,7 +47,7 @@ class HentaiCafeSearchMetadata : RaisedSearchMetadata() {
|
|||||||
|
|
||||||
const val TAG_TYPE_DEFAULT = 0
|
const val TAG_TYPE_DEFAULT = 0
|
||||||
|
|
||||||
val BASE_URL = "https://hentai.cafe"
|
const val BASE_URL = "https://hentai.cafe"
|
||||||
|
|
||||||
fun hcIdFromUrl(url: String)
|
fun hcIdFromUrl(url: String)
|
||||||
= url.split("/").last { it.isNotBlank() }
|
= url.split("/").last { it.isNotBlank() }
|
||||||
|
@ -89,9 +89,8 @@ class HitomiSearchMetadata: RaisedSearchMetadata() {
|
|||||||
|
|
||||||
const val TAG_TYPE_DEFAULT = 0
|
const val TAG_TYPE_DEFAULT = 0
|
||||||
|
|
||||||
val LTN_BASE_URL = "https://ltn.hitomi.la"
|
const val LTN_BASE_URL = "https://ltn.hitomi.la"
|
||||||
val BASE_URL = "https://hitomi.la"
|
const val BASE_URL = "https://hitomi.la"
|
||||||
val IMG_BASE_URL = "https://aa.hitomi.la/galleries"
|
|
||||||
|
|
||||||
fun hlIdFromUrl(url: String)
|
fun hlIdFromUrl(url: String)
|
||||||
= url.split('/').last().substringBeforeLast('.')
|
= url.split('/').last().substringBeforeLast('.')
|
||||||
|
@ -100,7 +100,7 @@ class NHentaiSearchMetadata : RaisedSearchMetadata() {
|
|||||||
|
|
||||||
const val TAG_TYPE_DEFAULT = 0
|
const val TAG_TYPE_DEFAULT = 0
|
||||||
|
|
||||||
val BASE_URL = "https://nhentai.net"
|
const val BASE_URL = "https://nhentai.net"
|
||||||
|
|
||||||
private const val NHENTAI_ARTIST_NAMESPACE = "artist"
|
private const val NHENTAI_ARTIST_NAMESPACE = "artist"
|
||||||
private const val NHENTAI_CATEGORIES_NAMESPACE = "category"
|
private const val NHENTAI_CATEGORIES_NAMESPACE = "category"
|
||||||
|
@ -42,9 +42,10 @@ class PervEdenSearchMetadata : RaisedSearchMetadata() {
|
|||||||
titleDesc += "Title: $it\n"
|
titleDesc += "Title: $it\n"
|
||||||
}
|
}
|
||||||
if(altTitles.isNotEmpty())
|
if(altTitles.isNotEmpty())
|
||||||
titleDesc += "Alternate Titles: \n" + altTitles.map {
|
titleDesc += "Alternate Titles: \n" + altTitles
|
||||||
|
.joinToString(separator = "\n", postfix = "\n") {
|
||||||
"▪ $it"
|
"▪ $it"
|
||||||
}.joinToString(separator = "\n", postfix = "\n")
|
}
|
||||||
|
|
||||||
val detailsDesc = StringBuilder()
|
val detailsDesc = StringBuilder()
|
||||||
artist?.let {
|
artist?.let {
|
||||||
@ -102,7 +103,7 @@ enum class PervEdenLang(val id: Long) {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun source(id: Long)
|
fun source(id: Long)
|
||||||
= PervEdenLang.values().find { it.id == id }
|
= values().find { it.id == id }
|
||||||
?: throw IllegalArgumentException("Unknown source ID: $id!")
|
?: throw IllegalArgumentException("Unknown source ID: $id!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,6 @@ package exh.metadata.metadata
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import exh.metadata.EX_DATE_FORMAT
|
import exh.metadata.EX_DATE_FORMAT
|
||||||
import exh.metadata.buildTagsDescription
|
|
||||||
import exh.metadata.joinEmulatedTagsToGenreString
|
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
import exh.plusAssign
|
import exh.plusAssign
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -1,190 +0,0 @@
|
|||||||
package exh.metadata.models
|
|
||||||
|
|
||||||
import android.net.Uri
|
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|
||||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
|
||||||
import exh.metadata.*
|
|
||||||
import exh.plusAssign
|
|
||||||
import io.realm.RealmList
|
|
||||||
import io.realm.RealmObject
|
|
||||||
import io.realm.annotations.Ignore
|
|
||||||
import io.realm.annotations.Index
|
|
||||||
import io.realm.annotations.PrimaryKey
|
|
||||||
import io.realm.annotations.RealmClass
|
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gallery metadata storage model
|
|
||||||
*/
|
|
||||||
|
|
||||||
@RealmClass
|
|
||||||
open class ExGalleryMetadata : RealmObject(), SearchableGalleryMetadata {
|
|
||||||
@PrimaryKey
|
|
||||||
override var uuid: String = UUID.randomUUID().toString()
|
|
||||||
|
|
||||||
var url: String? = null
|
|
||||||
set(value) {
|
|
||||||
//Ensure that URLs are always formatted in the same way to reduce duplicate galleries
|
|
||||||
field = value?.let { normalizeUrl(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Index
|
|
||||||
var gId: String? = null
|
|
||||||
@Index
|
|
||||||
var gToken: String? = null
|
|
||||||
|
|
||||||
@Index
|
|
||||||
var exh: Boolean? = null
|
|
||||||
|
|
||||||
var thumbnailUrl: String? = null
|
|
||||||
|
|
||||||
@Index
|
|
||||||
var title: String? = null
|
|
||||||
@Index
|
|
||||||
var altTitle: String? = null
|
|
||||||
|
|
||||||
@Index
|
|
||||||
override var uploader: String? = null
|
|
||||||
|
|
||||||
var genre: String? = null
|
|
||||||
|
|
||||||
var datePosted: Long? = null
|
|
||||||
var parent: String? = null
|
|
||||||
var visible: String? = null //Not a boolean
|
|
||||||
var language: String? = null
|
|
||||||
var translated: Boolean? = null
|
|
||||||
var size: Long? = null
|
|
||||||
var length: Int? = null
|
|
||||||
var favorites: Int? = null
|
|
||||||
var ratingCount: Int? = null
|
|
||||||
var averageRating: Double? = null
|
|
||||||
|
|
||||||
override var tags: RealmList<Tag> = RealmList()
|
|
||||||
|
|
||||||
override fun getTitles() = listOfNotNull(title, altTitle)
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
override val titleFields = TITLE_FIELDS
|
|
||||||
|
|
||||||
@Index
|
|
||||||
override var mangaId: Long? = null
|
|
||||||
|
|
||||||
class EmptyQuery : GalleryQuery<ExGalleryMetadata>(ExGalleryMetadata::class)
|
|
||||||
|
|
||||||
class UrlQuery(
|
|
||||||
val url: String,
|
|
||||||
val exh: Boolean
|
|
||||||
) : GalleryQuery<ExGalleryMetadata>(ExGalleryMetadata::class) {
|
|
||||||
override fun transform() = Query(
|
|
||||||
galleryId(url),
|
|
||||||
galleryToken(url),
|
|
||||||
exh
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
class Query(val gId: String,
|
|
||||||
val gToken: String,
|
|
||||||
val exh: Boolean
|
|
||||||
) : GalleryQuery<ExGalleryMetadata>(ExGalleryMetadata::class) {
|
|
||||||
override fun map() = mapOf(
|
|
||||||
::gId to Query::gId,
|
|
||||||
::gToken to Query::gToken,
|
|
||||||
::exh to Query::exh
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun copyTo(manga: SManga) {
|
|
||||||
url?.let { manga.url = normalizeUrl(it) }
|
|
||||||
thumbnailUrl?.let { manga.thumbnail_url = it }
|
|
||||||
|
|
||||||
//No title bug?
|
|
||||||
val titleObj = if(Injekt.get<PreferencesHelper>().useJapaneseTitle().getOrDefault())
|
|
||||||
altTitle ?: title
|
|
||||||
else
|
|
||||||
title
|
|
||||||
titleObj?.let { manga.title = it }
|
|
||||||
|
|
||||||
//Set artist (if we can find one)
|
|
||||||
tags.filter { it.namespace == EH_ARTIST_NAMESPACE }.let {
|
|
||||||
if(it.isNotEmpty()) manga.artist = it.joinToString(transform = { it.name!! })
|
|
||||||
}
|
|
||||||
|
|
||||||
//Copy tags -> genres
|
|
||||||
manga.genre = joinTagsToGenreString(this)
|
|
||||||
|
|
||||||
//Try to automatically identify if it is ongoing, we try not to be too lenient here to avoid making mistakes
|
|
||||||
//We default to completed
|
|
||||||
manga.status = SManga.COMPLETED
|
|
||||||
title?.let { t ->
|
|
||||||
ONGOING_SUFFIX.find {
|
|
||||||
t.endsWith(it, ignoreCase = true)
|
|
||||||
}?.let {
|
|
||||||
manga.status = SManga.ONGOING
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Build a nice looking description out of what we know
|
|
||||||
val titleDesc = StringBuilder()
|
|
||||||
title?.let { titleDesc += "Title: $it\n" }
|
|
||||||
altTitle?.let { titleDesc += "Alternate Title: $it\n" }
|
|
||||||
|
|
||||||
val detailsDesc = StringBuilder()
|
|
||||||
genre?.let { detailsDesc += "Genre: $it\n" }
|
|
||||||
uploader?.let { detailsDesc += "Uploader: $it\n" }
|
|
||||||
datePosted?.let { detailsDesc += "Posted: ${EX_DATE_FORMAT.format(Date(it))}\n" }
|
|
||||||
visible?.let { detailsDesc += "Visible: $it\n" }
|
|
||||||
language?.let {
|
|
||||||
detailsDesc += "Language: $it"
|
|
||||||
if(translated == true) detailsDesc += " TR"
|
|
||||||
detailsDesc += "\n"
|
|
||||||
}
|
|
||||||
size?.let { detailsDesc += "File Size: ${humanReadableByteCount(it, true)}\n" }
|
|
||||||
length?.let { detailsDesc += "Length: $it pages\n" }
|
|
||||||
favorites?.let { detailsDesc += "Favorited: $it times\n" }
|
|
||||||
averageRating?.let {
|
|
||||||
detailsDesc += "Rating: $it"
|
|
||||||
ratingCount?.let { detailsDesc += " ($it)" }
|
|
||||||
detailsDesc += "\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
val tagsDesc = buildTagsDescription(this)
|
|
||||||
|
|
||||||
manga.description = listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString())
|
|
||||||
.filter(String::isNotBlank)
|
|
||||||
.joinToString(separator = "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private fun splitGalleryUrl(url: String)
|
|
||||||
= url.let {
|
|
||||||
//Only parse URL if is full URL
|
|
||||||
val pathSegments = if(it.startsWith("http"))
|
|
||||||
Uri.parse(it).pathSegments
|
|
||||||
else
|
|
||||||
it.split('/')
|
|
||||||
pathSegments.filterNot(String::isNullOrBlank)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun galleryId(url: String) = splitGalleryUrl(url)[1]
|
|
||||||
|
|
||||||
fun galleryToken(url: String) =
|
|
||||||
splitGalleryUrl(url)[2]
|
|
||||||
|
|
||||||
fun normalizeUrl(id: String, token: String)
|
|
||||||
= "/g/$id/$token/?nw=always"
|
|
||||||
|
|
||||||
fun normalizeUrl(url: String)
|
|
||||||
= normalizeUrl(galleryId(url), galleryToken(url))
|
|
||||||
|
|
||||||
val TITLE_FIELDS = listOf(
|
|
||||||
ExGalleryMetadata::title.name,
|
|
||||||
ExGalleryMetadata::altTitle.name
|
|
||||||
)
|
|
||||||
|
|
||||||
private const val EH_ARTIST_NAMESPACE = "artist"
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
package exh.metadata.models
|
|
||||||
|
|
||||||
import io.realm.Case
|
|
||||||
import io.realm.Realm
|
|
||||||
import io.realm.RealmQuery
|
|
||||||
import java.util.*
|
|
||||||
import kotlin.reflect.KClass
|
|
||||||
import kotlin.reflect.KProperty
|
|
||||||
import kotlin.reflect.KProperty1
|
|
||||||
|
|
||||||
abstract class GalleryQuery<T : SearchableGalleryMetadata>(val clazz: KClass<T>) {
|
|
||||||
open fun map(): Map<*, *> = emptyMap<KProperty<T>, KProperty1<GalleryQuery<T>, *>>()
|
|
||||||
|
|
||||||
open fun transform(): GalleryQuery<T>? = this
|
|
||||||
|
|
||||||
open fun override(meta: RealmQuery<T>): RealmQuery<T> = meta
|
|
||||||
|
|
||||||
fun query(realm: Realm, meta: RealmQuery<T>? = null): RealmQuery<T>
|
|
||||||
= (meta ?: realm.where(clazz.java)).let {
|
|
||||||
val visited = mutableListOf<GalleryQuery<T>>()
|
|
||||||
|
|
||||||
var top: GalleryQuery<T>? = null
|
|
||||||
var newMeta = it
|
|
||||||
while(true) {
|
|
||||||
//DIFFERENT BEHAVIOR from: top?.transform() ?: this
|
|
||||||
top = if(top != null) top.transform() else this
|
|
||||||
|
|
||||||
if(top == null) break
|
|
||||||
|
|
||||||
if(top in visited) break
|
|
||||||
|
|
||||||
newMeta = top.applyMap(newMeta)
|
|
||||||
newMeta = top.override(newMeta)
|
|
||||||
|
|
||||||
visited += top
|
|
||||||
}
|
|
||||||
|
|
||||||
newMeta
|
|
||||||
}!!
|
|
||||||
|
|
||||||
fun applyMap(meta: RealmQuery<T>): RealmQuery<T> {
|
|
||||||
var newMeta = meta
|
|
||||||
|
|
||||||
map().forEach { (t, u) ->
|
|
||||||
t as KProperty<T>
|
|
||||||
u as KProperty1<GalleryQuery<T>, *>
|
|
||||||
|
|
||||||
val v = u.get(this)
|
|
||||||
val n = t.name
|
|
||||||
|
|
||||||
if(v != null) {
|
|
||||||
newMeta = when (v) {
|
|
||||||
is Date -> newMeta.equalTo(n, v)
|
|
||||||
is Boolean -> newMeta.equalTo(n, v)
|
|
||||||
is Byte -> newMeta.equalTo(n, v)
|
|
||||||
is ByteArray -> newMeta.equalTo(n, v)
|
|
||||||
is Double -> newMeta.equalTo(n, v)
|
|
||||||
is Float -> newMeta.equalTo(n, v)
|
|
||||||
is Int -> newMeta.equalTo(n, v)
|
|
||||||
is Long -> newMeta.equalTo(n, v)
|
|
||||||
is Short -> newMeta.equalTo(n, v)
|
|
||||||
is String -> newMeta.equalTo(n, v, Case.INSENSITIVE)
|
|
||||||
else -> throw IllegalArgumentException("Unknown type: ${v::class.java.name}!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return newMeta
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,95 +0,0 @@
|
|||||||
package exh.metadata.models
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
|
||||||
import exh.metadata.buildTagsDescription
|
|
||||||
import io.realm.RealmList
|
|
||||||
import io.realm.RealmObject
|
|
||||||
import io.realm.annotations.Ignore
|
|
||||||
import io.realm.annotations.Index
|
|
||||||
import io.realm.annotations.PrimaryKey
|
|
||||||
import io.realm.annotations.RealmClass
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
@RealmClass
|
|
||||||
open class HentaiCafeMetadata : RealmObject(), SearchableGalleryMetadata {
|
|
||||||
@PrimaryKey
|
|
||||||
override var uuid: String = UUID.randomUUID().toString()
|
|
||||||
|
|
||||||
@Index
|
|
||||||
var hcId: String? = null
|
|
||||||
var readerId: String? = null
|
|
||||||
|
|
||||||
var url get() = hcId?.let { "$BASE_URL/$it" }
|
|
||||||
set(a) {
|
|
||||||
a?.let {
|
|
||||||
hcId = hcIdFromUrl(a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var thumbnailUrl: String? = null
|
|
||||||
|
|
||||||
var title: String? = null
|
|
||||||
|
|
||||||
var artist: String? = null
|
|
||||||
|
|
||||||
override var uploader: String? = null //Always will be null as this is unknown
|
|
||||||
|
|
||||||
override var tags: RealmList<Tag> = RealmList()
|
|
||||||
|
|
||||||
override fun getTitles() = listOfNotNull(title)
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
override val titleFields = listOf(
|
|
||||||
::title.name
|
|
||||||
)
|
|
||||||
|
|
||||||
@Index
|
|
||||||
override var mangaId: Long? = null
|
|
||||||
|
|
||||||
override fun copyTo(manga: SManga) {
|
|
||||||
thumbnailUrl?.let { manga.thumbnail_url = it }
|
|
||||||
|
|
||||||
manga.title = title!!
|
|
||||||
manga.artist = artist
|
|
||||||
manga.author = artist
|
|
||||||
|
|
||||||
//Not available
|
|
||||||
manga.status = SManga.UNKNOWN
|
|
||||||
|
|
||||||
val detailsDesc = "Title: $title\n" +
|
|
||||||
"Artist: $artist\n"
|
|
||||||
|
|
||||||
val tagsDesc = buildTagsDescription(this)
|
|
||||||
|
|
||||||
manga.genre = tags.filter { it.namespace == "tag" }.joinToString {
|
|
||||||
it.name!!
|
|
||||||
}
|
|
||||||
|
|
||||||
manga.description = listOf(detailsDesc, tagsDesc.toString())
|
|
||||||
.filter(String::isNotBlank)
|
|
||||||
.joinToString(separator = "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
class EmptyQuery : GalleryQuery<HentaiCafeMetadata>(HentaiCafeMetadata::class)
|
|
||||||
|
|
||||||
class UrlQuery(
|
|
||||||
val url: String
|
|
||||||
) : GalleryQuery<HentaiCafeMetadata>(HentaiCafeMetadata::class) {
|
|
||||||
override fun transform() = Query(
|
|
||||||
hcIdFromUrl(url)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
class Query(val hcId: String): GalleryQuery<HentaiCafeMetadata>(HentaiCafeMetadata::class) {
|
|
||||||
override fun map() = mapOf(
|
|
||||||
HentaiCafeMetadata::hcId to Query::hcId
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val BASE_URL = "https://hentai.cafe"
|
|
||||||
|
|
||||||
fun hcIdFromUrl(url: String)
|
|
||||||
= url.split("/").last { it.isNotBlank() }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,152 +0,0 @@
|
|||||||
package exh.metadata.models
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
|
||||||
import exh.metadata.EX_DATE_FORMAT
|
|
||||||
import exh.metadata.buildTagsDescription
|
|
||||||
import exh.metadata.joinTagsToGenreString
|
|
||||||
import exh.plusAssign
|
|
||||||
import io.realm.RealmList
|
|
||||||
import io.realm.RealmObject
|
|
||||||
import io.realm.annotations.Ignore
|
|
||||||
import io.realm.annotations.Index
|
|
||||||
import io.realm.annotations.PrimaryKey
|
|
||||||
import io.realm.annotations.RealmClass
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
@RealmClass
|
|
||||||
open class HitomiGalleryMetadata : RealmObject(), SearchableGalleryMetadata {
|
|
||||||
@PrimaryKey
|
|
||||||
override var uuid: String = UUID.randomUUID().toString()
|
|
||||||
|
|
||||||
@Index
|
|
||||||
var hlId: String? = null
|
|
||||||
|
|
||||||
var thumbnailUrl: String? = null
|
|
||||||
|
|
||||||
var artist: String? = null
|
|
||||||
|
|
||||||
var group: String? = null
|
|
||||||
|
|
||||||
var type: String? = null
|
|
||||||
|
|
||||||
var language: String? = null
|
|
||||||
|
|
||||||
var languageSimple: String? = null
|
|
||||||
|
|
||||||
var series: RealmList<String> = RealmList()
|
|
||||||
|
|
||||||
var characters: RealmList<String> = RealmList()
|
|
||||||
|
|
||||||
var buyLink: String? = null
|
|
||||||
|
|
||||||
var uploadDate: Long? = null
|
|
||||||
|
|
||||||
override var tags: RealmList<Tag> = RealmList()
|
|
||||||
|
|
||||||
// Sites does not show uploader
|
|
||||||
override var uploader: String? = "admin"
|
|
||||||
|
|
||||||
var url get() = hlId?.let { urlFromHlId(it) }
|
|
||||||
set(a) {
|
|
||||||
a?.let {
|
|
||||||
hlId = hlIdFromUrl(a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Index
|
|
||||||
override var mangaId: Long? = null
|
|
||||||
|
|
||||||
@Index
|
|
||||||
var title: String? = null
|
|
||||||
|
|
||||||
override fun getTitles() = listOfNotNull(title)
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
override val titleFields = listOf(
|
|
||||||
::title.name
|
|
||||||
)
|
|
||||||
|
|
||||||
class EmptyQuery : GalleryQuery<HitomiGalleryMetadata>(HitomiGalleryMetadata::class)
|
|
||||||
|
|
||||||
class UrlQuery(
|
|
||||||
val url: String
|
|
||||||
) : GalleryQuery<HitomiGalleryMetadata>(HitomiGalleryMetadata::class) {
|
|
||||||
override fun transform() = Query(
|
|
||||||
hlIdFromUrl(url)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
class Query(val hlId: String): GalleryQuery<HitomiGalleryMetadata>(HitomiGalleryMetadata::class) {
|
|
||||||
override fun map() = mapOf(
|
|
||||||
HitomiGalleryMetadata::hlId to Query::hlId
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun copyTo(manga: SManga) {
|
|
||||||
thumbnailUrl?.let { manga.thumbnail_url = it }
|
|
||||||
|
|
||||||
val titleDesc = StringBuilder()
|
|
||||||
|
|
||||||
title?.let {
|
|
||||||
manga.title = it
|
|
||||||
titleDesc += "Title: $it\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
val detailsDesc = StringBuilder()
|
|
||||||
|
|
||||||
artist?.let {
|
|
||||||
manga.artist = it
|
|
||||||
manga.author = it
|
|
||||||
|
|
||||||
detailsDesc += "Artist: $it\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
group?.let {
|
|
||||||
detailsDesc += "Group: $it\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
type?.let {
|
|
||||||
detailsDesc += "Type: $it\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
(language ?: languageSimple ?: "none").let {
|
|
||||||
detailsDesc += "Language: $it\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
if(series.isNotEmpty())
|
|
||||||
detailsDesc += "Series: ${series.joinToString()}\n"
|
|
||||||
|
|
||||||
if(characters.isNotEmpty())
|
|
||||||
detailsDesc += "Characters: ${characters.joinToString()}\n"
|
|
||||||
|
|
||||||
uploadDate?.let {
|
|
||||||
detailsDesc += "Upload date: ${EX_DATE_FORMAT.format(Date(it))}\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
buyLink?.let {
|
|
||||||
detailsDesc += "Buy at: $it"
|
|
||||||
}
|
|
||||||
|
|
||||||
manga.status = SManga.UNKNOWN
|
|
||||||
|
|
||||||
//Copy tags -> genres
|
|
||||||
manga.genre = joinTagsToGenreString(this)
|
|
||||||
|
|
||||||
val tagsDesc = buildTagsDescription(this)
|
|
||||||
|
|
||||||
manga.description = listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString())
|
|
||||||
.filter(String::isNotBlank)
|
|
||||||
.joinToString(separator = "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val LTN_BASE_URL = "https://ltn.hitomi.la"
|
|
||||||
val BASE_URL = "https://hitomi.la"
|
|
||||||
|
|
||||||
fun hlIdFromUrl(url: String)
|
|
||||||
= url.split('/').last().substringBeforeLast('.')
|
|
||||||
|
|
||||||
fun urlFromHlId(id: String)
|
|
||||||
= "$BASE_URL/galleries/$id.html"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
package exh.metadata.models
|
|
||||||
|
|
||||||
import io.realm.RealmObject
|
|
||||||
import io.realm.annotations.Index
|
|
||||||
import io.realm.annotations.RealmClass
|
|
||||||
|
|
||||||
@RealmClass
|
|
||||||
open class HitomiPage: RealmObject() {
|
|
||||||
@Index lateinit var gallery: String
|
|
||||||
|
|
||||||
@Index var index: Int = -1
|
|
||||||
|
|
||||||
lateinit var url: String
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
package exh.metadata.models
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
|
||||||
import exh.metadata.models.HitomiGalleryMetadata.Companion.hlIdFromUrl
|
|
||||||
import exh.metadata.models.HitomiGalleryMetadata.Companion.urlFromHlId
|
|
||||||
import io.realm.RealmList
|
|
||||||
import io.realm.RealmObject
|
|
||||||
import io.realm.annotations.Ignore
|
|
||||||
import io.realm.annotations.Index
|
|
||||||
import io.realm.annotations.RealmClass
|
|
||||||
|
|
||||||
@RealmClass
|
|
||||||
open class HitomiSkeletonGalleryMetadata : RealmObject(), SearchableGalleryMetadata {
|
|
||||||
override var uuid: String
|
|
||||||
set(value) {}
|
|
||||||
get() = throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
var hlId: String? = null
|
|
||||||
|
|
||||||
var thumbnailUrl: String? = null
|
|
||||||
|
|
||||||
var artist: String? = null
|
|
||||||
|
|
||||||
var group: String? = null
|
|
||||||
|
|
||||||
var type: String? = null
|
|
||||||
|
|
||||||
var language: String? = null
|
|
||||||
|
|
||||||
var languageSimple: String? = null
|
|
||||||
|
|
||||||
var series: RealmList<String> = RealmList()
|
|
||||||
|
|
||||||
var characters: RealmList<String> = RealmList()
|
|
||||||
|
|
||||||
var buyLink: String? = null
|
|
||||||
|
|
||||||
var uploadDate: Long? = null
|
|
||||||
|
|
||||||
override var tags: RealmList<Tag> = RealmList()
|
|
||||||
|
|
||||||
// Sites does not show uploader
|
|
||||||
override var uploader: String? = "admin"
|
|
||||||
|
|
||||||
var url get() = hlId?.let { urlFromHlId(it) }
|
|
||||||
set(a) {
|
|
||||||
a?.let {
|
|
||||||
hlId = hlIdFromUrl(a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override var mangaId: Long? = null
|
|
||||||
|
|
||||||
@Index
|
|
||||||
var title: String? = null
|
|
||||||
|
|
||||||
override fun getTitles() = listOfNotNull(title)
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
override val titleFields = listOf(
|
|
||||||
::title.name
|
|
||||||
)
|
|
||||||
override fun copyTo(manga: SManga) {
|
|
||||||
throw UnsupportedOperationException("This operation cannot be performed on skeleton galleries!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,185 +0,0 @@
|
|||||||
package exh.metadata.models
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|
||||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
|
||||||
import exh.metadata.*
|
|
||||||
import exh.plusAssign
|
|
||||||
import io.realm.RealmList
|
|
||||||
import io.realm.RealmObject
|
|
||||||
import io.realm.annotations.Ignore
|
|
||||||
import io.realm.annotations.Index
|
|
||||||
import io.realm.annotations.PrimaryKey
|
|
||||||
import io.realm.annotations.RealmClass
|
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
/**
|
|
||||||
* NHentai metadata
|
|
||||||
*/
|
|
||||||
|
|
||||||
@RealmClass
|
|
||||||
open class NHentaiMetadata : RealmObject(), SearchableGalleryMetadata {
|
|
||||||
@PrimaryKey
|
|
||||||
override var uuid: String = UUID.randomUUID().toString()
|
|
||||||
|
|
||||||
var nhId: Long? = null
|
|
||||||
|
|
||||||
var url get() = nhId?.let { "$BASE_URL/g/$it" }
|
|
||||||
set(a) {
|
|
||||||
a?.let {
|
|
||||||
nhId = nhUrlToId(a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Index
|
|
||||||
override var uploader: String? = null
|
|
||||||
|
|
||||||
var uploadDate: Long? = null
|
|
||||||
|
|
||||||
var favoritesCount: Long? = null
|
|
||||||
|
|
||||||
var mediaId: String? = null
|
|
||||||
|
|
||||||
@Index
|
|
||||||
var japaneseTitle: String? = null
|
|
||||||
@Index
|
|
||||||
var englishTitle: String? = null
|
|
||||||
@Index
|
|
||||||
var shortTitle: String? = null
|
|
||||||
|
|
||||||
var coverImageType: String? = null
|
|
||||||
var pageImageTypes: RealmList<PageImageType> = RealmList()
|
|
||||||
var thumbnailImageType: String? = null
|
|
||||||
|
|
||||||
var scanlator: String? = null
|
|
||||||
|
|
||||||
override var tags: RealmList<Tag> = RealmList()
|
|
||||||
|
|
||||||
override fun getTitles() = listOf(japaneseTitle, englishTitle, shortTitle).filterNotNull()
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
override val titleFields = TITLE_FIELDS
|
|
||||||
|
|
||||||
@Index
|
|
||||||
override var mangaId: Long? = null
|
|
||||||
|
|
||||||
class EmptyQuery : GalleryQuery<NHentaiMetadata>(NHentaiMetadata::class)
|
|
||||||
|
|
||||||
class UrlQuery(
|
|
||||||
val url: String
|
|
||||||
) : GalleryQuery<NHentaiMetadata>(NHentaiMetadata::class) {
|
|
||||||
override fun transform() = Query(
|
|
||||||
nhUrlToId(url)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
class Query(
|
|
||||||
val nhId: Long
|
|
||||||
) : GalleryQuery<NHentaiMetadata>(NHentaiMetadata::class) {
|
|
||||||
override fun map() = mapOf(
|
|
||||||
::nhId to Query::nhId
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun copyTo(manga: SManga) {
|
|
||||||
url?.let { manga.url = it }
|
|
||||||
|
|
||||||
if(mediaId != null)
|
|
||||||
NHentaiMetadata.typeToExtension(thumbnailImageType)?.let {
|
|
||||||
manga.thumbnail_url = "https://t.nhentai.net/galleries/$mediaId/${
|
|
||||||
if(Injekt.get<PreferencesHelper>().eh_nh_useHighQualityThumbs().getOrDefault())
|
|
||||||
"cover"
|
|
||||||
else
|
|
||||||
"thumb"
|
|
||||||
}.$it"
|
|
||||||
}
|
|
||||||
|
|
||||||
manga.title = englishTitle ?: japaneseTitle ?: shortTitle!!
|
|
||||||
|
|
||||||
//Set artist (if we can find one)
|
|
||||||
tags.filter { it.namespace == NHENTAI_ARTIST_NAMESPACE }.let {
|
|
||||||
if(it.isNotEmpty()) manga.artist = it.joinToString(transform = { it.name!! })
|
|
||||||
}
|
|
||||||
|
|
||||||
var category: String? = null
|
|
||||||
tags.filter { it.namespace == NHENTAI_CATEGORIES_NAMESPACE }.let {
|
|
||||||
if(it.isNotEmpty()) category = it.joinToString(transform = { it.name!! })
|
|
||||||
}
|
|
||||||
|
|
||||||
//Copy tags -> genres
|
|
||||||
manga.genre = joinEmulatedTagsToGenreString(this)
|
|
||||||
|
|
||||||
//Try to automatically identify if it is ongoing, we try not to be too lenient here to avoid making mistakes
|
|
||||||
//We default to completed
|
|
||||||
manga.status = SManga.COMPLETED
|
|
||||||
englishTitle?.let { t ->
|
|
||||||
ONGOING_SUFFIX.find {
|
|
||||||
t.endsWith(it, ignoreCase = true)
|
|
||||||
}?.let {
|
|
||||||
manga.status = SManga.ONGOING
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val titleDesc = StringBuilder()
|
|
||||||
englishTitle?.let { titleDesc += "English Title: $it\n" }
|
|
||||||
japaneseTitle?.let { titleDesc += "Japanese Title: $it\n" }
|
|
||||||
shortTitle?.let { titleDesc += "Short Title: $it\n" }
|
|
||||||
|
|
||||||
val detailsDesc = StringBuilder()
|
|
||||||
category?.let { detailsDesc += "Category: $it\n" }
|
|
||||||
uploadDate?.let { detailsDesc += "Upload Date: ${EX_DATE_FORMAT.format(Date(it * 1000))}\n" }
|
|
||||||
pageImageTypes.size.let { detailsDesc += "Length: $it pages\n" }
|
|
||||||
favoritesCount?.let { detailsDesc += "Favorited: $it times\n" }
|
|
||||||
scanlator?.nullIfBlank()?.let { detailsDesc += "Scanlator: $it\n" }
|
|
||||||
|
|
||||||
val tagsDesc = buildTagsDescription(this)
|
|
||||||
|
|
||||||
manga.description = listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString())
|
|
||||||
.filter(String::isNotBlank)
|
|
||||||
.joinToString(separator = "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val BASE_URL = "https://nhentai.net"
|
|
||||||
|
|
||||||
private const val NHENTAI_ARTIST_NAMESPACE = "artist"
|
|
||||||
private const val NHENTAI_CATEGORIES_NAMESPACE = "category"
|
|
||||||
|
|
||||||
fun typeToExtension(t: String?) =
|
|
||||||
when(t) {
|
|
||||||
"p" -> "png"
|
|
||||||
"j" -> "jpg"
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
fun nhUrlToId(url: String)
|
|
||||||
= url.split("/").last { it.isNotBlank() }.toLong()
|
|
||||||
|
|
||||||
val TITLE_FIELDS = listOf(
|
|
||||||
NHentaiMetadata::japaneseTitle.name,
|
|
||||||
NHentaiMetadata::englishTitle.name,
|
|
||||||
NHentaiMetadata::shortTitle.name
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@RealmClass
|
|
||||||
open class PageImageType(var type: String? = null): RealmObject() {
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (javaClass != other?.javaClass) return false
|
|
||||||
|
|
||||||
other as PageImageType
|
|
||||||
|
|
||||||
if (type != other.type) return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun hashCode() = type?.hashCode() ?: 0
|
|
||||||
|
|
||||||
override fun toString() = "PageImageType(type=$type)"
|
|
||||||
}
|
|
@ -1,144 +0,0 @@
|
|||||||
package exh.metadata.models
|
|
||||||
|
|
||||||
import android.net.Uri
|
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
|
||||||
import exh.PERV_EDEN_EN_SOURCE_ID
|
|
||||||
import exh.PERV_EDEN_IT_SOURCE_ID
|
|
||||||
import exh.metadata.buildTagsDescription
|
|
||||||
import exh.metadata.joinEmulatedTagsToGenreString
|
|
||||||
import exh.plusAssign
|
|
||||||
import io.realm.RealmList
|
|
||||||
import io.realm.RealmObject
|
|
||||||
import io.realm.RealmQuery
|
|
||||||
import io.realm.annotations.Ignore
|
|
||||||
import io.realm.annotations.Index
|
|
||||||
import io.realm.annotations.PrimaryKey
|
|
||||||
import io.realm.annotations.RealmClass
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
@RealmClass
|
|
||||||
open class PervEdenGalleryMetadata : RealmObject(), SearchableGalleryMetadata {
|
|
||||||
@PrimaryKey
|
|
||||||
override var uuid: String = UUID.randomUUID().toString()
|
|
||||||
|
|
||||||
@Index
|
|
||||||
var pvId: String? = null
|
|
||||||
|
|
||||||
var url: String? = null
|
|
||||||
var thumbnailUrl: String? = null
|
|
||||||
|
|
||||||
@Index
|
|
||||||
var title: String? = null
|
|
||||||
var altTitles: RealmList<PervEdenTitle> = RealmList()
|
|
||||||
|
|
||||||
@Index
|
|
||||||
override var uploader: String? = null
|
|
||||||
|
|
||||||
@Index
|
|
||||||
var artist: String? = null
|
|
||||||
|
|
||||||
var type: String? = null
|
|
||||||
|
|
||||||
var rating: Float? = null
|
|
||||||
|
|
||||||
var status: String? = null
|
|
||||||
|
|
||||||
var lang: String? = null
|
|
||||||
|
|
||||||
override var tags: RealmList<Tag> = RealmList()
|
|
||||||
|
|
||||||
override fun getTitles() = listOf(title).plus(altTitles.map {
|
|
||||||
it.title
|
|
||||||
}).filterNotNull()
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
override val titleFields = TITLE_FIELDS
|
|
||||||
|
|
||||||
@Index
|
|
||||||
override var mangaId: Long? = null
|
|
||||||
|
|
||||||
override fun copyTo(manga: SManga) {
|
|
||||||
url?.let { manga.url = it }
|
|
||||||
thumbnailUrl?.let { manga.thumbnail_url = it }
|
|
||||||
|
|
||||||
val titleDesc = StringBuilder()
|
|
||||||
title?.let {
|
|
||||||
manga.title = it
|
|
||||||
titleDesc += "Title: $it\n"
|
|
||||||
}
|
|
||||||
if(altTitles.isNotEmpty())
|
|
||||||
titleDesc += "Alternate Titles: \n" + altTitles.map {
|
|
||||||
"▪ ${it.title}"
|
|
||||||
}.joinToString(separator = "\n", postfix = "\n")
|
|
||||||
|
|
||||||
val detailsDesc = StringBuilder()
|
|
||||||
artist?.let {
|
|
||||||
manga.artist = it
|
|
||||||
detailsDesc += "Artist: $it\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
type?.let {
|
|
||||||
detailsDesc += "Type: $it\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
status?.let {
|
|
||||||
manga.status = when(it) {
|
|
||||||
"Ongoing" -> SManga.ONGOING
|
|
||||||
"Completed", "Suspended" -> SManga.COMPLETED
|
|
||||||
else -> SManga.UNKNOWN
|
|
||||||
}
|
|
||||||
detailsDesc += "Status: $it\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
rating?.let {
|
|
||||||
detailsDesc += "Rating: %.2\n".format(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
//Copy tags -> genres
|
|
||||||
manga.genre = joinEmulatedTagsToGenreString(this)
|
|
||||||
|
|
||||||
val tagsDesc = buildTagsDescription(this)
|
|
||||||
|
|
||||||
manga.description = listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString())
|
|
||||||
.filter(String::isNotBlank)
|
|
||||||
.joinToString(separator = "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private fun splitGalleryUrl(url: String)
|
|
||||||
= url.let {
|
|
||||||
Uri.parse(it).pathSegments.filterNot(String::isNullOrBlank)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun pvIdFromUrl(url: String) = splitGalleryUrl(url).last()
|
|
||||||
|
|
||||||
val TITLE_FIELDS = listOf(
|
|
||||||
//TODO Somehow include altTitles
|
|
||||||
PervEdenGalleryMetadata::title.name
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@RealmClass
|
|
||||||
open class PervEdenTitle(var metadata: PervEdenGalleryMetadata? = null,
|
|
||||||
@Index var title: String? = null): RealmObject() {
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (javaClass != other?.javaClass) return false
|
|
||||||
|
|
||||||
other as PervEdenTitle
|
|
||||||
|
|
||||||
if (metadata != other.metadata) return false
|
|
||||||
if (title != other.title) return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
var result = metadata?.hashCode() ?: 0
|
|
||||||
result = 31 * result + (title?.hashCode() ?: 0)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString() = "PervEdenTitle(metadata=$metadata, title=$title)"
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
package exh.metadata.models
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
|
||||||
import io.realm.RealmList
|
|
||||||
import io.realm.RealmModel
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A gallery that can be searched using the EH search engine
|
|
||||||
*/
|
|
||||||
interface SearchableGalleryMetadata: RealmModel {
|
|
||||||
var uuid: String
|
|
||||||
|
|
||||||
var uploader: String?
|
|
||||||
|
|
||||||
//Being specific about which classes are used in generics to make deserialization easier
|
|
||||||
var tags: RealmList<Tag>
|
|
||||||
|
|
||||||
fun getTitles(): List<String>
|
|
||||||
|
|
||||||
val titleFields: List<String>
|
|
||||||
|
|
||||||
var mangaId: Long?
|
|
||||||
|
|
||||||
fun copyTo(manga: SManga)
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
package exh.metadata.models
|
|
||||||
|
|
||||||
import io.realm.RealmObject
|
|
||||||
import io.realm.annotations.Index
|
|
||||||
import io.realm.annotations.RealmClass
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple tag model
|
|
||||||
*/
|
|
||||||
|
|
||||||
@RealmClass
|
|
||||||
open class Tag(@Index var namespace: String? = null,
|
|
||||||
@Index var name: String? = null,
|
|
||||||
var light: Boolean? = null): RealmObject() {
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (javaClass != other?.javaClass) return false
|
|
||||||
|
|
||||||
other as Tag
|
|
||||||
|
|
||||||
if (namespace != other.namespace) return false
|
|
||||||
if (name != other.name) return false
|
|
||||||
if (light != other.light) return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
var result = namespace?.hashCode() ?: 0
|
|
||||||
result = 31 * result + (name?.hashCode() ?: 0)
|
|
||||||
result = 31 * result + (light?.hashCode() ?: 0)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString() = "Tag(namespace=$namespace, name=$name, light=$light)"
|
|
||||||
}
|
|
@ -1,133 +0,0 @@
|
|||||||
package exh.metadata.models
|
|
||||||
|
|
||||||
import android.net.Uri
|
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
|
||||||
import exh.metadata.EX_DATE_FORMAT
|
|
||||||
import exh.metadata.buildTagsDescription
|
|
||||||
import exh.metadata.joinEmulatedTagsToGenreString
|
|
||||||
import exh.plusAssign
|
|
||||||
import io.realm.RealmList
|
|
||||||
import io.realm.RealmObject
|
|
||||||
import io.realm.annotations.Ignore
|
|
||||||
import io.realm.annotations.Index
|
|
||||||
import io.realm.annotations.PrimaryKey
|
|
||||||
import io.realm.annotations.RealmClass
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
@RealmClass
|
|
||||||
open class TsuminoMetadata : RealmObject(), SearchableGalleryMetadata {
|
|
||||||
@PrimaryKey
|
|
||||||
override var uuid: String = UUID.randomUUID().toString()
|
|
||||||
|
|
||||||
@Index
|
|
||||||
var tmId: String? = null
|
|
||||||
|
|
||||||
var url get() = tmId?.let { mangaUrlFromId(it) }
|
|
||||||
set(a) {
|
|
||||||
a?.let {
|
|
||||||
tmId = tmIdFromUrl(a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var title: String? = null
|
|
||||||
|
|
||||||
var artist: String? = null
|
|
||||||
|
|
||||||
override var uploader: String? = null
|
|
||||||
|
|
||||||
var uploadDate: Long? = null
|
|
||||||
|
|
||||||
var length: Int? = null
|
|
||||||
|
|
||||||
var ratingString: String? = null
|
|
||||||
|
|
||||||
var category: String? = null
|
|
||||||
|
|
||||||
var collection: String? = null
|
|
||||||
|
|
||||||
var group: String? = null
|
|
||||||
|
|
||||||
var parody: RealmList<String> = RealmList()
|
|
||||||
|
|
||||||
var character: RealmList<String> = RealmList()
|
|
||||||
|
|
||||||
override var tags: RealmList<Tag> = RealmList()
|
|
||||||
|
|
||||||
override fun getTitles() = listOfNotNull(title)
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
override val titleFields = listOf(
|
|
||||||
::title.name
|
|
||||||
)
|
|
||||||
|
|
||||||
@Index
|
|
||||||
override var mangaId: Long? = null
|
|
||||||
|
|
||||||
class EmptyQuery : GalleryQuery<TsuminoMetadata>(TsuminoMetadata::class)
|
|
||||||
|
|
||||||
class UrlQuery(
|
|
||||||
val url: String
|
|
||||||
) : GalleryQuery<TsuminoMetadata>(TsuminoMetadata::class) {
|
|
||||||
override fun transform() = Query(
|
|
||||||
tmIdFromUrl(url)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
class Query(
|
|
||||||
val tmId: String
|
|
||||||
) : GalleryQuery<TsuminoMetadata>(TsuminoMetadata::class) {
|
|
||||||
override fun map() = mapOf(
|
|
||||||
::tmId to Query::tmId
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun copyTo(manga: SManga) {
|
|
||||||
title?.let { manga.title = it }
|
|
||||||
manga.thumbnail_url = thumbUrlFromId(tmId.toString())
|
|
||||||
|
|
||||||
artist?.let { manga.artist = it }
|
|
||||||
|
|
||||||
manga.status = SManga.UNKNOWN
|
|
||||||
|
|
||||||
val titleDesc = "Title: $title\n"
|
|
||||||
|
|
||||||
val detailsDesc = StringBuilder()
|
|
||||||
uploader?.let { detailsDesc += "Uploader: $it\n" }
|
|
||||||
uploadDate?.let { detailsDesc += "Uploaded: ${EX_DATE_FORMAT.format(Date(it))}\n" }
|
|
||||||
length?.let { detailsDesc += "Length: $it pages\n" }
|
|
||||||
ratingString?.let { detailsDesc += "Rating: $it\n" }
|
|
||||||
category?.let {
|
|
||||||
detailsDesc += "Category: $it\n"
|
|
||||||
}
|
|
||||||
collection?.let { detailsDesc += "Collection: $it\n" }
|
|
||||||
group?.let { detailsDesc += "Group: $it\n" }
|
|
||||||
val parodiesString = parody.joinToString()
|
|
||||||
if(parodiesString.isNotEmpty()) {
|
|
||||||
detailsDesc += "Parody: $parodiesString\n"
|
|
||||||
}
|
|
||||||
val charactersString = character.joinToString()
|
|
||||||
if(charactersString.isNotEmpty()) {
|
|
||||||
detailsDesc += "Character: $charactersString\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
//Copy tags -> genres
|
|
||||||
manga.genre = joinEmulatedTagsToGenreString(this)
|
|
||||||
|
|
||||||
val tagsDesc = buildTagsDescription(this)
|
|
||||||
|
|
||||||
manga.description = listOf(titleDesc, detailsDesc.toString(), tagsDesc.toString())
|
|
||||||
.filter(String::isNotBlank)
|
|
||||||
.joinToString(separator = "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val BASE_URL = "http://www.tsumino.com"
|
|
||||||
|
|
||||||
fun tmIdFromUrl(url: String)
|
|
||||||
= Uri.parse(url).pathSegments[2]
|
|
||||||
|
|
||||||
fun mangaUrlFromId(id: String) = "$BASE_URL/Book/Info/$id"
|
|
||||||
|
|
||||||
fun thumbUrlFromId(id: String) = "$BASE_URL/Image/Thumb/$id"
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user