add kotlinter

This commit is contained in:
Aria Moradi 2021-01-22 12:34:03 +03:30
parent b854fdeadb
commit 9a61f58043
38 changed files with 262 additions and 290 deletions

View File

@ -5,6 +5,7 @@ plugins {
// id("org.jetbrains.kotlin.jvm") version "1.4.21" // id("org.jetbrains.kotlin.jvm") version "1.4.21"
application application
id("com.github.johnrengelman.shadow") version "6.1.0" id("com.github.johnrengelman.shadow") version "6.1.0"
id("org.jmailen.kotlinter") version "3.3.0"
} }
val TachideskVersion = "v0.0.2" val TachideskVersion = "v0.0.2"
@ -139,9 +140,16 @@ tasks {
tasks.withType<ShadowJar> { tasks.withType<ShadowJar> {
destinationDir = File("$rootDir/server/build") destinationDir = File("$rootDir/server/build")
dependsOn("lintKotlin")
} }
tasks.named("processResources") { tasks.named("processResources") {
dependsOn(":webUI:copyBuild") dependsOn(":webUI:copyBuild")
} }
tasks.named("run") {
dependsOn("formatKotlin", "lintKotlin")
}

View File

@ -2,9 +2,9 @@ package eu.kanade.tachiyomi
import android.app.Application import android.app.Application
import android.content.Context import android.content.Context
//import android.content.res.Configuration // import android.content.res.Configuration
//import android.support.multidex.MultiDex // import android.support.multidex.MultiDex
//import timber.log.Timber // import timber.log.Timber
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.InjektScope import uy.kohesive.injekt.api.InjektScope
import uy.kohesive.injekt.registry.default.DefaultRegistrar import uy.kohesive.injekt.registry.default.DefaultRegistrar

View File

@ -2,19 +2,22 @@ package eu.kanade.tachiyomi
import android.app.Application import android.app.Application
import com.google.gson.Gson import com.google.gson.Gson
//import eu.kanade.tachiyomi.data.cache.ChapterCache // import eu.kanade.tachiyomi.data.cache.ChapterCache
//import eu.kanade.tachiyomi.data.cache.CoverCache // import eu.kanade.tachiyomi.data.cache.CoverCache
//import eu.kanade.tachiyomi.data.database.DatabaseHelper // import eu.kanade.tachiyomi.data.database.DatabaseHelper
//import eu.kanade.tachiyomi.data.download.DownloadManager // import eu.kanade.tachiyomi.data.download.DownloadManager
//import eu.kanade.tachiyomi.data.preference.PreferencesHelper // import eu.kanade.tachiyomi.data.preference.PreferencesHelper
//import eu.kanade.tachiyomi.data.sync.LibrarySyncManager // import eu.kanade.tachiyomi.data.sync.LibrarySyncManager
//import eu.kanade.tachiyomi.data.track.TrackManager // import eu.kanade.tachiyomi.data.track.TrackManager
//import eu.kanade.tachiyomi.extension.ExtensionManager // import eu.kanade.tachiyomi.extension.ExtensionManager
import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.source.SourceManager
import rx.Observable import rx.Observable
import rx.schedulers.Schedulers import rx.schedulers.Schedulers
import uy.kohesive.injekt.api.* import uy.kohesive.injekt.api.InjektModule
import uy.kohesive.injekt.api.InjektRegistrar
import uy.kohesive.injekt.api.addSingleton
import uy.kohesive.injekt.api.addSingletonFactory
import uy.kohesive.injekt.api.get
class AppModule(val app: Application) : InjektModule { class AppModule(val app: Application) : InjektModule {
@ -56,11 +59,9 @@ class AppModule(val app: Application) : InjektModule {
} }
// rxAsync { get<DatabaseHelper>() } // rxAsync { get<DatabaseHelper>() }
} }
private fun rxAsync(block: () -> Unit) { private fun rxAsync(block: () -> Unit) {
Observable.fromCallable { block() }.subscribeOn(Schedulers.computation()).subscribe() Observable.fromCallable { block() }.subscribeOn(Schedulers.computation()).subscribe()
} }
} }

View File

