Support Comic Info creation on download (#887)
* Support Comic Info creation on download * Update Json and add Protobuf
This commit is contained in:
@@ -19,6 +19,11 @@ import android.app.Application
|
||||
import eu.kanade.tachiyomi.network.JavaScriptEngine
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.protobuf.ProtoBuf
|
||||
import nl.adaptivity.xmlutil.serialization.XML
|
||||
import org.kodein.di.DI
|
||||
import org.kodein.di.conf.global
|
||||
import org.kodein.di.instance
|
||||
import rx.Observable
|
||||
import rx.schedulers.Schedulers
|
||||
import uy.kohesive.injekt.api.InjektModule
|
||||
@@ -53,7 +58,20 @@ class AppModule(val app: Application) : InjektModule {
|
||||
//
|
||||
// addSingletonFactory { LibrarySyncManager(app) }
|
||||
|
||||
addSingletonFactory { Json { ignoreUnknownKeys = true } }
|
||||
addSingletonFactory {
|
||||
val json by DI.global.instance<Json>()
|
||||
json
|
||||
}
|
||||
|
||||
addSingletonFactory {
|
||||
val xml by DI.global.instance<XML>()
|
||||
xml
|
||||
}
|
||||
|
||||
addSingletonFactory {
|
||||
val protobuf by DI.global.instance<ProtoBuf>()
|
||||
protobuf
|
||||
}
|
||||
|
||||
// Asynchronously init expensive components for a faster cold start
|
||||
|
||||
|
||||
+16
@@ -7,9 +7,14 @@ import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.sample
|
||||
import org.jetbrains.exposed.sql.select
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import suwayomi.tachidesk.manga.impl.Page
|
||||
import suwayomi.tachidesk.manga.impl.download.model.DownloadChapter
|
||||
import suwayomi.tachidesk.manga.impl.util.createComicInfoFile
|
||||
import suwayomi.tachidesk.manga.impl.util.getChapterCachePath
|
||||
import suwayomi.tachidesk.manga.model.table.ChapterTable
|
||||
import suwayomi.tachidesk.manga.model.table.MangaTable
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
|
||||
@@ -62,6 +67,17 @@ abstract class ChaptersFilesProvider(val mangaId: Int, val chapterId: Int) : Dow
|
||||
download.progress = ((pageNum + 1).toFloat()) / pageCount
|
||||
step(download, false)
|
||||
}
|
||||
|
||||
createComicInfoFile(
|
||||
folder.toPath(),
|
||||
transaction {
|
||||
MangaTable.select { MangaTable.id eq mangaId }.first()
|
||||
},
|
||||
transaction {
|
||||
ChapterTable.select { ChapterTable.id eq chapterId }.first()
|
||||
},
|
||||
)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
package suwayomi.tachidesk.manga.impl.util
|
||||
|
||||
import eu.kanade.tachiyomi.source.local.metadata.COMIC_INFO_FILE
|
||||
import eu.kanade.tachiyomi.source.local.metadata.ComicInfo
|
||||
import eu.kanade.tachiyomi.source.local.metadata.ComicInfoPublishingStatus
|
||||
import nl.adaptivity.xmlutil.serialization.XML
|
||||
import org.jetbrains.exposed.sql.ResultRow
|
||||
import org.jetbrains.exposed.sql.SortOrder
|
||||
import org.jetbrains.exposed.sql.select
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import suwayomi.tachidesk.manga.model.table.CategoryMangaTable
|
||||
import suwayomi.tachidesk.manga.model.table.CategoryTable
|
||||
import suwayomi.tachidesk.manga.model.table.ChapterTable
|
||||
import suwayomi.tachidesk.manga.model.table.MangaTable
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.deleteIfExists
|
||||
import kotlin.io.path.div
|
||||
import kotlin.io.path.outputStream
|
||||
|
||||
/**
|
||||
* Creates a ComicInfo instance based on the manga and chapter metadata.
|
||||
*/
|
||||
fun getComicInfo(
|
||||
manga: ResultRow,
|
||||
chapter: ResultRow,
|
||||
chapterUrl: String,
|
||||
categories: List<String>?,
|
||||
) = ComicInfo(
|
||||
title = ComicInfo.Title(chapter[ChapterTable.name]),
|
||||
series = ComicInfo.Series(manga[MangaTable.title]),
|
||||
number =
|
||||
chapter[ChapterTable.chapter_number].takeIf { it >= 0 }?.let {
|
||||
if ((it.rem(1) == 0.0f)) {
|
||||
ComicInfo.Number(it.toInt().toString())
|
||||
} else {
|
||||
ComicInfo.Number(it.toString())
|
||||
}
|
||||
},
|
||||
web = ComicInfo.Web(chapterUrl),
|
||||
summary = manga[MangaTable.description]?.let { ComicInfo.Summary(it) },
|
||||
writer = manga[MangaTable.author]?.let { ComicInfo.Writer(it) },
|
||||
penciller = manga[MangaTable.artist]?.let { ComicInfo.Penciller(it) },
|
||||
translator = chapter[ChapterTable.scanlator]?.let { ComicInfo.Translator(it) },
|
||||
genre = manga[MangaTable.genre]?.let { ComicInfo.Genre(it) },
|
||||
publishingStatus =
|
||||
ComicInfo.PublishingStatusTachiyomi(
|
||||
ComicInfoPublishingStatus.toComicInfoValue(manga[MangaTable.status].toLong()),
|
||||
),
|
||||
categories = categories?.let { ComicInfo.CategoriesTachiyomi(it.joinToString()) },
|
||||
inker = null,
|
||||
colorist = null,
|
||||
letterer = null,
|
||||
coverArtist = null,
|
||||
tags = null,
|
||||
)
|
||||
|
||||
/**
|
||||
* Creates a ComicInfo.xml file inside the given directory.
|
||||
*/
|
||||
fun createComicInfoFile(
|
||||
dir: Path,
|
||||
manga: ResultRow,
|
||||
chapter: ResultRow,
|
||||
) {
|
||||
val chapterUrl = chapter[ChapterTable.realUrl].orEmpty()
|
||||
val categories =
|
||||
transaction {
|
||||
CategoryMangaTable.innerJoin(CategoryTable).select {
|
||||
CategoryMangaTable.manga eq manga[MangaTable.id]
|
||||
}.orderBy(CategoryTable.order to SortOrder.ASC).map {
|
||||
it[CategoryTable.name]
|
||||
}
|
||||
}.takeUnless { it.isEmpty() }
|
||||
val comicInfo = getComicInfo(manga, chapter, chapterUrl, categories)
|
||||
// Remove the old file
|
||||
(dir / COMIC_INFO_FILE).deleteIfExists()
|
||||
(dir / COMIC_INFO_FILE).outputStream().use {
|
||||
val comicInfoString = Injekt.get<XML>().encodeToString(ComicInfo.serializer(), comicInfo)
|
||||
it.write(comicInfoString.toByteArray())
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,11 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.protobuf.ProtoBuf
|
||||
import mu.KotlinLogging
|
||||
import nl.adaptivity.xmlutil.XmlDeclMode
|
||||
import nl.adaptivity.xmlutil.core.XmlVersion
|
||||
import nl.adaptivity.xmlutil.serialization.XML
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||
import org.kodein.di.DI
|
||||
import org.kodein.di.bind
|
||||
@@ -33,7 +37,6 @@ import suwayomi.tachidesk.server.database.databaseUp
|
||||
import suwayomi.tachidesk.server.generated.BuildConfig
|
||||
import suwayomi.tachidesk.server.util.AppMutex.handleAppMutex
|
||||
import suwayomi.tachidesk.server.util.SystemTray
|
||||
import uy.kohesive.injekt.api.get
|
||||
import xyz.nulldev.androidcompat.AndroidCompat
|
||||
import xyz.nulldev.androidcompat.AndroidCompatInitializer
|
||||
import xyz.nulldev.ts.config.ApplicationRootDir
|
||||
@@ -112,7 +115,29 @@ fun applicationSetup() {
|
||||
bind<ApplicationDirs>() with singleton { applicationDirs }
|
||||
bind<IUpdater>() with singleton { Updater() }
|
||||
bind<JsonMapper>() with singleton { JavalinJackson() }
|
||||
bind<Json>() with singleton { Json { ignoreUnknownKeys = true } }
|
||||
bind<Json>() with
|
||||
singleton {
|
||||
Json {
|
||||
ignoreUnknownKeys = true
|
||||
explicitNulls = false
|
||||
}
|
||||
}
|
||||
bind<XML>() with
|
||||
singleton {
|
||||
XML {
|
||||
defaultPolicy {
|
||||
ignoreUnknownChildren()
|
||||
}
|
||||
autoPolymorphic = true
|
||||
xmlDeclMode = XmlDeclMode.Charset
|
||||
indent = 2
|
||||
xmlVersion = XmlVersion.XML10
|
||||
}
|
||||
}
|
||||
bind<ProtoBuf>() with
|
||||
singleton {
|
||||
ProtoBuf
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user