Various changes

This commit is contained in:
NerdNumber9
2017-11-29 20:35:10 -05:00
committed by NerdNumber9
parent 908128b55d
commit 5cb219d83e
35 changed files with 1140 additions and 649 deletions

View File

@@ -1,121 +1,32 @@
package exh.metadata
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.source.model.SManga
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.ExGalleryMetadata
import exh.metadata.models.NHentaiMetadata
import exh.metadata.models.PervEdenGalleryMetadata
import exh.metadata.models.SearchableGalleryMetadata
import exh.metadata.models.*
import io.realm.Realm
import io.realm.RealmQuery
import io.realm.RealmResults
import rx.Observable
import timber.log.Timber
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import kotlin.reflect.KClass
fun Realm.ehMetaQueryFromUrl(url: String,
exh: Boolean,
meta: RealmQuery<ExGalleryMetadata>? = null) =
ehMetadataQuery(
ExGalleryMetadata.galleryId(url),
ExGalleryMetadata.galleryToken(url),
exh,
meta
)
fun Realm.ehMetadataQuery(gId: String,
gToken: String,
exh: Boolean,
meta: RealmQuery<ExGalleryMetadata>? = null)
= (meta ?: where(ExGalleryMetadata::class.java))
.equalTo(ExGalleryMetadata::gId.name, gId)
.equalTo(ExGalleryMetadata::gToken.name, gToken)
.equalTo(ExGalleryMetadata::exh.name, exh)
fun Realm.loadEh(gId: String, gToken: String, exh: Boolean): ExGalleryMetadata?
= ehMetadataQuery(gId, gToken, exh)
.findFirst()
fun Realm.loadEhAsync(gId: String, gToken: String, exh: Boolean): Observable<ExGalleryMetadata?>
= ehMetadataQuery(gId, gToken, exh)
.findFirstAsync()
.asObservable()
private fun pervEdenSourceToLang(source: Long)
= when (source) {
PERV_EDEN_EN_SOURCE_ID -> "en"
PERV_EDEN_IT_SOURCE_ID -> "it"
else -> throw IllegalArgumentException()
}
fun Realm.pervEdenMetaQueryFromUrl(url: String,
source: Long,
meta: RealmQuery<PervEdenGalleryMetadata>? = null) =
pervEdenMetadataQuery(
PervEdenGalleryMetadata.pvIdFromUrl(url),
source,
meta
)
fun Realm.pervEdenMetadataQuery(pvId: String,
source: Long,
meta: RealmQuery<PervEdenGalleryMetadata>? = null)
= (meta ?: where(PervEdenGalleryMetadata::class.java))
.equalTo(PervEdenGalleryMetadata::lang.name, pervEdenSourceToLang(source))
.equalTo(PervEdenGalleryMetadata::pvId.name, pvId)
fun Realm.loadPervEden(pvId: String, source: Long): PervEdenGalleryMetadata?
= pervEdenMetadataQuery(pvId, source)
.findFirst()
fun Realm.loadPervEdenAsync(pvId: String, source: Long): Observable<PervEdenGalleryMetadata?>
= pervEdenMetadataQuery(pvId, source)
.findFirstAsync()
.asObservable()
fun Realm.nhentaiMetaQueryFromUrl(url: String,
meta: RealmQuery<NHentaiMetadata>? = null) =
nhentaiMetadataQuery(
NHentaiMetadata.nhIdFromUrl(url),
meta
)
fun Realm.nhentaiMetadataQuery(nhId: Long,
meta: RealmQuery<NHentaiMetadata>? = null)
= (meta ?: where(NHentaiMetadata::class.java))
.equalTo(NHentaiMetadata::nhId.name, nhId)
fun Realm.loadNhentai(nhId: Long): NHentaiMetadata?
= nhentaiMetadataQuery(nhId)
.findFirst()
fun Realm.loadNhentaiAsync(nhId: Long): Observable<NHentaiMetadata?>
= nhentaiMetadataQuery(nhId)
.findFirstAsync()
.asObservable()
fun Realm.loadAllMetadata(): Map<KClass<out SearchableGalleryMetadata>, RealmResults<out SearchableGalleryMetadata>> =
listOf<Pair<KClass<out SearchableGalleryMetadata>, RealmQuery<out SearchableGalleryMetadata>>>(
Pair(ExGalleryMetadata::class, where(ExGalleryMetadata::class.java)),
Pair(NHentaiMetadata::class, where(NHentaiMetadata::class.java)),
Pair(PervEdenGalleryMetadata::class, where(PervEdenGalleryMetadata::class.java))
).map {
Pair(it.first, it.second.findAllSorted(SearchableGalleryMetadata::mangaId.name))
Injekt.get<SourceManager>().getOnlineSources().filterIsInstance<LewdSource<*, *>>().map {
it.queryAll()
}.associate {
it.clazz to it.query(this@loadAllMetadata).findAllSorted(SearchableGalleryMetadata::mangaId.name)
}.toMap()
fun Realm.queryMetadataFromManga(manga: Manga,
meta: RealmQuery<out SearchableGalleryMetadata>? = null): RealmQuery<out SearchableGalleryMetadata> =
when(manga.source) {
EH_SOURCE_ID -> ehMetaQueryFromUrl(manga.url, false, meta as? RealmQuery<ExGalleryMetadata>)
EXH_SOURCE_ID -> ehMetaQueryFromUrl(manga.url, true, meta as? RealmQuery<ExGalleryMetadata>)
PERV_EDEN_EN_SOURCE_ID,
PERV_EDEN_IT_SOURCE_ID ->
pervEdenMetaQueryFromUrl(manga.url, manga.source, meta as? RealmQuery<PervEdenGalleryMetadata>)
NHENTAI_SOURCE_ID -> nhentaiMetaQueryFromUrl(manga.url, meta as? RealmQuery<NHentaiMetadata>)
else -> throw IllegalArgumentException("Unknown source type!")
}
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...")
@@ -138,11 +49,4 @@ fun Realm.syncMangaIds(mangas: List<LibraryItem>) {
}
val Manga.metadataClass
get() = when (source) {
EH_SOURCE_ID,
EXH_SOURCE_ID -> ExGalleryMetadata::class
PERV_EDEN_IT_SOURCE_ID,
PERV_EDEN_EN_SOURCE_ID -> PervEdenGalleryMetadata::class
NHENTAI_SOURCE_ID -> NHentaiMetadata::class
else -> null
}
get() = (Injekt.get<SourceManager>().get(source) as? LewdSource<*, *>)?.queryAll()?.clazz

View File

@@ -1,5 +1,10 @@
package exh.metadata
import exh.metadata.models.SearchableGalleryMetadata
import exh.plusAssign
import java.text.SimpleDateFormat
import java.util.*
/**
* Metadata utils
*/
@@ -44,4 +49,37 @@ fun <T> ignore(expr: () -> T): T? {
fun <K,V> Set<Map.Entry<K,V>>.forEach(action: (K, V) -> Unit) {
forEach { action(it.key, it.value) }
}
}
val ONGOING_SUFFIX = arrayOf(
"[ongoing]",
"(ongoing)",
"{ongoing}",
"<ongoing>",
"ongoing",
"[incomplete]",
"(incomplete)",
"{incomplete}",
"<incomplete>",
"incomplete",
"[wip]",
"(wip)",
"{wip}",
"<wip>",
"wip"
)
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"
}
}
}

