some refactor and comments

This commit is contained in:
Aria Moradi 2021-03-30 20:39:40 +04:30
parent 5b9219522d
commit addadefeb1
14 changed files with 84 additions and 54 deletions

View File

@ -19,6 +19,10 @@ import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.update
/**
* The new category will be placed at the end of the list
*/
fun createCategory(name: String) {
transaction {
val count = CategoryTable.selectAll().count()
@ -39,6 +43,9 @@ fun updateCategory(categoryId: Int, name: String?, isLanding: Boolean?) {
}
}
/**
* Move the category from position `from` to `to`
*/
fun reorderCategory(categoryId: Int, from: Int, to: Int) {
transaction {
val categories = CategoryTable.selectAll().orderBy(CategoryTable.order to SortOrder.ASC).toMutableList()

View File

@ -47,6 +47,10 @@ fun removeMangaFromCategory(mangaId: Int, categoryId: Int) {
}
}
/**
* list of mangas that belong to a category
*/
fun getCategoryMangaList(categoryId: Int): List<MangaDataClass> {
return transaction {
CategoryMangaTable.innerJoin(MangaTable).select { CategoryMangaTable.category eq categoryId }.map {
@ -55,6 +59,9 @@ fun getCategoryMangaList(categoryId: Int): List<MangaDataClass> {
}
}
/**
* list of categories that a manga belongs to
*/
fun getMangaCategories(mangaId: Int): List<CategoryDataClass> {
return transaction {
CategoryMangaTable.innerJoin(CategoryTable).select { CategoryMangaTable.manga eq mangaId }.orderBy(CategoryTable.order to SortOrder.ASC).map {

View File

@ -64,10 +64,10 @@ fun getChapterList(mangaId: Int): List<ChapterDataClass> {
// clear any orphaned chapters
val dbChapterCount = transaction { ChapterTable.selectAll().count() }
if (dbChapterCount > chapterCount) { // we got some clean up due
// TODO
// TODO: delete orphan chapters
}
return@transaction chapterList.mapIndexed { index, it ->
chapterList.mapIndexed { index, it ->
ChapterDataClass(
ChapterTable.select { ChapterTable.url eq it.url }.firstOrNull()!![ChapterTable.id].value,
it.url,
@ -136,6 +136,6 @@ fun getChapter(chapterIndex: Int, mangaId: Int): ChapterDataClass {
}
}
return@transaction chapter
chapter
}
}

View File

@ -15,9 +15,9 @@ import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.source.SourceFactory
import eu.kanade.tachiyomi.source.online.HttpSource
import ir.armor.tachidesk.impl.util.APKExtractor
import ir.armor.tachidesk.model.database.ExtensionTable
import ir.armor.tachidesk.model.database.SourceTable
import ir.armor.tachidesk.impl.util.APKExtractor
import ir.armor.tachidesk.server.applicationDirs
import kotlinx.coroutines.runBlocking
import mu.KotlinLogging
@ -114,42 +114,46 @@ fun installExtension(pkgName: String): Int {
File(dexFilePath).delete()
// update sources of the extension
val instance = loadExtensionInstance(jarFilePath,className)
val instance = loadExtensionInstance(jarFilePath, className)
val extensionId = transaction {
return@transaction ExtensionTable.select { ExtensionTable.name eq extensionRecord.name }.first()[ExtensionTable.id]
ExtensionTable.select { ExtensionTable.name eq extensionRecord.name }.firstOrNull()!![ExtensionTable.id]
}
if (instance is HttpSource) { // single source
val httpSource = instance as HttpSource
transaction {
if (SourceTable.select { SourceTable.id eq httpSource.id }.count() == 0L) {
SourceTable.insert {
it[this.id] = httpSource.id
it[name] = httpSource.name
it[this.lang] = httpSource.lang
it[extension] = extensionId
}
}
logger.debug("Installed source ${httpSource.name} with id ${httpSource.id}")
}
} else { // multi source
val sourceFactory = instance as SourceFactory
transaction {
sourceFactory.createSources().forEachIndexed { index, source ->
val httpSource = source as HttpSource
if (SourceTable.select { SourceTable.id eq httpSource.id }.count() == 0L) {
when (instance) {
is HttpSource -> { // single source
transaction {
if (SourceTable.select { SourceTable.id eq instance.id }.count() == 0L) {
SourceTable.insert {
it[this.id] = httpSource.id
it[name] = httpSource.name
it[this.lang] = httpSource.lang
it[this.id] = instance.id
it[name] = instance.name
it[this.lang] = instance.lang
it[extension] = extensionId
it[partOfFactorySource] = true
}
}
logger.debug("Installed source ${httpSource.name} with id:${httpSource.id}")
logger.debug("Installed source ${instance.name} with id ${instance.id}")
}
}
is SourceFactory -> { // theme source or multi lang
transaction {
instance.createSources().forEachIndexed { index, source ->
val httpSource = source as HttpSource
if (SourceTable.select { SourceTable.id eq httpSource.id }.count() == 0L) {
SourceTable.insert {
it[this.id] = httpSource.id
it[name] = httpSource.name
it[this.lang] = httpSource.lang
it[extension] = extensionId
it[partOfFactorySource] = true
}
}
logger.debug("Installed source ${httpSource.name} with id:${httpSource.id}")
}
}
}
else -> {
throw RuntimeException("Extension content is unexpected")
}
}
// update extension info

View File

@ -48,7 +48,7 @@ fun getExtensionList(): List<ExtensionDataClass> {
}
fun extensionTableAsDataClass() = transaction {
return@transaction ExtensionTable.selectAll().map {
ExtensionTable.selectAll().map {
ExtensionDataClass(
it[ExtensionTable.name],
it[ExtensionTable.pkgName],

View File

@ -17,6 +17,9 @@ import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.update
// TODO: `Category.isLanding` is to handle the default categories a new library manga gets,
// ..implement that shit at some time...
// ..also Consider to rename it to `isDefault`
fun addMangaToLibrary(mangaId: Int) {
val manga = getManga(mangaId)
if (!manga.inLibrary) {

View File

@ -88,7 +88,7 @@ fun getManga(mangaId: Int, proxyThumbnail: Boolean = true): MangaDataClass {
}
}
fun getThumbnail(mangaId: Int): Pair<InputStream, String> {
fun getMangaThumbnail(mangaId: Int): Pair<InputStream, String> {
val mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!! }
val saveDir = applicationDirs.thumbnailsRoot
val fileName = mangaId.toString()

View File

@ -21,6 +21,10 @@ import org.jetbrains.exposed.sql.update
import java.io.File
import java.io.InputStream
/**
* A page might have a imageUrl ready from the get go, or we might need to
* go an extra step and call fetchImageUrl to get it.
*/
fun getTrueImageUrl(page: Page, source: HttpSource): String {
if (page.imageUrl == null) {
page.imageUrl = source.fetchImageUrl(page).toBlocking().first()!!
@ -63,6 +67,7 @@ fun getPageImage(mangaId: Int, chapterIndex: Int, index: Int): Pair<InputStream,
}
}
// TODO: rewrite this to match tachiyomi
fun getChapterDir(mangaId: Int, chapterId: Int): String {
val mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!! }
val sourceId = mangaEntry[MangaTable.sourceReference]

View File

@ -9,6 +9,7 @@ package ir.armor.tachidesk.impl
import ir.armor.tachidesk.model.dataclass.PagedMangaListDataClass
// TODO
fun sourceFilters(sourceId: Long) {
val source = getHttpSource(sourceId)
// source.getFilterList().toItems()
@ -29,6 +30,9 @@ data class FilterWrapper(
val filter: Any
)
/**
* Note: Exhentai had a filter serializer (now in SY) that we might be able to steal
*/
// private fun FilterList.toFilterWrapper(): List<FilterWrapper> {
// return mapNotNull { filter ->
// when (filter) {

View File

@ -23,7 +23,6 @@ private val logger = KotlinLogging.logger {}
private val sourceCache = ConcurrentHashMap<Long, HttpSource>()
fun getHttpSource(sourceId: Long): HttpSource {
val cachedResult: HttpSource? = sourceCache[sourceId]
if (cachedResult != null) {
@ -41,10 +40,10 @@ fun getHttpSource(sourceId: Long): HttpSource {
val jarName = apkName.substringBefore(".apk") + ".jar"
val jarPath = "${applicationDirs.extensionsRoot}/$jarName"
val extensionInstance = loadExtensionInstance(jarPath,className)
val extensionInstance = loadExtensionInstance(jarPath, className)
if (sourceRecord[SourceTable.partOfFactorySource]) {
(extensionInstance as SourceFactory).createSources().forEach{
(extensionInstance as SourceFactory).createSources().forEach {
sourceCache[it.id] = it as HttpSource
}
} else {
@ -58,7 +57,7 @@ fun getHttpSource(sourceId: Long): HttpSource {
fun getSourceList(): List<SourceDataClass> {
return transaction {
return@transaction SourceTable.selectAll().map {
SourceTable.selectAll().map {
SourceDataClass(
it[SourceTable.id].value.toString(),
it[SourceTable.name],
@ -74,7 +73,7 @@ fun getSource(sourceId: Long): SourceDataClass {
return transaction {
val source = SourceTable.select { SourceTable.id eq sourceId }.firstOrNull()
return@transaction SourceDataClass(
SourceDataClass(
sourceId.toString(),
source?.get(SourceTable.name),
source?.get(SourceTable.lang),

View File

@ -134,8 +134,8 @@ object APKExtractor {
// AttrValue StrInd
off += 5 * 4 // Skip over the 5 words of an attribute
val attrName = compXmlString(
xml, sitOff, stOff,
attrNameSi
xml, sitOff, stOff,
attrNameSi
)
val attrValue = if (attrValueSi != -1) compXmlString(xml, sitOff, stOff, attrValueSi)
else "resourceID 0x ${Integer.toHexString(attrResId)}"
@ -151,21 +151,21 @@ object APKExtractor {
val name = compXmlString(xml, sitOff, stOff, nameSi)
finalXML.append("</$name>")
prtIndent(
indent,
"</" + name + "> (line " + startTagLineNo +
"-" + lineNo + ")"
indent,
"</" + name + "> (line " + startTagLineNo +
"-" + lineNo + ")"
)
// tr.parent(); // Step back up the NobTree
} else if (tag0 == endDocTag) { // END OF XML DOC TAG
break
} else {
logger.debug(
" Unrecognized tag code '${Integer.toHexString(tag0)}'' at offset $off"
" Unrecognized tag code '${Integer.toHexString(tag0)}'' at offset $off"
)
break
}
} // end of while loop scanning tags and attributes of XML tree
logger.debug(" end at offset $off");
logger.debug(" end at offset $off")
return finalXML.toString()
} // end of decompressXML
@ -197,16 +197,16 @@ object APKExtractor {
private fun LEW(arr: ByteArray, off: Int): Int {
return (arr[off + 3].toInt() shl 24) and -0x1000000 or
(arr[off + 2].toInt() shl 16 and 0xff0000) or
(arr[off + 1].toInt() shl 8 and 0xff00) or
(arr[off].toInt() and 0xFF)
(arr[off + 2].toInt() shl 16 and 0xff0000) or
(arr[off + 1].toInt() shl 8 and 0xff00) or
(arr[off].toInt() and 0xFF)
} // end of LEW
@Throws(Exception::class)
private fun loadXMLFromString(xml: String?): Document {
return DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.parse(InputSource(StringReader(xml)))
.newDocumentBuilder()
.parse(InputSource(StringReader(xml)))
}
@Throws(IOException::class)
@ -247,4 +247,4 @@ object APKExtractor {
return ""
}
}
}
}

View File

@ -1,4 +1,4 @@
package ir.armor.tachidesk.impl
package ir.armor.tachidesk.impl.util
/*
* Copyright (C) Contributors to the Suwayomi project
@ -13,6 +13,7 @@ import okhttp3.FormBody
import okhttp3.OkHttpClient
import java.net.URLEncoder
// TODO: finish MangaDex support
class MangaDexHelper(private val mangaDexSource: HttpSource) {
private fun clientBuilder(): OkHttpClient = clientBuilder(0)

View File

@ -8,8 +8,8 @@ package ir.armor.tachidesk.model.database
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import eu.kanade.tachiyomi.source.model.SManga
import ir.armor.tachidesk.impl.proxyThumbnailUrl
import ir.armor.tachidesk.model.dataclass.MangaDataClass
import ir.armor.tachidesk.impl.proxyThumbnailUrl
import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.ResultRow

View File

@ -18,7 +18,7 @@ import ir.armor.tachidesk.impl.getMangaList
import ir.armor.tachidesk.impl.getPageImage
import ir.armor.tachidesk.impl.getSource
import ir.armor.tachidesk.impl.getSourceList
import ir.armor.tachidesk.impl.getThumbnail
import ir.armor.tachidesk.impl.getMangaThumbnail
import ir.armor.tachidesk.impl.installExtension
import ir.armor.tachidesk.impl.removeCategory
import ir.armor.tachidesk.impl.removeMangaFromCategory
@ -143,7 +143,7 @@ fun javalinSetup() {
// manga thumbnail
app.get("api/v1/manga/:mangaId/thumbnail") { ctx ->
val mangaId = ctx.pathParam("mangaId").toInt()
val result = getThumbnail(mangaId)
val result = getMangaThumbnail(mangaId)
ctx.result(result.first)
ctx.header("content-type", result.second)