Merge branch 'master' of github.com:Suwayomi/Tachidesk

This commit is contained in:
Aria Moradi 2021-05-30 04:56:59 +04:30
commit 10a29cab33
20 changed files with 362 additions and 24 deletions

View File

@ -1,6 +1,7 @@
plugins {
application
kotlin("plugin.serialization")
}
@ -46,6 +47,17 @@ dependencies {
implementation("org.mozilla:rhino-runtime:1.7.13")
// 'org.mozilla:rhino-engine' provides the same interface as 'javax.script' a.k.a Nashorn
implementation("org.mozilla:rhino-engine:1.7.13")
// Kotlin wrapper around Java Preferences, makes certain things easier
val multiplatformSettingsVersion = "0.7.7"
implementation("com.russhwolf:multiplatform-settings-jvm:$multiplatformSettingsVersion")
implementation("com.russhwolf:multiplatform-settings-serialization-jvm:$multiplatformSettingsVersion")
}
tasks {
withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions.freeCompilerArgs = listOf("-Xopt-in=kotlin.RequiresOptIn")
}
}
//def fatJarTask = tasks.getByPath(':AndroidCompat:JVMPatch:fatJar')

View File

@ -38,7 +38,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import xyz.nulldev.androidcompat.info.ApplicationInfoImpl;
import xyz.nulldev.androidcompat.io.AndroidFiles;
import xyz.nulldev.androidcompat.io.sharedprefs.JsonSharedPreferences;
import xyz.nulldev.androidcompat.io.sharedprefs.JavaSharedPreferences;
import xyz.nulldev.androidcompat.service.ServiceSupport;
import xyz.nulldev.androidcompat.util.KodeinGlobalHelper;
@ -165,23 +165,22 @@ public class CustomContext extends Context implements DIAware {
/** Fake shared prefs! **/
private Map<String, SharedPreferences> prefs = new HashMap<>(); //Cache
private File sharedPrefsFileFromString(String s) {
return new File(androidFiles.getPrefsDir(), s + ".json");
}
@Override
public synchronized SharedPreferences getSharedPreferences(String s, int i) {
SharedPreferences preferences = prefs.get(s);
//Create new shared preferences if one does not exist
if(preferences == null) {
preferences = getSharedPreferences(sharedPrefsFileFromString(s), i);
preferences = new JavaSharedPreferences(s);
prefs.put(s, preferences);
}
return preferences;
}
public SharedPreferences getSharedPreferences(File file, int mode) {
return new JsonSharedPreferences(file);
@Override
public SharedPreferences getSharedPreferences(@NotNull File file, int mode) {
String path = file.getAbsolutePath().replace('\\', '/');
int firstSlash = path.indexOf("/");
return new JavaSharedPreferences(path.substring(firstSlash));
}
@Override
@ -191,8 +190,8 @@ public class CustomContext extends Context implements DIAware {
@Override
public boolean deleteSharedPreferences(String name) {
prefs.remove(name);
return sharedPrefsFileFromString(name).delete();
JavaSharedPreferences item = (JavaSharedPreferences) prefs.remove(name);
return item.deleteAll();
}
@Override

View File

@ -26,8 +26,6 @@ class AndroidFiles(val configManager: ConfigManager = GlobalConfigManager) {
val downloadCacheDir: File get() = registerFile(filesConfig.downloadCacheDir)
val databasesDir: File get() = registerFile(filesConfig.databasesDir)
val prefsDir: File get() = registerFile(filesConfig.prefsDir)
val packagesDir: File get() = registerFile(filesConfig.packageDir)
fun registerFile(file: String): File {

View File

@ -0,0 +1,168 @@
package xyz.nulldev.androidcompat.io.sharedprefs
import android.content.SharedPreferences
import com.russhwolf.settings.ExperimentalSettingsApi
import com.russhwolf.settings.ExperimentalSettingsImplementation
import com.russhwolf.settings.JvmPreferencesSettings
import com.russhwolf.settings.serialization.decodeValue
import com.russhwolf.settings.serialization.encodeValue
import com.russhwolf.settings.set
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerializationException
import kotlinx.serialization.builtins.SetSerializer
import kotlinx.serialization.builtins.nullable
import kotlinx.serialization.builtins.serializer
import java.util.prefs.PreferenceChangeListener
import java.util.prefs.Preferences
@OptIn(ExperimentalSettingsImplementation::class, ExperimentalSerializationApi::class, ExperimentalSettingsApi::class)
class JavaSharedPreferences(key: String) : SharedPreferences {
private val javaPreferences = Preferences.userRoot().node("suwayomi/tachidesk/$key")
private val preferences = JvmPreferencesSettings(javaPreferences)
private val listeners = mutableMapOf<SharedPreferences.OnSharedPreferenceChangeListener, PreferenceChangeListener>()
// TODO: 2021-05-29 Need to find a way to get this working with all pref types
override fun getAll(): MutableMap<String, *> {
return preferences.keys.associateWith { preferences.getStringOrNull(it) }.toMutableMap()
}
override fun getString(key: String, defValue: String?): String? {
return if (defValue != null) {
preferences.getString(key, defValue)
} else {
preferences.getStringOrNull(key)
}
}
override fun getStringSet(key: String, defValues: MutableSet<String>?): MutableSet<String>? {
try {
return if (defValues != null) {
preferences.decodeValue(SetSerializer(String.serializer()).nullable, key, defValues)
} else {
preferences.decodeValue(SetSerializer(String.serializer()).nullable, key, null)
}?.toMutableSet()
} catch (e: SerializationException) {
throw ClassCastException("$key was not a StringSet")
}
}
override fun getInt(key: String, defValue: Int): Int {
return preferences.getInt(key, defValue)
}
override fun getLong(key: String, defValue: Long): Long {
return preferences.getLong(key, defValue)
}
override fun getFloat(key: String, defValue: Float): Float {
return preferences.getFloat(key, defValue)
}
override fun getBoolean(key: String, defValue: Boolean): Boolean {
return preferences.getBoolean(key, defValue)
}
override fun contains(key: String): Boolean {
return key in preferences.keys
}
override fun edit(): SharedPreferences.Editor {
return Editor(preferences)
}
class Editor(private val preferences: JvmPreferencesSettings) : SharedPreferences.Editor {
val itemsToAdd = mutableMapOf<String, Any>()
override fun putString(key: String, value: String?): SharedPreferences.Editor {
if (value != null) {
itemsToAdd[key] = value
} else {
remove(key)
}
return this
}
override fun putStringSet(
key: String,
values: MutableSet<String>?
): SharedPreferences.Editor {
if (values != null) {
itemsToAdd[key] = values
} else {
remove(key)
}
return this
}
override fun putInt(key: String, value: Int): SharedPreferences.Editor {
itemsToAdd[key] = value
return this
}
override fun putLong(key: String, value: Long): SharedPreferences.Editor {
itemsToAdd[key] = value
return this
}
override fun putFloat(key: String, value: Float): SharedPreferences.Editor {
itemsToAdd[key] = value
return this
}
override fun putBoolean(key: String, value: Boolean): SharedPreferences.Editor {
itemsToAdd[key] = value
return this
}
override fun remove(key: String): SharedPreferences.Editor {
itemsToAdd.remove(key)
return this
}
override fun clear(): SharedPreferences.Editor {
itemsToAdd.clear()
return this
}
override fun commit(): Boolean {
addToPreferences()
return true
}
override fun apply() {
addToPreferences()
}
private fun addToPreferences() {
itemsToAdd.forEach { (key, value) ->
@Suppress("UNCHECKED_CAST")
when (value) {
is Set<*> -> preferences.encodeValue(SetSerializer(String.serializer()), key, value as Set<String>)
else -> {
preferences[key] = value
}
}
}
}
}
override fun registerOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener) {
val javaListener = PreferenceChangeListener {
listener.onSharedPreferenceChanged(this, it.key)
}
listeners[listener] = javaListener
javaPreferences.addPreferenceChangeListener(javaListener)
}
override fun unregisterOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener) {
val registeredListener = listeners.remove(listener)
if (registeredListener != null) {
javaPreferences.removePreferenceChangeListener(registeredListener)
}
}
fun deleteAll(): Boolean {
javaPreferences.removeNode()
return true
}
}

View File

@ -23,7 +23,7 @@ Here is a list of current features:
- A library to save your mangas and categories to put them into.
- Searching and browsing installed sources.
- A decent chapter reader.
- Ability to download Mangas for offline read(This partially works)
- Ability to download Mangas for offline read
- Backup and restore support powered by Tachiyomi Legacy Backups
**Note:** Keep in mind that Tachidesk is alpha software and can break rarely and/or with each update. See [Troubleshooting](https://github.com/Suwayomi/Tachidesk/wiki/Troubleshooting) if it happens.

View File

@ -2,6 +2,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm") version "1.4.32"
kotlin("plugin.serialization") version "1.4.32" apply false
}
allprojects {
@ -50,6 +51,10 @@ configure(projects) {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$coroutinesVersion")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion")
val kotlinSerializationVersion = "1.2.1"
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerializationVersion")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-protobuf:$kotlinSerializationVersion")
// Dependency Injection
implementation("org.kodein.di:kodein-di-conf-jvm:7.5.0")

View File

@ -14,7 +14,7 @@ import suwayomi.server.database.migration.lib.Migration
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
class M0004_AnimeTablesBatch1 : Migration() {
private object AnimeExtensionTable : IntIdTable() {
private class AnimeExtensionTable : IntIdTable() {
val apkName = varchar("apk_name", 1024)
// default is the local source icon from tachiyomi
@ -35,7 +35,7 @@ class M0004_AnimeTablesBatch1 : Migration() {
val classFQName = varchar("class_name", 1024).default("") // fully qualified name
}
private object AnimeSourceTable : IdTable<Long>() {
private class AnimeSourceTable : IdTable<Long>() {
override val id = long("id").entityId()
val name = varchar("name", 128)
val lang = varchar("lang", 10)
@ -46,8 +46,8 @@ class M0004_AnimeTablesBatch1 : Migration() {
override fun run() {
transaction {
SchemaUtils.create(
AnimeExtensionTable,
AnimeSourceTable
AnimeExtensionTable(),
AnimeSourceTable()
)
}
}

View File

@ -14,7 +14,7 @@ import suwayomi.server.database.migration.lib.Migration
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
class M0005_AnimeTablesBatch2 : Migration() {
private object AnimeTable : IntIdTable() {
private class AnimeTable : IntIdTable() {
val url = varchar("url", 2048)
val title = varchar("title", 512)
val initialized = bool("initialized").default(false)
@ -38,7 +38,7 @@ class M0005_AnimeTablesBatch2 : Migration() {
override fun run() {
transaction {
SchemaUtils.create(
AnimeTable
AnimeTable()
)
}
}

View File

@ -14,7 +14,7 @@ import suwayomi.server.database.migration.lib.Migration
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
class M0006_AnimeTablesBatch3 : Migration() {
private object EpisodeTable : IntIdTable() {
private class EpisodeTable : IntIdTable() {
val url = varchar("url", 2048)
val name = varchar("name", 512)
val date_upload = long("date_upload").default(0)
@ -34,7 +34,7 @@ class M0006_AnimeTablesBatch3 : Migration() {
override fun run() {
transaction {
SchemaUtils.create(
EpisodeTable
EpisodeTable()
)
}
}

View File

@ -0,0 +1,38 @@
package suwayomi.server.database.migration
import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.ReferenceOption
import org.jetbrains.exposed.sql.SchemaUtils
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.server.database.migration.lib.Migration
import suwayomi.tachidesk.model.table.ChapterTable
import suwayomi.tachidesk.model.table.MangaTable
/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
class M0010_MangaAndChapterMeta : Migration() {
private class ChapterMetaTable : IntIdTable() {
val key = varchar("key", 256)
val value = varchar("value", 4096)
val ref = reference("chapter_ref", ChapterTable, ReferenceOption.CASCADE)
}
private class MangaMetaTable : IntIdTable() {
val key = varchar("key", 256)
val value = varchar("value", 4096)
val ref = reference("manga_ref", MangaTable, ReferenceOption.CASCADE)
}
override fun run() {
transaction {
SchemaUtils.create(
ChapterMetaTable(),
MangaMetaTable()
)
}
}
}

View File

@ -18,11 +18,13 @@ import suwayomi.tachidesk.impl.CategoryManga.removeMangaFromCategory
import suwayomi.tachidesk.impl.Chapter.getChapter
import suwayomi.tachidesk.impl.Chapter.getChapterList
import suwayomi.tachidesk.impl.Chapter.modifyChapter
import suwayomi.tachidesk.impl.Chapter.modifyChapterMeta
import suwayomi.tachidesk.impl.Library.addMangaToLibrary
import suwayomi.tachidesk.impl.Library.getLibraryMangas
import suwayomi.tachidesk.impl.Library.removeMangaFromLibrary
import suwayomi.tachidesk.impl.Manga.getManga
import suwayomi.tachidesk.impl.Manga.getMangaThumbnail
import suwayomi.tachidesk.impl.Manga.modifyMangaMeta
import suwayomi.tachidesk.impl.MangaList.getMangaList
import suwayomi.tachidesk.impl.Page.getPageImage
import suwayomi.tachidesk.impl.Search.sourceFilters
@ -185,6 +187,18 @@ object TachideskAPI {
ctx.json(future { getChapterList(mangaId, onlineFetch) })
}
// used to modify a manga's meta paramaters
app.patch("/api/v1/manga/:mangaId/meta") { ctx ->
val mangaId = ctx.pathParam("mangaId").toInt()
val key = ctx.formParam("key")!!
val value = ctx.formParam("value")!!
modifyMangaMeta(mangaId, key, value)
ctx.status(200)
}
// used to display a chapter, get a chapter in order to show it's pages
app.get("/api/v1/manga/:mangaId/chapter/:chapterIndex") { ctx ->
val chapterIndex = ctx.pathParam("chapterIndex").toInt()
@ -207,6 +221,19 @@ object TachideskAPI {
ctx.status(200)
}
// used to modify a chapter's meta paramaters
app.patch("/api/v1/manga/:mangaId/chapter/:chapterIndex/meta") { ctx ->
val chapterIndex = ctx.pathParam("chapterIndex").toInt()
val mangaId = ctx.pathParam("mangaId").toInt()
val key = ctx.formParam("key")!!
val value = ctx.formParam("value")!!
modifyChapterMeta(mangaId, chapterIndex, key, value)
ctx.status(200)
}
// get page at index "index"
app.get("/api/v1/manga/:mangaId/chapter/:chapterIndex/page/:index") { ctx ->
val mangaId = ctx.pathParam("mangaId").toInt()

View File

@ -9,6 +9,7 @@ package suwayomi.tachidesk.impl
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.sql.SortOrder.DESC
import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.deleteWhere
@ -20,6 +21,7 @@ import suwayomi.tachidesk.impl.Manga.getManga
import suwayomi.tachidesk.impl.util.GetHttpSource.getHttpSource
import suwayomi.tachidesk.impl.util.lang.awaitSingle
import suwayomi.tachidesk.model.dataclass.ChapterDataClass
import suwayomi.tachidesk.model.table.ChapterMetaTable
import suwayomi.tachidesk.model.table.ChapterTable
import suwayomi.tachidesk.model.table.MangaTable
import suwayomi.tachidesk.model.table.PageTable
@ -131,6 +133,7 @@ object Chapter {
dbChapter[ChapterTable.pageCount],
chapterList.size,
meta = getChapterMetaMap(dbChapter[ChapterTable.id])
)
}
}
@ -199,7 +202,8 @@ object Chapter {
chapterEntry[ChapterTable.chapterIndex],
chapterEntry[ChapterTable.isDownloaded],
pageCount,
chapterCount.toInt()
chapterCount.toInt(),
getChapterMetaMap(chapterEntry[ChapterTable.id])
)
} else {
ChapterTable.toDataClass(chapterEntry)
@ -230,4 +234,30 @@ object Chapter {
}
}
}
fun getChapterMetaMap(chapter: EntityID<Int>): Map<String, String> {
return transaction {
ChapterMetaTable.select { ChapterMetaTable.ref eq chapter }
.associate { it[ChapterMetaTable.key] to it[ChapterMetaTable.value] }
}
}
fun modifyChapterMeta(mangaId: Int, chapterIndex: Int, key: String, value: String) {
transaction {
val chapter = ChapterTable.select { (ChapterTable.manga eq mangaId) and (ChapterTable.chapterIndex eq chapterIndex) }
.first()[ChapterTable.id]
val meta = transaction { ChapterMetaTable.select { (ChapterMetaTable.ref eq chapter) and (ChapterMetaTable.key eq key) } }.firstOrNull()
if (meta == null) {
ChapterMetaTable.insert {
it[ChapterMetaTable.key] = key
it[ChapterMetaTable.value] = value
it[ChapterMetaTable.ref] = chapter
}
} else {
ChapterMetaTable.update {
it[ChapterMetaTable.value] = value
}
}
}
}
}

View File

@ -9,6 +9,9 @@ package suwayomi.tachidesk.impl
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.SManga
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.insert
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.update
@ -24,6 +27,7 @@ import suwayomi.tachidesk.impl.util.network.await
import suwayomi.tachidesk.impl.util.storage.CachedImageResponse.clearCachedImage
import suwayomi.tachidesk.impl.util.storage.CachedImageResponse.getCachedImageResponse
import suwayomi.tachidesk.model.dataclass.MangaDataClass
import suwayomi.tachidesk.model.table.MangaMetaTable
import suwayomi.tachidesk.model.table.MangaStatus
import suwayomi.tachidesk.model.table.MangaTable
import java.io.InputStream
@ -57,6 +61,7 @@ object Manga {
MangaStatus.valueOf(mangaEntry[MangaTable.status]).name,
mangaEntry[MangaTable.inLibrary],
getSource(mangaEntry[MangaTable.sourceReference]),
getMangaMetaMap(mangaEntry[MangaTable.id]),
false
)
} else { // initialize manga
@ -104,11 +109,38 @@ object Manga {
MangaStatus.valueOf(fetchedManga.status).name,
mangaEntry[MangaTable.inLibrary],
getSource(mangaEntry[MangaTable.sourceReference]),
getMangaMetaMap(mangaEntry[MangaTable.id]),
true
)
}
}
fun getMangaMetaMap(manga: EntityID<Int>): Map<String, String> {
return transaction {
MangaMetaTable.select { MangaMetaTable.ref eq manga }
.associate { it[MangaMetaTable.key] to it[MangaMetaTable.value] }
}
}
fun modifyMangaMeta(mangaId: Int, key: String, value: String) {
transaction {
val manga = MangaMetaTable.select { (MangaTable.id eq mangaId) }
.first()[MangaTable.id]
val meta = transaction { MangaMetaTable.select { (MangaMetaTable.ref eq manga) and (MangaMetaTable.key eq key) } }.firstOrNull()
if (meta == null) {
MangaMetaTable.insert {
it[MangaMetaTable.key] = key
it[MangaMetaTable.value] = value
it[MangaMetaTable.ref] = manga
}
} else {
MangaMetaTable.update {
it[MangaMetaTable.value] = value
}
}
}
}
private val applicationDirs by DI.global.instance<ApplicationDirs>()
suspend fun getMangaThumbnail(mangaId: Int): Pair<InputStream, String> {
val saveDir = applicationDirs.mangaThumbnailsRoot

View File

@ -11,6 +11,7 @@ import eu.kanade.tachiyomi.source.model.MangasPage
import org.jetbrains.exposed.sql.insertAndGetId
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.impl.Manga.getMangaMetaMap
import suwayomi.tachidesk.impl.util.GetHttpSource.getHttpSource
import suwayomi.tachidesk.impl.util.lang.awaitSingle
import suwayomi.tachidesk.model.dataclass.MangaDataClass
@ -89,7 +90,8 @@ object MangaList {
mangaEntry[MangaTable.description],
mangaEntry[MangaTable.genre],
MangaStatus.valueOf(mangaEntry[MangaTable.status]).name,
mangaEntry[MangaTable.inLibrary]
mangaEntry[MangaTable.inLibrary],
meta = getMangaMetaMap(mangaEntry[MangaTable.id])
)
}
}

View File

@ -39,4 +39,6 @@ data class ChapterDataClass(
/** total chapter count, used to calculate if there's a next and prev chapter */
val chapterCount: Int? = null,
/** used to store client specific values */
val meta: Map<String, String> = emptyMap(),
)

View File

@ -26,6 +26,7 @@ data class MangaDataClass(
val status: String = MangaStatus.UNKNOWN.name,
val inLibrary: Boolean = false,
val source: SourceDataClass? = null,
val meta: Map<String, String> = emptyMap(),
val freshData: Boolean = false
)

View File

@ -0,0 +1,10 @@
package suwayomi.tachidesk.model.table
import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.ReferenceOption
object ChapterMetaTable : IntIdTable() {
val key = varchar("key", 256)
val value = varchar("value", 4096)
val ref = reference("chapter_ref", ChapterTable, ReferenceOption.CASCADE)
}

View File

@ -11,6 +11,7 @@ import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.ResultRow
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.impl.Chapter.getChapterMetaMap
import suwayomi.tachidesk.model.dataclass.ChapterDataClass
object ChapterTable : IntIdTable() {
@ -51,4 +52,5 @@ fun ChapterTable.toDataClass(chapterEntry: ResultRow) =
chapterEntry[isDownloaded],
chapterEntry[pageCount],
transaction { ChapterTable.select { ChapterTable.manga eq chapterEntry[manga].value }.count().toInt() },
getChapterMetaMap(chapterEntry[id]),
)

View File

@ -0,0 +1,10 @@
package suwayomi.tachidesk.model.table
import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.ReferenceOption
object MangaMetaTable : IntIdTable() {
val key = varchar("key", 256)
val value = varchar("value", 4096)
val ref = reference("manga_ref", MangaTable, ReferenceOption.CASCADE)
}

View File

@ -10,6 +10,7 @@ package suwayomi.tachidesk.model.table
import eu.kanade.tachiyomi.source.model.SManga
import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.ResultRow
import suwayomi.tachidesk.impl.Manga.getMangaMetaMap
import suwayomi.tachidesk.impl.MangaList.proxyThumbnailUrl
import suwayomi.tachidesk.model.dataclass.MangaDataClass
import suwayomi.tachidesk.model.table.MangaStatus.Companion
@ -50,7 +51,8 @@ fun MangaTable.toDataClass(mangaEntry: ResultRow) =
mangaEntry[description],
mangaEntry[genre],
Companion.valueOf(mangaEntry[status]).name,
mangaEntry[inLibrary]
mangaEntry[inLibrary],
meta = getMangaMetaMap(mangaEntry[id])
)
enum class MangaStatus(val status: Int) {