View File

@@ -1,219 +0,0 @@
package exh.metadata
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.all.EHentai
import eu.kanade.tachiyomi.source.online.all.PervEden
import exh.metadata.models.*
import exh.plusAssign
import uy.kohesive.injekt.injectLazy
import java.text.SimpleDateFormat
import java.util.*
/**
* Copies gallery metadata to a manga object
*/
private const val EH_ARTIST_NAMESPACE = "artist"
private const val EH_AUTHOR_NAMESPACE = "author"
private const val NHENTAI_ARTIST_NAMESPACE = "artist"
private const val NHENTAI_CATEGORIES_NAMESPACE = "category"
private val ONGOING_SUFFIX = arrayOf(
"[ongoing]",
"(ongoing)",
"{ongoing}"
)
val EX_DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US)
private val prefs: PreferencesHelper by injectLazy()
fun ExGalleryMetadata.copyTo(manga: SManga) {
//TODO Find some way to do this with SManga
/*exh?.let {
manga.source = if(it)
2
else
1
}*/
url?.let { manga.url = it }
thumbnailUrl?.let { manga.thumbnail_url = it }
//No title bug?
val titleObj = if(prefs.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!! })
}
//Set author (if we can find one)
tags.filter { it.namespace == EH_AUTHOR_NAMESPACE }.let {
if(it.isNotEmpty()) manga.author = it.joinToString(transform = { it.name!! })
}
//Set genre
genre?.let { manga.genre = it }
//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()
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")
}
fun PervEdenGalleryMetadata.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 {
manga.genre = it
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)
}
val tagsDesc = buildTagsDescription(this)
manga.description = listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString())
.filter(String::isNotBlank)
.joinToString(separator = "\n")
}
fun NHentaiMetadata.copyTo(manga: SManga) {
url?.let { manga.url = it }
//TODO next update allow this to be changed to use HD covers
if(mediaId != null)
NHentaiMetadata.typeToExtension(thumbnailImageType)?.let {
manga.thumbnail_url = "https://t.nhentai.net/galleries/$mediaId/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!! })
}
tags.filter { it.namespace == NHENTAI_CATEGORIES_NAMESPACE }.let {
if(it.isNotEmpty()) manga.genre = it.joinToString(transform = { it.name!! })
}
//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()
uploadDate?.let { detailsDesc += "Upload Date: ${EX_DATE_FORMAT.format(Date(it))}\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")
}
fun SearchableGalleryMetadata.genericCopyTo(manga: SManga): Boolean {
when(this) {
is ExGalleryMetadata -> this.copyTo(manga)
is PervEdenGalleryMetadata -> this.copyTo(manga)
is NHentaiMetadata -> this.copyTo(manga)
else -> return false
}
return true
}
private 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"
}
}
}