@ -1,17 +1,17 @@
package eu.kanade.tachiyomi.extension.api package eu.kanade.tachiyomi.extension.api
//import android.content.Context // import android.content.Context
//import eu.kanade.tachiyomi.data.preference.PreferencesHelper // import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.extension.model.Extension import eu.kanade.tachiyomi.extension.model.Extension
import eu.kanade.tachiyomi.extension.util.ExtensionLoader import eu.kanade.tachiyomi.extension.util.ExtensionLoader
import ir.armor.tachidesk.database.dataclass.ExtensionDataClass import ir.armor.tachidesk.database.dataclass.ExtensionDataClass
//import kotlinx.coroutines.Dispatchers // import kotlinx.coroutines.Dispatchers
//import kotlinx.coroutines.withContext // import kotlinx.coroutines.withContext
import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.int import kotlinx.serialization.json.int
import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive import kotlinx.serialization.json.jsonPrimitive
//import uy.kohesive.injekt.injectLazy // import uy.kohesive.injekt.injectLazy
internal class ExtensionGithubApi { internal class ExtensionGithubApi {
@ -27,7 +27,7 @@ internal class ExtensionGithubApi {
// suspend fun checkForUpdates(): List<Extension.Installed> { // suspend fun checkForUpdates(): List<Extension.Installed> {
// val extensions = fin dExtensions() // val extensions = fin dExtensions()
// //
//// preferences.lastExtCheck().set(Date().time) // // preferences.lastExtCheck().set(Date().time)
// //
// val installedExtensions = ExtensionLoader.loadExtensions(context) // val installedExtensions = ExtensionLoader.loadExtensions(context)
// .filterIsInstance<LoadResult.Success>() // .filterIsInstance<LoadResult.Success>()
@ -49,23 +49,23 @@ internal class ExtensionGithubApi {
private fun parseResponse(json: JsonArray): List<Extension.Available> { private fun parseResponse(json: JsonArray): List<Extension.Available> {
return json return json
.filter { element -> .filter { element ->
val versionName = element.jsonObject["version"]!!.jsonPrimitive.content val versionName = element.jsonObject["version"]!!.jsonPrimitive.content
val libVersion = versionName.substringBeforeLast('.').toDouble() val libVersion = versionName.substringBeforeLast('.').toDouble()
libVersion >= ExtensionLoader.LIB_VERSION_MIN && libVersion <= ExtensionLoader.LIB_VERSION_MAX libVersion >= ExtensionLoader.LIB_VERSION_MIN && libVersion <= ExtensionLoader.LIB_VERSION_MAX
} }
.map { element -> .map { element ->
val name = element.jsonObject["name"]!!.jsonPrimitive.content.substringAfter("Tachiyomi: ") val name = element.jsonObject["name"]!!.jsonPrimitive.content.substringAfter("Tachiyomi: ")
val pkgName = element.jsonObject["pkg"]!!.jsonPrimitive.content val pkgName = element.jsonObject["pkg"]!!.jsonPrimitive.content
val apkName = element.jsonObject["apk"]!!.jsonPrimitive.content val apkName = element.jsonObject["apk"]!!.jsonPrimitive.content
val versionName = element.jsonObject["version"]!!.jsonPrimitive.content val versionName = element.jsonObject["version"]!!.jsonPrimitive.content
val versionCode = element.jsonObject["code"]!!.jsonPrimitive.int val versionCode = element.jsonObject["code"]!!.jsonPrimitive.int
val lang = element.jsonObject["lang"]!!.jsonPrimitive.content val lang = element.jsonObject["lang"]!!.jsonPrimitive.content
val nsfw = element.jsonObject["nsfw"]!!.jsonPrimitive.int == 1 val nsfw = element.jsonObject["nsfw"]!!.jsonPrimitive.int == 1
val icon = "$REPO_URL_PREFIX/icon/${apkName.replace(".apk", ".png")}" val icon = "$REPO_URL_PREFIX/icon/${apkName.replace(".apk", ".png")}"
Extension.Available(name, pkgName, versionName, versionCode, lang, nsfw, apkName, icon) Extension.Available(name, pkgName, versionName, versionCode, lang, nsfw, apkName, icon)
} }
} }
fun getApkUrl(extension: Extension.Available): String { fun getApkUrl(extension: Extension.Available): String {

View File

@ -9,7 +9,7 @@ import retrofit2.Retrofit
import retrofit2.http.GET import retrofit2.http.GET
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
//import uy.kohesive.injekt.injectLazy // import uy.kohesive.injekt.injectLazy
/** /**
* Used to get the extension repo listing from GitHub. * Used to get the extension repo listing from GitHub.

View File

@ -1,28 +1,22 @@
package eu.kanade.tachiyomi.extension.util package eu.kanade.tachiyomi.extension.util
//import android.annotation.SuppressLint // import android.annotation.SuppressLint
//import android.content.Context // import android.content.Context
//import android.content.pm.PackageInfo // import android.content.pm.PackageInfo
//import android.content.pm.PackageManager // import android.content.pm.PackageManager
//import dalvik.system.PathClassLoader // import dalvik.system.PathClassLoader
import eu.kanade.tachiyomi.annoations.Nsfw // import eu.kanade.tachiyomi.data.preference.PreferenceValues
//import eu.kanade.tachiyomi.data.preference.PreferenceValues // import eu.kanade.tachiyomi.data.preference.PreferencesHelper
//import eu.kanade.tachiyomi.data.preference.PreferencesHelper // import eu.kanade.tachiyomi.util.lang.Hash
import eu.kanade.tachiyomi.extension.model.Extension // import kotlinx.coroutines.async
import eu.kanade.tachiyomi.extension.model.LoadResult // import kotlinx.coroutines.runBlocking
import eu.kanade.tachiyomi.source.CatalogueSource // import timber.log.Timber
import eu.kanade.tachiyomi.source.Source // import uy.kohesive.injekt.injectLazy
import eu.kanade.tachiyomi.source.SourceFactory
//import eu.kanade.tachiyomi.util.lang.Hash
//import kotlinx.coroutines.async
//import kotlinx.coroutines.runBlocking
//import timber.log.Timber
//import uy.kohesive.injekt.injectLazy
/** /**
* Class that handles the loading of the extensions installed in the system. * Class that handles the loading of the extensions installed in the system.
*/ */
//@SuppressLint("PackageManagerGetSignatures") // @SuppressLint("PackageManagerGetSignatures")
internal object ExtensionLoader { internal object ExtensionLoader {
// private val preferences: PreferencesHelper by injectLazy() // private val preferences: PreferencesHelper by injectLazy()

View File

@ -1,30 +1,23 @@
package eu.kanade.tachiyomi.network package eu.kanade.tachiyomi.network
//import android.annotation.SuppressLint // import android.annotation.SuppressLint
//import android.content.Context // import android.content.Context
//import android.os.Build // import android.os.Build
//import android.os.Handler // import android.os.Handler
//import android.os.Looper // import android.os.Looper
//import android.webkit.WebSettings // import android.webkit.WebSettings
//import android.webkit.WebView // import android.webkit.WebView
//import android.widget.Toast // import android.widget.Toast
//import eu.kanade.tachiyomi.R // import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.source.online.HttpSource // import eu.kanade.tachiyomi.util.lang.launchUI
//import eu.kanade.tachiyomi.util.lang.launchUI // import eu.kanade.tachiyomi.util.system.WebViewClientCompat
//import eu.kanade.tachiyomi.util.system.WebViewClientCompat // import eu.kanade.tachiyomi.util.system.WebViewUtil
//import eu.kanade.tachiyomi.util.system.WebViewUtil // import eu.kanade.tachiyomi.util.system.isOutdated
//import eu.kanade.tachiyomi.util.system.isOutdated // import eu.kanade.tachiyomi.util.system.setDefaultSettings
//import eu.kanade.tachiyomi.util.system.setDefaultSettings // import eu.kanade.tachiyomi.util.system.toast
//import eu.kanade.tachiyomi.util.system.toast
import okhttp3.Cookie
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response import okhttp3.Response
//import uy.kohesive.injekt.injectLazy // import uy.kohesive.injekt.injectLazy
import java.io.IOException
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
class CloudflareInterceptor() : Interceptor { class CloudflareInterceptor() : Interceptor {
@ -77,7 +70,7 @@ class CloudflareInterceptor() : Interceptor {
// } // }
} }
// //
//// @SuppressLint("SetJavaScriptEnabled") // // @SuppressLint("SetJavaScriptEnabled")
// private fun resolveWithWebView(request: Request, oldCookie: Cookie?) { // private fun resolveWithWebView(request: Request, oldCookie: Cookie?) {
// // We need to lock this thread until the WebView finds the challenge solution url, because // // We need to lock this thread until the WebView finds the challenge solution url, because
// // OkHttp doesn't support asynchronous interceptors. // // OkHttp doesn't support asynchronous interceptors.

View File

@ -1,17 +1,14 @@
package eu.kanade.tachiyomi.network package eu.kanade.tachiyomi.network
//import android.content.Context // import android.content.Context
//import eu.kanade.tachiyomi.BuildConfig // import eu.kanade.tachiyomi.BuildConfig
//import eu.kanade.tachiyomi.data.preference.PreferencesHelper // import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import android.content.Context import android.content.Context
import okhttp3.Cache // import okhttp3.HttpUrl.Companion.toHttpUrl
//import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
//import okhttp3.dnsoverhttps.DnsOverHttps // import okhttp3.dnsoverhttps.DnsOverHttps
//import okhttp3.logging.HttpLoggingInterceptor // import okhttp3.logging.HttpLoggingInterceptor
//import uy.kohesive.injekt.injectLazy // import uy.kohesive.injekt.injectLazy
import java.io.File
import java.net.InetAddress
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class NetworkHelper(context: Context) { class NetworkHelper(context: Context) {

View File

@ -1,18 +1,14 @@
package eu.kanade.tachiyomi.network package eu.kanade.tachiyomi.network
//import kotlinx.coroutines.suspendCancellableCoroutine // import kotlinx.coroutines.suspendCancellableCoroutine
import okhttp3.Call import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import rx.Observable import rx.Observable
import rx.Producer import rx.Producer
import rx.Subscription import rx.Subscription
import java.io.IOException
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
fun Call.asObservable(): Observable<Response> { fun Call.asObservable(): Observable<Response> {
return Observable.unsafeCreate { subscriber -> return Observable.unsafeCreate { subscriber ->
@ -52,7 +48,7 @@ fun Call.asObservable(): Observable<Response> {
} }
// Based on https://github.com/gildor/kotlin-coroutines-okhttp // Based on https://github.com/gildor/kotlin-coroutines-okhttp
//suspend fun Call.await(assertSuccess: Boolean = false): Response { // suspend fun Call.await(assertSuccess: Boolean = false): Response {
// return suspendCancellableCoroutine { continuation -> // return suspendCancellableCoroutine { continuation ->
// enqueue( // enqueue(
// object : Callback { // object : Callback {
@ -81,7 +77,7 @@ fun Call.asObservable(): Observable<Response> {
// } // }
// } // }
// } // }
//} // }
fun Call.asObservableSuccess(): Observable<Response> { fun Call.asObservableSuccess(): Observable<Response> {
return asObservable().doOnNext { response -> return asObservable().doOnNext { response ->
@ -92,7 +88,7 @@ fun Call.asObservableSuccess(): Observable<Response> {
} }
} }
//fun OkHttpClient.newCallWithProgress(request: Request, listener: ProgressListener): Call { // fun OkHttpClient.newCallWithProgress(request: Request, listener: ProgressListener): Call {
// val progressClient = newBuilder() // val progressClient = newBuilder()
// .cache(null) // .cache(null)
// .addNetworkInterceptor { chain -> // .addNetworkInterceptor { chain ->
@ -104,7 +100,7 @@ fun Call.asObservableSuccess(): Observable<Response> {
// .build() // .build()
// //
// return progressClient.newCall(request) // return progressClient.newCall(request)
//} // }
fun OkHttpClient.newCallWithProgress(request: Request, listener: ProgressListener): Call { fun OkHttpClient.newCallWithProgress(request: Request, listener: ProgressListener): Call {
val progressClient = newBuilder() val progressClient = newBuilder()

View File

@ -1,6 +1,6 @@
package eu.kanade.tachiyomi.source package eu.kanade.tachiyomi.source
//import androidx.preference.PreferenceScreen // import androidx.preference.PreferenceScreen
interface ConfigurableSource : Source { interface ConfigurableSource : Source {

View File

@ -1,13 +1,13 @@
package eu.kanade.tachiyomi.source package eu.kanade.tachiyomi.source
//import android.graphics.drawable.Drawable // import android.graphics.drawable.Drawable
//import eu.kanade.tachiyomi.extension.ExtensionManager // import eu.kanade.tachiyomi.extension.ExtensionManager
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import rx.Observable import rx.Observable
//import uy.kohesive.injekt.Injekt // import uy.kohesive.injekt.Injekt
//import uy.kohesive.injekt.api.get // import uy.kohesive.injekt.api.get
/** /**
* A basic interface for creating a source. It could be an online source, a local source, etc... * A basic interface for creating a source. It could be an online source, a local source, etc...
@ -46,6 +46,6 @@ interface Source {
fun fetchPageList(chapter: SChapter): Observable<List<Page>> fun fetchPageList(chapter: SChapter): Observable<List<Page>>
} }
//fun Source.icon(): Drawable? = Injekt.get<ExtensionManager>().getAppIconForSource(this) // fun Source.icon(): Drawable? = Injekt.get<ExtensionManager>().getAppIconForSource(this)
//fun Source.getPreferenceKey(): String = "source_$id" // fun Source.getPreferenceKey(): String = "source_$id"

View File

@ -1,7 +1,7 @@
package eu.kanade.tachiyomi.source package eu.kanade.tachiyomi.source
//import android.content.Context // import android.content.Context
//import eu.kanade.tachiyomi.R // import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga

View File

@ -9,7 +9,7 @@ open class Page(
val url: String = "", val url: String = "",
var imageUrl: String? = null, var imageUrl: String? = null,
@Transient var uri: Uri? = null // Deprecated but can't be deleted due to extensions @Transient var uri: Uri? = null // Deprecated but can't be deleted due to extensions
): ProgressListener { ) : ProgressListener {
val number: Int val number: Int
get() = index + 1 get() = index + 1

View File

@ -12,7 +12,7 @@ interface SChapter : Serializable {
var chapter_number: Float var chapter_number: Float
var scanlator: String? var scanlator: String?
fun copyFrom(other: SChapter) { fun copyFrom(other: SChapter) {
name = other.name name = other.name

View File

@ -16,7 +16,7 @@ import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import rx.Observable import rx.Observable
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
//import uy.kohesive.injekt.injectLazy // import uy.kohesive.injekt.injectLazy
import java.net.URI import java.net.URI
import java.net.URISyntaxException import java.net.URISyntaxException
import java.security.MessageDigest import java.security.MessageDigest

View File

@ -3,6 +3,6 @@ package ir.armor.tachidesk
import net.harawata.appdirs.AppDirsFactory import net.harawata.appdirs.AppDirsFactory
object Config { object Config {
val dataRoot = AppDirsFactory.getInstance().getUserDataDir("Tachidesk",null, null) val dataRoot = AppDirsFactory.getInstance().getUserDataDir("Tachidesk", null, null)
val extensionsRoot = "$dataRoot/extensions" val extensionsRoot = "$dataRoot/extensions"
} }

View File

@ -2,7 +2,17 @@ package ir.armor.tachidesk
import eu.kanade.tachiyomi.App import eu.kanade.tachiyomi.App
import io.javalin.Javalin import io.javalin.Javalin
import ir.armor.tachidesk.util.* import ir.armor.tachidesk.util.applicationSetup
import ir.armor.tachidesk.util.getChapterList
import ir.armor.tachidesk.util.getExtensionList
import ir.armor.tachidesk.util.getManga
import ir.armor.tachidesk.util.getMangaList
import ir.armor.tachidesk.util.getPages
import ir.armor.tachidesk.util.getSourceList
import ir.armor.tachidesk.util.installAPK
import ir.armor.tachidesk.util.sourceFilters
import ir.armor.tachidesk.util.sourceGlobalSearch
import ir.armor.tachidesk.util.sourceSearch
import org.kodein.di.DI import org.kodein.di.DI
import org.kodein.di.conf.global import org.kodein.di.conf.global
import xyz.nulldev.androidcompat.AndroidCompat import xyz.nulldev.androidcompat.AndroidCompat
@ -28,26 +38,23 @@ class Main {
registerConfigModules() registerConfigModules()
//Load config API // Load config API
DI.global.addImport(ConfigKodeinModule().create()) DI.global.addImport(ConfigKodeinModule().create())
//Load Android compatibility dependencies // Load Android compatibility dependencies
AndroidCompatInitializer().init() AndroidCompatInitializer().init()
// start app // start app
androidCompat.startApp(App()) androidCompat.startApp(App())
val app = Javalin.create { config -> val app = Javalin.create { config ->
try { try {
this::class.java.classLoader.getResource("/react/index.html") this::class.java.classLoader.getResource("/react/index.html")
config.addStaticFiles("/react") config.addStaticFiles("/react")
config.addSinglePageRoot("/","/react/index.html") config.addSinglePageRoot("/", "/react/index.html")
} catch (e: RuntimeException) { } catch (e: RuntimeException) {
println("Warning: react build files are missing.") println("Warning: react build files are missing.")
} }
}.start(4567) }.start(4567)
app.before() { ctx -> app.before() { ctx ->
// allow the client which is running on another port // allow the client which is running on another port
ctx.header("Access-Control-Allow-Origin", "*") ctx.header("Access-Control-Allow-Origin", "*")
@ -57,12 +64,11 @@ class Main {
ctx.json(getExtensionList()) ctx.json(getExtensionList())
} }
app.get("/api/v1/extension/install/:apkName") { ctx -> app.get("/api/v1/extension/install/:apkName") { ctx ->
val apkName = ctx.pathParam("apkName") val apkName = ctx.pathParam("apkName")
println(apkName) println(apkName)
ctx.status( ctx.status(
installAPK(apkName) installAPK(apkName)
) )
} }
app.get("/api/v1/source/list") { ctx -> app.get("/api/v1/source/list") { ctx ->
@ -114,11 +120,6 @@ class Main {
val sourceId = ctx.pathParam("sourceId").toLong() val sourceId = ctx.pathParam("sourceId").toLong()
ctx.json(sourceFilters(sourceId)) ctx.json(sourceFilters(sourceId))
} }
} }
} }
} }

View File

@ -25,4 +25,4 @@ fun makeDataBaseTables() {
SchemaUtils.create(MangaTable) SchemaUtils.create(MangaTable)
SchemaUtils.create(ChapterTable) SchemaUtils.create(ChapterTable)
} }
} }

View File

@ -1,11 +1,11 @@
package ir.armor.tachidesk.database.dataclass package ir.armor.tachidesk.database.dataclass
data class ChapterDataClass( data class ChapterDataClass(
val id: Int, val id: Int,
val url: String, val url: String,
val name: String, val name: String,
val date_upload: Long, val date_upload: Long,
val chapter_number: Float, val chapter_number: Float,
val scanlator: String?, val scanlator: String?,
val mangaId: Int, val mangaId: Int,
) )

View File

@ -1,14 +1,14 @@
package ir.armor.tachidesk.database.dataclass package ir.armor.tachidesk.database.dataclass
data class ExtensionDataClass( data class ExtensionDataClass(
val name: String, val name: String,
val pkgName: String, val pkgName: String,
val versionName: String, val versionName: String,
val versionCode: Int, val versionCode: Int,
val lang: String, val lang: String,
val isNsfw: Boolean, val isNsfw: Boolean,
val apkName: String, val apkName: String,
val iconUrl: String, val iconUrl: String,
val installed: Boolean, val installed: Boolean,
val classFQName: String, val classFQName: String,
) )

View File

@ -3,18 +3,18 @@ package ir.armor.tachidesk.database.dataclass
import ir.armor.tachidesk.database.table.MangaStatus import ir.armor.tachidesk.database.table.MangaStatus
data class MangaDataClass( data class MangaDataClass(
val id: Int, val id: Int,
val sourceId: Long, val sourceId: Long,
val url: String, val url: String,
val title: String, val title: String,
val thumbnail_url: String? = null, val thumbnail_url: String? = null,
val initialized: Boolean = false, val initialized: Boolean = false,
val artist: String? = null, val artist: String? = null,
val author: String? = null, val author: String? = null,
val description: String? = null, val description: String? = null,
val genre: String? = null, val genre: String? = null,
val status: String = MangaStatus.UNKNOWN.name val status: String = MangaStatus.UNKNOWN.name
) )

View File

@ -1,6 +1,6 @@
package ir.armor.tachidesk.database.dataclass package ir.armor.tachidesk.database.dataclass
data class PageDataClass( data class PageDataClass(
val index: Int, val index: Int,
var imageUrl: String, var imageUrl: String,
) )

View File

@ -1,9 +1,9 @@
package ir.armor.tachidesk.database.dataclass package ir.armor.tachidesk.database.dataclass
data class SourceDataClass( data class SourceDataClass(
val id: String, val id: String,
val name: String, val name: String,
val lang: String, val lang: String,
val iconUrl: String, val iconUrl: String,
val supportsLatest: Boolean val supportsLatest: Boolean
) )

View File

@ -18,4 +18,4 @@ class ExtensionEntity(id: EntityID<Int>) : IntEntity(id) {
var iconUrl by ExtensionsTable.iconUrl var iconUrl by ExtensionsTable.iconUrl
var installed by ExtensionsTable.installed var installed by ExtensionsTable.installed
var classFQName by ExtensionsTable.classFQName var classFQName by ExtensionsTable.classFQName
} }

View File

@ -20,4 +20,4 @@ class MangaEntity(id: EntityID<Int>) : IntEntity(id) {
var thumbnail_url by MangaTable.thumbnail_url var thumbnail_url by MangaTable.thumbnail_url
var sourceReference by MangaEntity referencedOn MangaTable.sourceReference var sourceReference by MangaEntity referencedOn MangaTable.sourceReference
} }

View File

@ -1,7 +1,8 @@
package ir.armor.tachidesk.database.entity package ir.armor.tachidesk.database.entity
import ir.armor.tachidesk.database.table.SourceTable import ir.armor.tachidesk.database.table.SourceTable
import org.jetbrains.exposed.dao.* import org.jetbrains.exposed.dao.EntityClass
import org.jetbrains.exposed.dao.LongEntity
import org.jetbrains.exposed.dao.id.EntityID import org.jetbrains.exposed.dao.id.EntityID
class SourceEntity(id: EntityID<Long>) : LongEntity(id) { class SourceEntity(id: EntityID<Long>) : LongEntity(id) {
@ -13,4 +14,4 @@ class SourceEntity(id: EntityID<Long>) : LongEntity(id) {
var extension by ExtensionEntity referencedOn SourceTable.extension var extension by ExtensionEntity referencedOn SourceTable.extension
var partOfFactorySource by SourceTable.partOfFactorySource var partOfFactorySource by SourceTable.partOfFactorySource
var positionInFactorySource by SourceTable.positionInFactorySource var positionInFactorySource by SourceTable.positionInFactorySource
} }

View File

@ -1,6 +1,5 @@
package ir.armor.tachidesk.database.table package ir.armor.tachidesk.database.table
import eu.kanade.tachiyomi.source.model.SManga
import org.jetbrains.exposed.dao.id.IntIdTable import org.jetbrains.exposed.dao.id.IntIdTable
object ChapterTable : IntIdTable() { object ChapterTable : IntIdTable() {
@ -8,7 +7,7 @@ object ChapterTable : IntIdTable() {
val name = varchar("name", 512) val name = varchar("name", 512)
val date_upload = long("date_upload").default(0) val date_upload = long("date_upload").default(0)
val chapter_number = float("chapter_number").default(-1f) val chapter_number = float("chapter_number").default(-1f)
val scanlator = varchar("scanlator",128).nullable() val scanlator = varchar("scanlator", 128).nullable()
val manga = reference("manga", MangaTable) val manga = reference("manga", MangaTable)
} }

View File

@ -2,7 +2,6 @@ package ir.armor.tachidesk.database.table
import org.jetbrains.exposed.dao.id.IntIdTable import org.jetbrains.exposed.dao.id.IntIdTable
object ExtensionsTable : IntIdTable() { object ExtensionsTable : IntIdTable() {
val name = varchar("name", 128) val name = varchar("name", 128)
val pkgName = varchar("pkg_name", 128) val pkgName = varchar("pkg_name", 128)
@ -15,4 +14,4 @@ object ExtensionsTable : IntIdTable() {
val installed = bool("installed").default(false) val installed = bool("installed").default(false)
val classFQName = varchar("class_name", 256).default("") // fully qualified name val classFQName = varchar("class_name", 256).default("") // fully qualified name
} }

View File

@ -30,4 +30,4 @@ enum class MangaStatus(val status: Int) {
companion object { companion object {
fun valueOf(value: Int): MangaStatus = values().find { it.status == value } ?: UNKNOWN fun valueOf(value: Int): MangaStatus = values().find { it.status == value } ?: UNKNOWN
} }
} }

View File

@ -4,9 +4,9 @@ import org.jetbrains.exposed.dao.id.IdTable
object SourceTable : IdTable<Long>() { object SourceTable : IdTable<Long>() {
override val id = long("id").entityId() override val id = long("id").entityId()
val name= varchar("name", 128) val name = varchar("name", 128)
val lang = varchar("lang", 10) val lang = varchar("lang", 10)
val extension = reference("extension", ExtensionsTable) val extension = reference("extension", ExtensionsTable)
val partOfFactorySource = bool("part_of_factory_source").default(false) val partOfFactorySource = bool("part_of_factory_source").default(false)
val positionInFactorySource = integer("position_in_factory_source").nullable() val positionInFactorySource = integer("position_in_factory_source").nullable()
} }

View File

@ -41,7 +41,6 @@ fun installAPK(apkName: String): Int {
// download apk file // download apk file
downloadAPKFile(apkToDownload, apkFilePath) downloadAPKFile(apkToDownload, apkFilePath)
val className: String = APKExtractor.extract_dex_and_read_className(apkFilePath, dexFilePath) val className: String = APKExtractor.extract_dex_and_read_className(apkFilePath, dexFilePath)
println(className) println(className)
// dex -> jar // dex -> jar
@ -60,7 +59,7 @@ fun installAPK(apkName: String): Int {
return@transaction ExtensionsTable.select { ExtensionsTable.name eq extensionRecord.name }.first()[ExtensionsTable.id] return@transaction ExtensionsTable.select { ExtensionsTable.name eq extensionRecord.name }.first()[ExtensionsTable.id]
} }
if (instance is HttpSource) {// single source if (instance is HttpSource) { // single source
val httpSource = instance as HttpSource val httpSource = instance as HttpSource
transaction { transaction {
// SourceEntity.new { // SourceEntity.new {
@ -80,7 +79,6 @@ fun installAPK(apkName: String): Int {
// println(httpSource.name) // println(httpSource.name)
// println() // println()
} }
} else { // multi source } else { // multi source
val sourceFactory = instance as SourceFactory val sourceFactory = instance as SourceFactory
transaction { transaction {
@ -110,7 +108,6 @@ fun installAPK(apkName: String): Int {
it[classFQName] = className it[classFQName] = className
} }
} }
} }
return 201 // we downloaded successfully return 201 // we downloaded successfully
} else { } else {
@ -122,7 +119,7 @@ val networkHelper: NetworkHelper by injectLazy()
private fun downloadAPKFile(url: String, apkPath: String) { private fun downloadAPKFile(url: String, apkPath: String) {
val request = Request.Builder().url(url).build() val request = Request.Builder().url(url).build()
val response = networkHelper.client.newCall(request).execute() val response = networkHelper.client.newCall(request).execute()
val downloadedFile = File(apkPath) val downloadedFile = File(apkPath)
val sink = downloadedFile.sink().buffer() val sink = downloadedFile.sink().buffer()

View File

@ -6,23 +6,21 @@ import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import ir.armor.tachidesk.database.dataclass.ChapterDataClass import ir.armor.tachidesk.database.dataclass.ChapterDataClass
import ir.armor.tachidesk.database.dataclass.PageDataClass import ir.armor.tachidesk.database.dataclass.PageDataClass
import ir.armor.tachidesk.database.entity.MangaEntity
import ir.armor.tachidesk.database.table.ChapterTable import ir.armor.tachidesk.database.table.ChapterTable
import ir.armor.tachidesk.database.table.MangaTable import ir.armor.tachidesk.database.table.MangaTable
import org.jetbrains.exposed.sql.insertAndGetId import org.jetbrains.exposed.sql.insertAndGetId
import org.jetbrains.exposed.sql.select import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.transactions.transaction
fun getChapterList(mangaId: Int): List<ChapterDataClass> { fun getChapterList(mangaId: Int): List<ChapterDataClass> {
val mangaDetails = getManga(mangaId) val mangaDetails = getManga(mangaId)
val source = getHttpSource(mangaDetails.sourceId) val source = getHttpSource(mangaDetails.sourceId)
val chapterList = source.fetchChapterList( val chapterList = source.fetchChapterList(
SManga.create().apply { SManga.create().apply {
title = mangaDetails.title title = mangaDetails.title
url = mangaDetails.url url = mangaDetails.url
} }
).toBlocking().first() ).toBlocking().first()
return transaction { return transaction {
@ -41,16 +39,15 @@ fun getChapterList(mangaId: Int): List<ChapterDataClass> {
} }
} }
return@transaction chapterList.map { return@transaction chapterList.map {
ChapterDataClass( ChapterDataClass(
ChapterTable.select { ChapterTable.url eq it.url }.firstOrNull()!![ChapterTable.id].value, ChapterTable.select { ChapterTable.url eq it.url }.firstOrNull()!![ChapterTable.id].value,
it.url, it.url,
it.name, it.name,
it.date_upload, it.date_upload,
it.chapter_number, it.chapter_number,
it.scanlator, it.scanlator,
mangaId mangaId
) )
} }
} }
@ -64,24 +61,23 @@ fun getPages(chapterId: Int, mangaId: Int): List<PageDataClass> {
val source = getHttpSource(mangaEntry[MangaTable.sourceReference].value) val source = getHttpSource(mangaEntry[MangaTable.sourceReference].value)
val pagesList = source.fetchPageList( val pagesList = source.fetchPageList(
SChapter.create().apply { SChapter.create().apply {
url = chapterEntry[ChapterTable.url] url = chapterEntry[ChapterTable.url]
name = chapterEntry[ChapterTable.name] name = chapterEntry[ChapterTable.name]
} }
).toBlocking().first() ).toBlocking().first()
return@transaction pagesList.map { return@transaction pagesList.map {
PageDataClass( PageDataClass(
it.index, it.index,
getTrueImageUrl(it,source) getTrueImageUrl(it, source)
) )
} }
} }
} }
fun getTrueImageUrl(page: Page, source: HttpSource): String { fun getTrueImageUrl(page: Page, source: HttpSource): String {
return if ( page.imageUrl == null){ return if (page.imageUrl == null) {
source.fetchImageUrl(page).toBlocking().first()!! source.fetchImageUrl(page).toBlocking().first()!!
} else page.imageUrl!! } else page.imageUrl!!
} }

View File

@ -67,18 +67,17 @@ fun getExtensionList(offline: Boolean = false): List<ExtensionDataClass> {
return transaction { return transaction {
return@transaction ExtensionsTable.selectAll().map { return@transaction ExtensionsTable.selectAll().map {
ExtensionDataClass( ExtensionDataClass(
it[ExtensionsTable.name], it[ExtensionsTable.name],
it[ExtensionsTable.pkgName], it[ExtensionsTable.pkgName],
it[ExtensionsTable.versionName], it[ExtensionsTable.versionName],
it[ExtensionsTable.versionCode], it[ExtensionsTable.versionCode],
it[ExtensionsTable.lang], it[ExtensionsTable.lang],
it[ExtensionsTable.isNsfw], it[ExtensionsTable.isNsfw],
it[ExtensionsTable.apkName], it[ExtensionsTable.apkName],
it[ExtensionsTable.iconUrl], it[ExtensionsTable.iconUrl],
it[ExtensionsTable.installed], it[ExtensionsTable.installed],
it[ExtensionsTable.classFQName] it[ExtensionsTable.classFQName]
) )
} }
} }
} }

View File

@ -14,28 +14,28 @@ fun getManga(mangaId: Int): MangaDataClass {
return@transaction if (mangaEntry[MangaTable.initialized]) { return@transaction if (mangaEntry[MangaTable.initialized]) {
MangaDataClass( MangaDataClass(
mangaId, mangaId,
mangaEntry[MangaTable.sourceReference].value, mangaEntry[MangaTable.sourceReference].value,
mangaEntry[MangaTable.url], mangaEntry[MangaTable.url],
mangaEntry[MangaTable.title], mangaEntry[MangaTable.title],
mangaEntry[MangaTable.thumbnail_url], mangaEntry[MangaTable.thumbnail_url],
true, true,
mangaEntry[MangaTable.artist], mangaEntry[MangaTable.artist],
mangaEntry[MangaTable.author], mangaEntry[MangaTable.author],
mangaEntry[MangaTable.description], mangaEntry[MangaTable.description],
mangaEntry[MangaTable.genre], mangaEntry[MangaTable.genre],
MangaStatus.valueOf(mangaEntry[MangaTable.status]).name, MangaStatus.valueOf(mangaEntry[MangaTable.status]).name,
) )
} else { // initialize manga } else { // initialize manga
val source = getHttpSource(mangaEntry[MangaTable.sourceReference].value) val source = getHttpSource(mangaEntry[MangaTable.sourceReference].value)
val fetchedManga = source.fetchMangaDetails( val fetchedManga = source.fetchMangaDetails(
SManga.create().apply { SManga.create().apply {
url = mangaEntry[MangaTable.url] url = mangaEntry[MangaTable.url]
title = mangaEntry[MangaTable.title] title = mangaEntry[MangaTable.title]
} }
).toBlocking().first() ).toBlocking().first()
// update database // update database
@ -56,23 +56,21 @@ fun getManga(mangaId: Int): MangaDataClass {
mangaEntry = MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!! mangaEntry = MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!!
MangaDataClass( MangaDataClass(
mangaId, mangaId,
mangaEntry[MangaTable.sourceReference].value, mangaEntry[MangaTable.sourceReference].value,
mangaEntry[MangaTable.url],
mangaEntry[MangaTable.title],
mangaEntry[MangaTable.thumbnail_url],
mangaEntry[MangaTable.url], true,
mangaEntry[MangaTable.title],
mangaEntry[MangaTable.thumbnail_url],
true, mangaEntry[MangaTable.artist],
mangaEntry[MangaTable.author],
mangaEntry[MangaTable.artist], mangaEntry[MangaTable.description],
mangaEntry[MangaTable.author], mangaEntry[MangaTable.genre],
mangaEntry[MangaTable.description], MangaStatus.valueOf(mangaEntry[MangaTable.status]).name,
mangaEntry[MangaTable.genre],
MangaStatus.valueOf(mangaEntry[MangaTable.status]).name,
) )
} }
} }
} }

View File

@ -3,8 +3,6 @@ package ir.armor.tachidesk.util
import ir.armor.tachidesk.database.dataclass.MangaDataClass import ir.armor.tachidesk.database.dataclass.MangaDataClass
import ir.armor.tachidesk.database.table.MangaStatus import ir.armor.tachidesk.database.table.MangaStatus
import ir.armor.tachidesk.database.table.MangaTable import ir.armor.tachidesk.database.table.MangaTable
import ir.armor.tachidesk.database.table.SourceTable
import org.jetbrains.exposed.sql.insert
import org.jetbrains.exposed.sql.insertAndGetId import org.jetbrains.exposed.sql.insertAndGetId
import org.jetbrains.exposed.sql.select import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.transactions.transaction
@ -41,21 +39,21 @@ fun getMangaList(sourceId: Long, pageNum: Int = 1, popular: Boolean): List<Manga
} }
MangaDataClass( MangaDataClass(
mangaEntityId, mangaEntityId,
sourceId.toLong(), sourceId.toLong(),
manga.url, manga.url,
manga.title, manga.title,
manga.thumbnail_url, manga.thumbnail_url,
manga.initialized, manga.initialized,
manga.artist, manga.artist,
manga.author, manga.author,
manga.description, manga.description,
manga.genre, manga.genre,
MangaStatus.valueOf(manga.status).name, MangaStatus.valueOf(manga.status).name,
) )
} }
} }
} }

View File

@ -1,28 +1,24 @@
package ir.armor.tachidesk.util package ir.armor.tachidesk.util
import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList
fun sourceFilters(sourceId: Long) { fun sourceFilters(sourceId: Long) {
val source = getHttpSource(sourceId) val source = getHttpSource(sourceId)
//source.getFilterList().toItems() // source.getFilterList().toItems()
} }
fun sourceSearch(sourceId: Long, searchTerm: String) { fun sourceSearch(sourceId: Long, searchTerm: String) {
val source = getHttpSource(sourceId) val source = getHttpSource(sourceId)
//source.fetchSearchManga() // source.fetchSearchManga()
} }
fun sourceGlobalSearch(searchTerm: String) { fun sourceGlobalSearch(searchTerm: String) {
} }
data class FilterWrapper( data class FilterWrapper(
val type: String, val type: String,
val filter: Any val filter: Any
) )
//private fun FilterList.toItems(): List<FilterWrapper> { // private fun FilterList.toItems(): List<FilterWrapper> {
// return mapNotNull { filter -> // return mapNotNull { filter ->
// when (filter) { // when (filter) {
// is Filter.Header -> FilterWrapper("Header",filter) // is Filter.Header -> FilterWrapper("Header",filter)
@ -56,4 +52,4 @@ data class FilterWrapper(
// } // }
// } // }
// } // }
//} // }

View File

@ -13,7 +13,7 @@ import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.transactions.transaction
import java.net.URL import java.net.URL
import java.net.URLClassLoader import java.net.URLClassLoader
import java.util.* import java.util.Locale
private val sourceCache = mutableListOf<Pair<Long, HttpSource>>() private val sourceCache = mutableListOf<Pair<Long, HttpSource>>()
private val extensionCache = mutableListOf<Pair<String, Any>>() private val extensionCache = mutableListOf<Pair<String, Any>>()
@ -39,16 +39,16 @@ fun getHttpSource(sourceId: Long): HttpSource {
val cachedExtensionPair = extensionCache.firstOrNull { it.first == jarPath } val cachedExtensionPair = extensionCache.firstOrNull { it.first == jarPath }
var usedCached = false var usedCached = false
val instance = val instance =
if (cachedExtensionPair != null) { if (cachedExtensionPair != null) {
usedCached = true usedCached = true
println("Used cached Extension") println("Used cached Extension")
cachedExtensionPair.second cachedExtensionPair.second
} else { } else {
println("No Extension cache") println("No Extension cache")
val child = URLClassLoader(arrayOf<URL>(URL("file:$jarPath")), this::class.java.classLoader) val child = URLClassLoader(arrayOf<URL>(URL("file:$jarPath")), this::class.java.classLoader)
val classToLoad = Class.forName(className, true, child) val classToLoad = Class.forName(className, true, child)
classToLoad.newInstance() classToLoad.newInstance()
} }
if (sourceRecord.partOfFactorySource) { if (sourceRecord.partOfFactorySource) {
return@transaction if (usedCached) { return@transaction if (usedCached) {
(instance as List<HttpSource>)[sourceRecord.positionInFactorySource!!] (instance as List<HttpSource>)[sourceRecord.positionInFactorySource!!]
@ -71,12 +71,12 @@ fun getSourceList(): List<SourceDataClass> {
return transaction { return transaction {
return@transaction SourceTable.selectAll().map { return@transaction SourceTable.selectAll().map {
SourceDataClass( SourceDataClass(
it[SourceTable.id].value.toString(), it[SourceTable.id].value.toString(),
it[SourceTable.name], it[SourceTable.name],
Locale(it[SourceTable.lang]).getDisplayLanguage(Locale(it[SourceTable.lang])), Locale(it[SourceTable.lang]).getDisplayLanguage(Locale(it[SourceTable.lang])),
ExtensionsTable.select { ExtensionsTable.id eq it[SourceTable.extension] }.first()[ExtensionsTable.iconUrl], ExtensionsTable.select { ExtensionsTable.id eq it[SourceTable.extension] }.first()[ExtensionsTable.iconUrl],
getHttpSource(it[SourceTable.id].value).supportsLatest getHttpSource(it[SourceTable.id].value).supportsLatest
) )
} }
} }
} }

View File

@ -9,6 +9,5 @@ fun applicationSetup() {
File(Config.dataRoot).mkdirs() File(Config.dataRoot).mkdirs()
File(Config.extensionsRoot).mkdirs() File(Config.extensionsRoot).mkdirs()
makeDataBaseTables() makeDataBaseTables()
} }