let's not polute the namespace

This commit is contained in:
Aria Moradi
2021-03-30 21:04:06 +04:30
parent 2a3c78d43e
commit 90ae180b3e
13 changed files with 200 additions and 164 deletions
@@ -7,6 +7,7 @@ package ir.armor.tachidesk.impl
* 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/. */
import ir.armor.tachidesk.impl.CategoryManga.removeMangaFromCategory
import ir.armor.tachidesk.model.database.CategoryMangaTable
import ir.armor.tachidesk.model.database.CategoryTable
import ir.armor.tachidesk.model.database.toDataClass
@@ -19,29 +20,29 @@ 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()
if (CategoryTable.select { CategoryTable.name eq name }.firstOrNull() == null)
CategoryTable.insert {
it[CategoryTable.name] = name
it[CategoryTable.order] = count.toInt() + 1
}
}
}
fun updateCategory(categoryId: Int, name: String?, isLanding: Boolean?) {
transaction {
CategoryTable.update({ CategoryTable.id eq categoryId }) {
if (name != null) it[CategoryTable.name] = name
if (isLanding != null) it[CategoryTable.isLanding] = isLanding
object Category {
/**
* The new category will be placed at the end of the list
*/
fun createCategory(name: String) {
transaction {
val count = CategoryTable.selectAll().count()
if (CategoryTable.select { CategoryTable.name eq name }.firstOrNull() == null)
CategoryTable.insert {
it[CategoryTable.name] = name
it[CategoryTable.order] = count.toInt() + 1
}
}
}
fun updateCategory(categoryId: Int, name: String?, isLanding: Boolean?) {
transaction {
CategoryTable.update({ CategoryTable.id eq categoryId }) {
if (name != null) it[CategoryTable.name] = name
if (isLanding != null) it[CategoryTable.isLanding] = isLanding
}
}
}
}
/**
* Move the category from position `from` to `to`
@@ -74,3 +75,4 @@ fun getCategoryList(): List<CategoryDataClass> {
}
}
}
}
@@ -21,6 +21,7 @@ import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.update
object CategoryManga {
fun addMangaToCategory(mangaId: Int, categoryId: Int) {
transaction {
if (CategoryMangaTable.select { (CategoryMangaTable.category eq categoryId) and (CategoryMangaTable.manga eq mangaId) }.firstOrNull() == null) {
@@ -69,3 +70,4 @@ fun getMangaCategories(mangaId: Int): List<CategoryDataClass> {
}
}
}
}
@@ -9,6 +9,8 @@ package ir.armor.tachidesk.impl
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import ir.armor.tachidesk.impl.Manga.getManga
import ir.armor.tachidesk.impl.Source.getHttpSource
import ir.armor.tachidesk.model.database.ChapterTable
import ir.armor.tachidesk.model.database.MangaTable
import ir.armor.tachidesk.model.database.PageTable
@@ -21,121 +23,123 @@ import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.update
fun getChapterList(mangaId: Int): List<ChapterDataClass> {
val mangaDetails = getManga(mangaId)
val source = getHttpSource(mangaDetails.sourceId.toLong())
object Chapter {
fun getChapterList(mangaId: Int): List<ChapterDataClass> {
val mangaDetails = getManga(mangaId)
val source = getHttpSource(mangaDetails.sourceId.toLong())
val chapterList = source.fetchChapterList(
SManga.create().apply {
title = mangaDetails.title
url = mangaDetails.url
}
).toBlocking().first()
val chapterCount = chapterList.count()
return transaction {
chapterList.reversed().forEachIndexed { index, fetchedChapter ->
val chapterEntry = ChapterTable.select { ChapterTable.url eq fetchedChapter.url }.firstOrNull()
if (chapterEntry == null) {
ChapterTable.insertAndGetId {
it[url] = fetchedChapter.url
it[name] = fetchedChapter.name
it[date_upload] = fetchedChapter.date_upload
it[chapter_number] = fetchedChapter.chapter_number
it[scanlator] = fetchedChapter.scanlator
it[chapterIndex] = index + 1
it[manga] = mangaId
val chapterList = source.fetchChapterList(
SManga.create().apply {
title = mangaDetails.title
url = mangaDetails.url
}
} else {
ChapterTable.update({ ChapterTable.url eq fetchedChapter.url }) {
it[name] = fetchedChapter.name
it[date_upload] = fetchedChapter.date_upload
it[chapter_number] = fetchedChapter.chapter_number
it[scanlator] = fetchedChapter.scanlator
it[chapterIndex] = index + 1
it[manga] = mangaId
}
}
}
// clear any orphaned chapters
val dbChapterCount = transaction { ChapterTable.selectAll().count() }
if (dbChapterCount > chapterCount) { // we got some clean up due
// TODO: delete orphan chapters
}
chapterList.mapIndexed { index, it ->
ChapterDataClass(
ChapterTable.select { ChapterTable.url eq it.url }.firstOrNull()!![ChapterTable.id].value,
it.url,
it.name,
it.date_upload,
it.chapter_number,
it.scanlator,
mangaId,
chapterCount - index,
chapterCount
)
}
}
}
fun getChapter(chapterIndex: Int, mangaId: Int): ChapterDataClass {
return transaction {
val chapterEntry = ChapterTable.select {
ChapterTable.chapterIndex eq chapterIndex and (ChapterTable.manga eq mangaId)
}.firstOrNull()!!
val mangaEntry = MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!!
val source = getHttpSource(mangaEntry[MangaTable.sourceReference])
val pageList = source.fetchPageList(
SChapter.create().apply {
url = chapterEntry[ChapterTable.url]
name = chapterEntry[ChapterTable.name]
}
).toBlocking().first()
val chapterId = chapterEntry[ChapterTable.id].value
val chapterCount = transaction { ChapterTable.selectAll().count() }
val chapterCount = chapterList.count()
val chapter = ChapterDataClass(
chapterId,
chapterEntry[ChapterTable.url],
chapterEntry[ChapterTable.name],
chapterEntry[ChapterTable.date_upload],
chapterEntry[ChapterTable.chapter_number],
chapterEntry[ChapterTable.scanlator],
mangaId,
chapterEntry[ChapterTable.chapterIndex],
chapterCount.toInt(),
return transaction {
chapterList.reversed().forEachIndexed { index, fetchedChapter ->
val chapterEntry = ChapterTable.select { ChapterTable.url eq fetchedChapter.url }.firstOrNull()
if (chapterEntry == null) {
ChapterTable.insertAndGetId {
it[url] = fetchedChapter.url
it[name] = fetchedChapter.name
it[date_upload] = fetchedChapter.date_upload
it[chapter_number] = fetchedChapter.chapter_number
it[scanlator] = fetchedChapter.scanlator
pageList.count()
)
pageList.forEach { page ->
val pageEntry = transaction { PageTable.select { (PageTable.chapter eq chapterId) and (PageTable.index eq page.index) }.firstOrNull() }
if (pageEntry == null) {
transaction {
PageTable.insert {
it[index] = page.index
it[url] = page.url
it[imageUrl] = page.imageUrl
it[this.chapter] = chapterId
it[chapterIndex] = index + 1
it[manga] = mangaId
}
}
} else {
transaction {
PageTable.update({ (PageTable.chapter eq chapterId) and (PageTable.index eq page.index) }) {
it[url] = page.url
it[imageUrl] = page.imageUrl
} else {
ChapterTable.update({ ChapterTable.url eq fetchedChapter.url }) {
it[name] = fetchedChapter.name
it[date_upload] = fetchedChapter.date_upload
it[chapter_number] = fetchedChapter.chapter_number
it[scanlator] = fetchedChapter.scanlator
it[chapterIndex] = index + 1
it[manga] = mangaId
}
}
}
}
chapter
// clear any orphaned chapters
val dbChapterCount = transaction { ChapterTable.selectAll().count() }
if (dbChapterCount > chapterCount) { // we got some clean up due
// TODO: delete orphan chapters
}
chapterList.mapIndexed { index, it ->
ChapterDataClass(
ChapterTable.select { ChapterTable.url eq it.url }.firstOrNull()!![ChapterTable.id].value,
it.url,
it.name,
it.date_upload,
it.chapter_number,
it.scanlator,
mangaId,
chapterCount - index,
chapterCount
)
}
}
}
}
fun getChapter(chapterIndex: Int, mangaId: Int): ChapterDataClass {
return transaction {
val chapterEntry = ChapterTable.select {
ChapterTable.chapterIndex eq chapterIndex and (ChapterTable.manga eq mangaId)
}.firstOrNull()!!
val mangaEntry = MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!!
val source = getHttpSource(mangaEntry[MangaTable.sourceReference])
val pageList = source.fetchPageList(
SChapter.create().apply {
url = chapterEntry[ChapterTable.url]
name = chapterEntry[ChapterTable.name]
}
).toBlocking().first()
val chapterId = chapterEntry[ChapterTable.id].value
val chapterCount = transaction { ChapterTable.selectAll().count() }
val chapter = ChapterDataClass(
chapterId,
chapterEntry[ChapterTable.url],
chapterEntry[ChapterTable.name],
chapterEntry[ChapterTable.date_upload],
chapterEntry[ChapterTable.chapter_number],
chapterEntry[ChapterTable.scanlator],
mangaId,
chapterEntry[ChapterTable.chapterIndex],
chapterCount.toInt(),
pageList.count()
)
pageList.forEach { page ->
val pageEntry = transaction { PageTable.select { (PageTable.chapter eq chapterId) and (PageTable.index eq page.index) }.firstOrNull() }
if (pageEntry == null) {
transaction {
PageTable.insert {
it[index] = page.index
it[url] = page.url
it[imageUrl] = page.imageUrl
it[this.chapter] = chapterId
}
}
} else {
transaction {
PageTable.update({ (PageTable.chapter eq chapterId) and (PageTable.index eq page.index) }) {
it[url] = page.url
it[imageUrl] = page.imageUrl
}
}
}
}
chapter
}
}
}
@@ -15,6 +15,7 @@ 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.ExtensionsList.extensionTableAsDataClass
import ir.armor.tachidesk.model.database.ExtensionTable
import ir.armor.tachidesk.model.database.SourceTable
import ir.armor.tachidesk.impl.util.APKExtractor
@@ -37,6 +38,7 @@ import java.net.URLClassLoader
import java.nio.file.Files
import java.nio.file.Path
object Extension {
private val logger = KotlinLogging.logger {}
/**
@@ -205,7 +207,7 @@ fun uninstallExtension(pkgName: String) {
}
fun updateExtension(pkgName: String): Int {
val targetExtension = ExtensionListData.updateMap.remove(pkgName)!!
val targetExtension = ExtensionsList.updateMap.remove(pkgName)!!
uninstallExtension(pkgName)
transaction {
ExtensionTable.update({ ExtensionTable.pkgName eq pkgName }) {
@@ -239,3 +241,4 @@ fun getExtensionIcon(apkName: String): Pair<InputStream, String> {
fun getExtensionIconUrl(apkName: String): String {
return "/api/v1/extension/icon/$apkName"
}
}
@@ -9,6 +9,7 @@ package ir.armor.tachidesk.impl
import eu.kanade.tachiyomi.extension.api.ExtensionGithubApi
import eu.kanade.tachiyomi.extension.model.Extension
import ir.armor.tachidesk.impl.Extension.getExtensionIconUrl
import ir.armor.tachidesk.model.database.ExtensionTable
import ir.armor.tachidesk.model.dataclass.ExtensionDataClass
import kotlinx.coroutines.runBlocking
@@ -21,21 +22,22 @@ import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.update
import java.util.concurrent.ConcurrentHashMap
object ExtensionsList {
private val logger = KotlinLogging.logger {}
object ExtensionListData {
var lastUpdateCheck: Long = 0
var updateMap = ConcurrentHashMap<String, Extension.Available>()
}
// const val ExtensionUpdateDelayTime = 60 * 1000 // 60,000 milliseconds = 60 seconds
const val ExtensionUpdateDelayTime = 0
fun getExtensionList(): List<ExtensionDataClass> {
// update if {ExtensionUpdateDelayTime} seconds has passed or requested offline and database is empty
if (ExtensionListData.lastUpdateCheck + ExtensionUpdateDelayTime < System.currentTimeMillis()) {
if (lastUpdateCheck + ExtensionUpdateDelayTime < System.currentTimeMillis()) {
logger.debug("Getting extensions list from the internet")
ExtensionListData.lastUpdateCheck = System.currentTimeMillis()
lastUpdateCheck = System.currentTimeMillis()
runBlocking {
val foundExtensions = ExtensionGithubApi.findExtensions()
updateExtensionDatabase(foundExtensions)
@@ -76,7 +78,7 @@ private fun updateExtensionDatabase(foundExtensions: List<Extension.Available>)
ExtensionTable.update({ ExtensionTable.pkgName eq foundExtension.pkgName }) {
it[hasUpdate] = true
}
ExtensionListData.updateMap.putIfAbsent(foundExtension.pkgName, foundExtension)
updateMap.putIfAbsent(foundExtension.pkgName, foundExtension)
} else if (foundExtension.versionCode < extensionRecord[ExtensionTable.versionCode]) {
// some how the user installed an invalid version
ExtensionTable.update({ ExtensionTable.pkgName eq foundExtension.pkgName }) {
@@ -131,3 +133,4 @@ private fun updateExtensionDatabase(foundExtensions: List<Extension.Available>)
}
}
}
}
@@ -7,6 +7,7 @@ package ir.armor.tachidesk.impl
* 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/. */
import ir.armor.tachidesk.impl.Manga.getManga
import ir.armor.tachidesk.model.database.CategoryMangaTable
import ir.armor.tachidesk.model.database.MangaTable
import ir.armor.tachidesk.model.database.toDataClass
@@ -17,6 +18,7 @@ import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.update
object Library {
// 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`
@@ -51,3 +53,4 @@ fun getLibraryMangas(): List<MangaDataClass> {
}
}
}
}
@@ -9,6 +9,9 @@ package ir.armor.tachidesk.impl
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.SManga
import ir.armor.tachidesk.impl.MangaList.proxyThumbnailUrl
import ir.armor.tachidesk.impl.Source.getHttpSource
import ir.armor.tachidesk.impl.Source.getSource
import ir.armor.tachidesk.model.database.MangaStatus
import ir.armor.tachidesk.model.database.MangaTable
import ir.armor.tachidesk.model.dataclass.MangaDataClass
@@ -18,6 +21,7 @@ import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.update
import java.io.InputStream
object Manga {
fun getManga(mangaId: Int, proxyThumbnail: Boolean = true): MangaDataClass {
var mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!! }
@@ -106,3 +110,4 @@ fun getMangaThumbnail(mangaId: Int): Pair<InputStream, String> {
).execute()
}
}
}
@@ -8,6 +8,7 @@ package ir.armor.tachidesk.impl
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import eu.kanade.tachiyomi.source.model.MangasPage
import ir.armor.tachidesk.impl.Source.getHttpSource
import ir.armor.tachidesk.model.database.MangaStatus
import ir.armor.tachidesk.model.database.MangaTable
import ir.armor.tachidesk.model.dataclass.MangaDataClass
@@ -16,6 +17,7 @@ import org.jetbrains.exposed.sql.insertAndGetId
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
object MangaList {
fun proxyThumbnailUrl(mangaId: Int): String {
return "/api/v1/manga/$mangaId/thumbnail"
}
@@ -96,3 +98,4 @@ fun MangasPage.processEntries(sourceId: Long): PagedMangaListDataClass {
mangasPage.hasNextPage
)
}
}
@@ -9,6 +9,7 @@ package ir.armor.tachidesk.impl
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.online.HttpSource
import ir.armor.tachidesk.impl.Source.getHttpSource
import ir.armor.tachidesk.model.database.ChapterTable
import ir.armor.tachidesk.model.database.MangaTable
import ir.armor.tachidesk.model.database.PageTable
@@ -21,6 +22,7 @@ import org.jetbrains.exposed.sql.update
import java.io.File
import java.io.InputStream
object Page{
/**
* 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.
@@ -88,3 +90,4 @@ fun getChapterDir(mangaId: Int, chapterId: Int): String {
File(mangaDir).mkdirs()
return mangaDir
}
}
@@ -7,8 +7,11 @@ package ir.armor.tachidesk.impl
* 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/. */
import ir.armor.tachidesk.impl.MangaList.processEntries
import ir.armor.tachidesk.impl.Source.getHttpSource
import ir.armor.tachidesk.model.dataclass.PagedMangaListDataClass
object Search {
// TODO
fun sourceFilters(sourceId: Long) {
val source = getHttpSource(sourceId)
@@ -68,3 +71,4 @@ data class FilterWrapper(
// }
// }
// }
}
@@ -9,6 +9,8 @@ package ir.armor.tachidesk.impl
import eu.kanade.tachiyomi.source.SourceFactory
import eu.kanade.tachiyomi.source.online.HttpSource
import ir.armor.tachidesk.impl.Extension.getExtensionIconUrl
import ir.armor.tachidesk.impl.Extension.loadExtensionInstance
import ir.armor.tachidesk.model.database.ExtensionTable
import ir.armor.tachidesk.model.database.SourceTable
import ir.armor.tachidesk.model.dataclass.SourceDataClass
@@ -19,6 +21,7 @@ import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import java.util.concurrent.ConcurrentHashMap
object Source {
private val logger = KotlinLogging.logger {}
private val sourceCache = ConcurrentHashMap<Long, HttpSource>()
@@ -82,3 +85,4 @@ fun getSource(sourceId: Long): SourceDataClass {
)
}
}
}
@@ -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.MangaList.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
@@ -2,34 +2,34 @@ package ir.armor.tachidesk.server
import io.javalin.Javalin
import ir.armor.tachidesk.Main
import ir.armor.tachidesk.impl.addMangaToCategory
import ir.armor.tachidesk.impl.addMangaToLibrary
import ir.armor.tachidesk.impl.createCategory
import ir.armor.tachidesk.impl.getCategoryList
import ir.armor.tachidesk.impl.getCategoryMangaList
import ir.armor.tachidesk.impl.getChapter
import ir.armor.tachidesk.impl.getChapterList
import ir.armor.tachidesk.impl.getExtensionIcon
import ir.armor.tachidesk.impl.getExtensionList
import ir.armor.tachidesk.impl.getLibraryMangas
import ir.armor.tachidesk.impl.getManga
import ir.armor.tachidesk.impl.getMangaCategories
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.getMangaThumbnail
import ir.armor.tachidesk.impl.installExtension
import ir.armor.tachidesk.impl.removeCategory
import ir.armor.tachidesk.impl.removeMangaFromCategory
import ir.armor.tachidesk.impl.removeMangaFromLibrary
import ir.armor.tachidesk.impl.reorderCategory
import ir.armor.tachidesk.impl.sourceFilters
import ir.armor.tachidesk.impl.sourceGlobalSearch
import ir.armor.tachidesk.impl.sourceSearch
import ir.armor.tachidesk.impl.uninstallExtension
import ir.armor.tachidesk.impl.updateCategory
import ir.armor.tachidesk.impl.updateExtension
import ir.armor.tachidesk.impl.Category.createCategory
import ir.armor.tachidesk.impl.Category.getCategoryList
import ir.armor.tachidesk.impl.Category.removeCategory
import ir.armor.tachidesk.impl.Category.reorderCategory
import ir.armor.tachidesk.impl.Category.updateCategory
import ir.armor.tachidesk.impl.CategoryManga.addMangaToCategory
import ir.armor.tachidesk.impl.CategoryManga.getCategoryMangaList
import ir.armor.tachidesk.impl.CategoryManga.getMangaCategories
import ir.armor.tachidesk.impl.CategoryManga.removeMangaFromCategory
import ir.armor.tachidesk.impl.Chapter.getChapter
import ir.armor.tachidesk.impl.Chapter.getChapterList
import ir.armor.tachidesk.impl.Extension.getExtensionIcon
import ir.armor.tachidesk.impl.Extension.installExtension
import ir.armor.tachidesk.impl.Extension.uninstallExtension
import ir.armor.tachidesk.impl.Extension.updateExtension
import ir.armor.tachidesk.impl.ExtensionsList.getExtensionList
import ir.armor.tachidesk.impl.Library.addMangaToLibrary
import ir.armor.tachidesk.impl.Library.getLibraryMangas
import ir.armor.tachidesk.impl.Library.removeMangaFromLibrary
import ir.armor.tachidesk.impl.Manga.getManga
import ir.armor.tachidesk.impl.Manga.getMangaThumbnail
import ir.armor.tachidesk.impl.MangaList.getMangaList
import ir.armor.tachidesk.impl.Page.getPageImage
import ir.armor.tachidesk.impl.Search.sourceFilters
import ir.armor.tachidesk.impl.Search.sourceGlobalSearch
import ir.armor.tachidesk.impl.Search.sourceSearch
import ir.armor.tachidesk.impl.Source.getSource
import ir.armor.tachidesk.impl.Source.getSourceList
import ir.armor.tachidesk.server.util.openInBrowser
import mu.KotlinLogging
import java.io.IOException
@@ -81,7 +81,7 @@ fun javalinSetup() {
val pkgName = ctx.pathParam("pkgName")
ctx.status(
installExtension(pkgName)
installExtension(pkgName)
)
}
@@ -89,7 +89,7 @@ fun javalinSetup() {
val pkgName = ctx.pathParam("pkgName")
ctx.status(
updateExtension(pkgName)
updateExtension(pkgName)
)
}