View File

@@ -1,12 +1,22 @@
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.EX_DATE_FORMAT
import exh.metadata.ONGOING_SUFFIX
import exh.metadata.buildTagsDescription
import exh.metadata.humanReadableByteCount
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.*
/**
@@ -61,12 +71,99 @@ open class ExGalleryMetadata : RealmObject(), SearchableGalleryMetadata {
@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(
ExGalleryMetadata::gId to Query::gId,
ExGalleryMetadata::gToken to Query::gToken,
ExGalleryMetadata::exh to Query::exh
)
}
override fun copyTo(manga: SManga) {
url?.let { manga.url = 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!! })
}
//Set author (if we can find one)
tags.filter { it.namespace == EH_AUTHOR_NAMESPACE }.let {
if(it.isNotEmpty()) manga.author = it.joinToString(transform = { it.name!! })
}
//Set genre
genre?.let { manga.genre = it }
//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()
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 {
Uri.parse(it).pathSegments
.filterNot(String::isNullOrBlank)
}
Uri.parse(it).pathSegments
.filterNot(String::isNullOrBlank)
}
fun galleryId(url: String) = splitGalleryUrl(url).let { it[it.size - 2] }
@@ -77,5 +174,9 @@ open class ExGalleryMetadata : RealmObject(), SearchableGalleryMetadata {
ExGalleryMetadata::title.name,
ExGalleryMetadata::altTitle.name
)
private const val EH_ARTIST_NAMESPACE = "artist"
private const val EH_AUTHOR_NAMESPACE = "author"
}
}

View File

@@ -0,0 +1,68 @@
package exh.metadata.models
import io.realm.*
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.qualifiedName}!")
}
}
}
return newMeta
}
}

View File

@@ -0,0 +1,91 @@
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 title: String? = null
var artist: String? = null
override var uploader: String? = null
override var tags: RealmList<Tag> = RealmList()
override fun getTitles() = listOf(title).filterNotNull()
@Ignore
override val titleFields = listOf(
HentaiCafeMetadata::title.name
)
@Index
override var mangaId: Long? = null
override fun copyTo(manga: SManga) {
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() }
}
}

View File

@@ -1,11 +1,21 @@
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.EX_DATE_FORMAT
import exh.metadata.ONGOING_SUFFIX
import exh.metadata.buildTagsDescription
import exh.metadata.nullIfBlank
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.*
/**
@@ -58,18 +68,92 @@ open class NHentaiMetadata : RealmObject(), SearchableGalleryMetadata {
@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(
nhIdFromUrl(url)
)
}
class Query(
val nhId: Long
) : GalleryQuery<NHentaiMetadata>(NHentaiMetadata::class) {
override fun map() = mapOf(
NHentaiMetadata::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_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!! })
}
tags.filter { it.namespace == NHENTAI_CATEGORIES_NAMESPACE }.let {
if(it.isNotEmpty()) manga.genre = it.joinToString(transform = { it.name!! })
}
//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()
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
}
when(t) {
"p" -> "png"
"j" -> "jpg"
else -> null
}
fun nhIdFromUrl(url: String)
= url.split("/").last { it.isNotBlank() }.toLong()
= url.split("/").last { it.isNotBlank() }.toLong()
val TITLE_FIELDS = listOf(
NHentaiMetadata::japaneseTitle.name,

View File

@@ -1,8 +1,14 @@
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.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
@@ -50,11 +56,79 @@ open class PervEdenGalleryMetadata : RealmObject(), SearchableGalleryMetadata {
@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 {
manga.genre = it
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)
}
val tagsDesc = buildTagsDescription(this)
manga.description = listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString())
.filter(String::isNotBlank)
.joinToString(separator = "\n")
}
class EmptyQuery : GalleryQuery<PervEdenGalleryMetadata>(PervEdenGalleryMetadata::class)
class UrlQuery(
val url: String,
val lang: PervEdenLang
) : GalleryQuery<PervEdenGalleryMetadata>(PervEdenGalleryMetadata::class) {
override fun transform() = Query(
pvIdFromUrl(url),
lang
)
}
class Query(val pvId: String,
val lang: PervEdenLang
) : GalleryQuery<PervEdenGalleryMetadata>(PervEdenGalleryMetadata::class) {
override fun map() = mapOf(
PervEdenGalleryMetadata::pvId to Query::pvId
)
override fun override(meta: RealmQuery<PervEdenGalleryMetadata>)
= meta.equalTo(PervEdenGalleryMetadata::lang.name, lang.name)
}
companion object {
private fun splitGalleryUrl(url: String)
= url.let {
Uri.parse(it).pathSegments.filterNot(String::isNullOrBlank)
}
Uri.parse(it).pathSegments.filterNot(String::isNullOrBlank)
}
fun pvIdFromUrl(url: String) = splitGalleryUrl(url).last()
@@ -88,3 +162,14 @@ open class PervEdenTitle(var metadata: PervEdenGalleryMetadata? = null,
override fun toString() = "PervEdenTitle(metadata=$metadata, title=$title)"
}
enum class PervEdenLang(val id: Long) {
en(PERV_EDEN_EN_SOURCE_ID),
it(PERV_EDEN_IT_SOURCE_ID);
companion object {
fun source(id: Long)
= PervEdenLang.values().find { it.id == id }
?: throw IllegalArgumentException("Unknown source ID: $id!")
}
}

View File

@@ -1,11 +1,8 @@
package exh.metadata.models
import eu.kanade.tachiyomi.source.model.SManga
import io.realm.RealmList
import io.realm.RealmModel
import io.realm.annotations.Index
import java.util.ArrayList
import java.util.HashMap
import kotlin.reflect.KCallable
/**
* A gallery that can be searched using the EH search engine
@@ -23,4 +20,6 @@ interface SearchableGalleryMetadata: RealmModel {
val titleFields: List<String>
var mangaId: Long?
fun copyTo(manga: SManga)
}