mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-12-23 18:11:53 +01:00
Turned on kt lint
This commit is contained in:
parent
cc28ff7a77
commit
da786bbc40
@ -8,7 +8,7 @@ plugins {
|
||||
kotlin("android")
|
||||
kotlin("android.extensions")
|
||||
kotlin("kapt")
|
||||
//id("org.jmailen.kotlinter") version "2.3.1"
|
||||
id("org.jmailen.kotlinter") version "2.3.1"
|
||||
id("com.github.zellius.shortcut-helper")
|
||||
id("com.google.gms.google-services") apply false
|
||||
}
|
||||
@ -114,9 +114,9 @@ dependencies {
|
||||
|
||||
implementation("com.google.firebase:firebase-core:17.2.3")
|
||||
|
||||
val lifecycle_version = "2.1.0"
|
||||
implementation("androidx.lifecycle:lifecycle-extensions:$lifecycle_version")
|
||||
implementation("androidx.lifecycle:lifecycle-common-java8:$lifecycle_version")
|
||||
val lifecycleVersion = "2.1.0"
|
||||
implementation("androidx.lifecycle:lifecycle-extensions:$lifecycleVersion")
|
||||
implementation("androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion")
|
||||
|
||||
// ReactiveX
|
||||
implementation("io.reactivex:rxandroid:1.2.1")
|
||||
@ -126,15 +126,15 @@ dependencies {
|
||||
implementation("com.github.pwittchen:reactivenetwork:0.13.0")
|
||||
|
||||
// Network client
|
||||
val okhttp_version = "4.3.1"
|
||||
implementation("com.squareup.okhttp3:okhttp:$okhttp_version")
|
||||
implementation("com.squareup.okhttp3:logging-interceptor:$okhttp_version")
|
||||
val okhttpVersion = "4.3.1"
|
||||
implementation("com.squareup.okhttp3:okhttp:$okhttpVersion")
|
||||
implementation("com.squareup.okhttp3:logging-interceptor:$okhttpVersion")
|
||||
implementation("com.squareup.okio:okio:2.4.3")
|
||||
|
||||
// REST
|
||||
val retrofit_version = "2.7.1"
|
||||
implementation("com.squareup.retrofit2:retrofit:$retrofit_version")
|
||||
implementation("com.squareup.retrofit2:converter-gson:$retrofit_version")
|
||||
val retrofitVersion = "2.7.1"
|
||||
implementation("com.squareup.retrofit2:retrofit:$retrofitVersion")
|
||||
implementation("com.squareup.retrofit2:converter-gson:$retrofitVersion")
|
||||
|
||||
// JSON
|
||||
implementation("com.google.code.gson:gson:2.8.6")
|
||||
@ -164,18 +164,18 @@ dependencies {
|
||||
implementation("io.requery:sqlite-android:3.31.0")
|
||||
|
||||
// Model View Presenter
|
||||
val nucleus_version = "3.0.0"
|
||||
implementation("info.android15.nucleus:nucleus:$nucleus_version")
|
||||
implementation("info.android15.nucleus:nucleus-support-v7:$nucleus_version")
|
||||
val nucleusVersion = "3.0.0"
|
||||
implementation("info.android15.nucleus:nucleus:$nucleusVersion")
|
||||
implementation("info.android15.nucleus:nucleus-support-v7:$nucleusVersion")
|
||||
|
||||
// Dependency injection
|
||||
implementation("com.github.inorichi.injekt:injekt-core:65b0440")
|
||||
|
||||
// Image library
|
||||
val glide_version = "4.11.0"
|
||||
implementation("com.github.bumptech.glide:glide:$glide_version")
|
||||
implementation("com.github.bumptech.glide:okhttp3-integration:$glide_version")
|
||||
kapt("com.github.bumptech.glide:compiler:$glide_version")
|
||||
val glideVersion = "4.11.0"
|
||||
implementation("com.github.bumptech.glide:glide:$glideVersion")
|
||||
implementation("com.github.bumptech.glide:okhttp3-integration:$glideVersion")
|
||||
kapt("com.github.bumptech.glide:compiler:$glideVersion")
|
||||
|
||||
// Transformations
|
||||
implementation("jp.wasabeef:glide-transformations:4.1.0")
|
||||
@ -208,28 +208,28 @@ dependencies {
|
||||
implementation("com.github.inorichi:conductor-support-preference:a32c357")
|
||||
|
||||
// RxBindings
|
||||
val rxbindings_version = "1.0.1"
|
||||
implementation("com.jakewharton.rxbinding:rxbinding-kotlin:$rxbindings_version")
|
||||
implementation("com.jakewharton.rxbinding:rxbinding-appcompat-v7-kotlin:$rxbindings_version")
|
||||
implementation("com.jakewharton.rxbinding:rxbinding-support-v4-kotlin:$rxbindings_version")
|
||||
implementation("com.jakewharton.rxbinding:rxbinding-recyclerview-v7-kotlin:$rxbindings_version")
|
||||
val rxbindingsVersion = "1.0.1"
|
||||
implementation("com.jakewharton.rxbinding:rxbinding-kotlin:$rxbindingsVersion")
|
||||
implementation("com.jakewharton.rxbinding:rxbinding-appcompat-v7-kotlin:$rxbindingsVersion")
|
||||
implementation("com.jakewharton.rxbinding:rxbinding-support-v4-kotlin:$rxbindingsVersion")
|
||||
implementation("com.jakewharton.rxbinding:rxbinding-recyclerview-v7-kotlin:$rxbindingsVersion")
|
||||
|
||||
// Tests
|
||||
testImplementation("junit:junit:4.13")
|
||||
testImplementation("org.assertj:assertj-core:1.7.1")
|
||||
testImplementation("org.assertj:assertj-core:3.12.2")
|
||||
testImplementation("org.mockito:mockito-core:1.10.19")
|
||||
|
||||
val robolectric_version = "3.1.4"
|
||||
testImplementation("org.robolectric:robolectric:$robolectric_version")
|
||||
testImplementation("org.robolectric:shadows-multidex:$robolectric_version")
|
||||
testImplementation("org.robolectric:shadows-play-services:$robolectric_version")
|
||||
val robolectricVersion = "3.1.4"
|
||||
testImplementation("org.robolectric:robolectric:$robolectricVersion")
|
||||
testImplementation("org.robolectric:shadows-multidex:$robolectricVersion")
|
||||
testImplementation("org.robolectric:shadows-play-services:$robolectricVersion")
|
||||
|
||||
|
||||
implementation(kotlin("stdlib", org.jetbrains.kotlin.config.KotlinCompilerVersion.VERSION))
|
||||
|
||||
val coroutines_version = "1.3.3"
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version")
|
||||
val coroutinesVersion = "1.3.3"
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion")
|
||||
|
||||
//Crash reports
|
||||
val acraVersion = "4.9.2"
|
||||
@ -239,13 +239,13 @@ dependencies {
|
||||
implementation("info.debatty:java-string-similarity:1.2.1")
|
||||
}
|
||||
|
||||
/*tasks.preBuild {
|
||||
tasks.preBuild {
|
||||
dependsOn(tasks.lintKotlin)
|
||||
}
|
||||
tasks.lintKotlin {
|
||||
dependsOn(tasks.formatKotlin)
|
||||
}*/
|
||||
}
|
||||
|
||||
if (getGradle().getStartParameter().getTaskRequests().toString().contains("Standard")) {
|
||||
if (gradle.startParameter.taskRequests.toString().contains("Standard")) {
|
||||
apply(mapOf("plugin" to "com.google.gms.google-services"))
|
||||
}
|
@ -52,7 +52,7 @@ open class App : Application(), LifecycleObserver {
|
||||
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
|
||||
fun onAppBackgrounded() {
|
||||
//App in background
|
||||
// App in background
|
||||
val preferences: PreferencesHelper by injectLazy()
|
||||
if (preferences.lockAfter().getOrDefault() >= 0) {
|
||||
SecureActivityDelegate.locked = true
|
||||
@ -92,5 +92,4 @@ open class App : Application(), LifecycleObserver {
|
||||
protected open fun setupNotificationChannels() {
|
||||
Notifications.createChannels(this)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,7 +13,11 @@ import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
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 {
|
||||
|
||||
@ -52,7 +56,5 @@ class AppModule(val app: Application) : InjektModule {
|
||||
GlobalScope.launch { get<DatabaseHelper>() }
|
||||
|
||||
GlobalScope.launch { get<DownloadManager>() }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -67,5 +67,4 @@ object Migrations {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package eu.kanade.tachiyomi.data.backup
|
||||
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
|
||||
|
||||
|
||||
object BackupConst {
|
||||
|
||||
const val INTENT_FILTER = "SettingsBackupFragment"
|
||||
@ -18,5 +17,5 @@ object BackupConst {
|
||||
const val EXTRA_TIME = "$ID.$INTENT_FILTER.EXTRA_TIME"
|
||||
const val EXTRA_ERROR_FILE_PATH = "$ID.$INTENT_FILTER.EXTRA_ERROR_FILE_PATH"
|
||||
const val EXTRA_ERROR_FILE = "$ID.$INTENT_FILTER.EXTRA_ERROR_FILE"
|
||||
const val EXTRA_MINI_ERROR= "$ID.$INTENT_FILTER.EXTRA_MINI_ERROR"
|
||||
}
|
||||
const val EXTRA_MINI_ERROR = "$ID.$INTENT_FILTER.EXTRA_MINI_ERROR"
|
||||
}
|
||||
|
@ -5,8 +5,8 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import com.google.gson.JsonArray
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
|
||||
/**
|
||||
* [IntentService] used to backup [Manga] information to [JsonArray]
|
||||
@ -45,7 +45,6 @@ class BackupCreateService : IntentService(NAME) {
|
||||
}
|
||||
context.startService(intent)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private val backupManager by lazy { BackupManager(this) }
|
||||
@ -60,5 +59,4 @@ class BackupCreateService : IntentService(NAME) {
|
||||
if (uri != null)
|
||||
backupManager.createBackup(uri, flags, false)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,9 +6,9 @@ import com.evernote.android.job.JobManager
|
||||
import com.evernote.android.job.JobRequest
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import java.util.concurrent.TimeUnit
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class BackupCreatorJob : Job() {
|
||||
|
||||
|
@ -3,8 +3,15 @@ package eu.kanade.tachiyomi.data.backup
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import com.github.salomonbrys.kotson.*
|
||||
import com.google.gson.*
|
||||
import com.github.salomonbrys.kotson.fromJson
|
||||
import com.github.salomonbrys.kotson.registerTypeAdapter
|
||||
import com.github.salomonbrys.kotson.registerTypeHierarchyAdapter
|
||||
import com.github.salomonbrys.kotson.set
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import com.hippo.unifile.UniFile
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CATEGORY
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CATEGORY_MASK
|
||||
@ -22,22 +29,34 @@ import eu.kanade.tachiyomi.data.backup.models.Backup.HISTORY
|
||||
import eu.kanade.tachiyomi.data.backup.models.Backup.MANGA
|
||||
import eu.kanade.tachiyomi.data.backup.models.Backup.TRACK
|
||||
import eu.kanade.tachiyomi.data.backup.models.DHistory
|
||||
import eu.kanade.tachiyomi.data.backup.serializer.*
|
||||
import eu.kanade.tachiyomi.data.backup.serializer.CategoryTypeAdapter
|
||||
import eu.kanade.tachiyomi.data.backup.serializer.ChapterTypeAdapter
|
||||
import eu.kanade.tachiyomi.data.backup.serializer.HistoryTypeAdapter
|
||||
import eu.kanade.tachiyomi.data.backup.serializer.MangaTypeAdapter
|
||||
import eu.kanade.tachiyomi.data.backup.serializer.TrackTypeAdapter
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.*
|
||||
import eu.kanade.tachiyomi.data.database.models.CategoryImpl
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
|
||||
import eu.kanade.tachiyomi.data.database.models.History
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.database.models.TrackImpl
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||
import eu.kanade.tachiyomi.util.system.sendLocalBroadcast
|
||||
import kotlin.math.max
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import rx.Observable
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import kotlin.math.max
|
||||
|
||||
class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
|
||||
|
||||
|
@ -38,23 +38,22 @@ import eu.kanade.tachiyomi.util.lang.chop
|
||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||
import eu.kanade.tachiyomi.util.system.isServiceRunning
|
||||
import eu.kanade.tachiyomi.util.system.notificationManager
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* Restores backup from json file
|
||||
*/
|
||||
class BackupRestoreService : Service() {
|
||||
|
||||
|
||||
/**
|
||||
* Wake lock that will be held until the service is destroyed.
|
||||
*/
|
||||
@ -87,7 +86,6 @@ class BackupRestoreService : Service() {
|
||||
*/
|
||||
private val trackingErrors = mutableListOf<String>()
|
||||
|
||||
|
||||
/**
|
||||
* List containing missing sources
|
||||
*/
|
||||
@ -113,7 +111,6 @@ class BackupRestoreService : Service() {
|
||||
*/
|
||||
internal val trackManager: TrackManager by injectLazy()
|
||||
|
||||
|
||||
/**
|
||||
* Method called when the service is created. It injects dependencies and acquire the wake lock.
|
||||
*/
|
||||
@ -216,7 +213,6 @@ class BackupRestoreService : Service() {
|
||||
showResultNotification(logFile.parent, logFile.name)
|
||||
}
|
||||
|
||||
|
||||
/**Restore categories if they were backed up
|
||||
*
|
||||
*/
|
||||
@ -246,8 +242,7 @@ class BackupRestoreService : Service() {
|
||||
if (job?.isCancelled == false) {
|
||||
showProgressNotification(restoreProgress, totalAmount, manga.title)
|
||||
restoreProgress += 1
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
throw java.lang.Exception("Job was cancelled")
|
||||
}
|
||||
val dbManga = backupManager.getMangaFromDatabase(manga)
|
||||
@ -262,7 +257,7 @@ class BackupRestoreService : Service() {
|
||||
}
|
||||
|
||||
if (!dbMangaExists || !backupManager.restoreChaptersForManga(manga, chapters)) {
|
||||
//manga gets chapters added
|
||||
// manga gets chapters added
|
||||
backupManager.restoreChapterFetch(source, manga, chapters)
|
||||
}
|
||||
// Restore categories
|
||||
@ -280,8 +275,7 @@ class BackupRestoreService : Service() {
|
||||
val cause = e.cause
|
||||
if (cause is SourceNotFoundException) {
|
||||
sourcesMissing.add(cause.id)
|
||||
}
|
||||
else if (e.message?.contains("licensed", true) == true) {
|
||||
} else if (e.message?.contains("licensed", true) == true) {
|
||||
lincensedManga++
|
||||
}
|
||||
errors.add("${manga.title} - ${cause?.message ?: e.message}")
|
||||
@ -303,7 +297,7 @@ class BackupRestoreService : Service() {
|
||||
try {
|
||||
service.refresh(track)
|
||||
db.insertTrack(track).executeAsBlocking()
|
||||
}catch (e : Exception){
|
||||
} catch (e: Exception) {
|
||||
errors.add("${manga.title} - ${e.message}")
|
||||
}
|
||||
} else {
|
||||
@ -357,7 +351,6 @@ class BackupRestoreService : Service() {
|
||||
NotificationReceiver.cancelRestorePendingBroadcast(this)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shows the notification containing the currently updating manga and the progress.
|
||||
*
|
||||
@ -473,4 +466,4 @@ class BackupRestoreService : Service() {
|
||||
context.stopService(Intent(context, BackupRestoreService::class.java))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
package eu.kanade.tachiyomi.data.backup.models
|
||||
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* Json values
|
||||
@ -20,4 +21,4 @@ object Backup {
|
||||
val date = SimpleDateFormat("yyyy-MM-dd_HH-mm", Locale.getDefault()).format(Date())
|
||||
return "tachiyomi_$date.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
package eu.kanade.tachiyomi.data.backup.models
|
||||
|
||||
data class DHistory(val url: String,val lastRead: Long)
|
||||
data class DHistory(val url: String, val lastRead: Long)
|
||||
|
@ -28,4 +28,4 @@ object CategoryTypeAdapter {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,4 +29,4 @@ object HistoryTypeAdapter {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,4 +35,4 @@ object MangaTypeAdapter {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package eu.kanade.tachiyomi.data.backup.serializer
|
||||
|
||||
import android.telecom.DisconnectCause.REMOTE
|
||||
import com.github.salomonbrys.kotson.typeAdapter
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.stream.JsonToken
|
||||
|
@ -9,14 +9,13 @@ import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||
import eu.kanade.tachiyomi.util.storage.saveTo
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import okhttp3.Response
|
||||
import okio.Okio
|
||||
import okio.buffer
|
||||
import okio.sink
|
||||
import rx.Observable
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* Class used to create chapter cache
|
||||
@ -136,7 +135,6 @@ class ChapterCache(private val context: Context) {
|
||||
diskCache.flush()
|
||||
editor.commit()
|
||||
editor.abortUnlessCommitted()
|
||||
|
||||
} catch (e: Exception) {
|
||||
// Ignore.
|
||||
} finally {
|
||||
@ -202,4 +200,3 @@ class ChapterCache(private val context: Context) {
|
||||
return "${chapter.manga_id}${chapter.url}"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,8 +20,8 @@ class CoverCache(private val context: Context) {
|
||||
/**
|
||||
* Cache directory used for cache management.
|
||||
*/
|
||||
private val cacheDir = context.getExternalFilesDir("covers") ?:
|
||||
File(context.filesDir, "covers").also { it.mkdirs() }
|
||||
private val cacheDir = context.getExternalFilesDir("covers")
|
||||
?: File(context.filesDir, "covers").also { it.mkdirs() }
|
||||
|
||||
/**
|
||||
* Returns the cover from cache.
|
||||
@ -37,7 +37,7 @@ class CoverCache(private val context: Context) {
|
||||
* Copy the given stream to this cache.
|
||||
*
|
||||
* @param thumbnailUrl url of the thumbnail.
|
||||
* @param inputStream the stream to copy.
|
||||
* @param inputStream the stream to copy.
|
||||
* @throws IOException if there's any error.
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
|
@ -29,8 +29,8 @@ import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory
|
||||
/**
|
||||
* This class provides operations to manage the database through its interfaces.
|
||||
*/
|
||||
open class DatabaseHelper(context: Context)
|
||||
: MangaQueries, ChapterQueries, TrackQueries, CategoryQueries, MangaCategoryQueries,
|
||||
open class DatabaseHelper(context: Context) :
|
||||
MangaQueries, ChapterQueries, TrackQueries, CategoryQueries, MangaCategoryQueries,
|
||||
HistoryQueries, SearchMetadataQueries {
|
||||
|
||||
private val configuration = SupportSQLiteOpenHelper.Configuration.builder(context)
|
||||
@ -52,5 +52,4 @@ open class DatabaseHelper(context: Context)
|
||||
inline fun inTransaction(block: () -> Unit) = db.inTransaction(block)
|
||||
|
||||
fun lowLevel() = db.lowLevel()
|
||||
|
||||
}
|
||||
|
@ -22,4 +22,3 @@ inline fun <T> StorIOSQLite.inTransactionReturn(block: () -> T): T {
|
||||
lowLevel().endTransaction()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,10 +2,12 @@ package eu.kanade.tachiyomi.data.database
|
||||
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import androidx.sqlite.db.SupportSQLiteOpenHelper
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.database.sqlite.SQLiteOpenHelper
|
||||
import eu.kanade.tachiyomi.data.database.tables.*
|
||||
import eu.kanade.tachiyomi.data.database.tables.CategoryTable
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable
|
||||
import eu.kanade.tachiyomi.data.database.tables.HistoryTable
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
||||
import eu.kanade.tachiyomi.data.database.tables.TrackTable
|
||||
|
||||
class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) {
|
||||
|
||||
@ -81,5 +83,4 @@ class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) {
|
||||
override fun onConfigure(db: SupportSQLiteDatabase) {
|
||||
db.setForeignKeyConstraintsEnabled(true)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,5 +5,4 @@ import com.pushtorefresh.storio.sqlite.impl.DefaultStorIOSQLite
|
||||
interface DbProvider {
|
||||
|
||||
val db: DefaultStorIOSQLite
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,6 @@ class CategoryPutResolver : DefaultPutResolver<Category>() {
|
||||
val orderString = obj.mangaOrder.joinToString("/")
|
||||
put(COL_MANGA_ORDER, orderString)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,4 +88,3 @@ class ChapterDeleteResolver : DefaultDeleteResolver<Chapter>() {
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
package eu.kanade.tachiyomi.data.database.mappers
|
||||
|
||||
|
||||
import android.content.ContentValues
|
||||
import android.database.Cursor
|
||||
import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping
|
||||
@ -63,4 +62,4 @@ class SearchMetadataDeleteResolver : DefaultDeleteResolver<SearchMetadata>() {
|
||||
.where("$COL_MANGA_ID = ?")
|
||||
.whereArgs(obj.mangaId)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,6 @@ class TrackPutResolver : DefaultPutResolver<Track>() {
|
||||
put(COL_STATUS, obj.status)
|
||||
put(COL_TRACKING_URL, obj.tracking_url)
|
||||
put(COL_SCORE, obj.score)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,18 +15,18 @@ interface Category : Serializable {
|
||||
|
||||
var flags: Int
|
||||
|
||||
var mangaOrder:List<Long>
|
||||
var mangaOrder: List<Long>
|
||||
|
||||
var mangaSort:Char?
|
||||
var mangaSort: Char?
|
||||
|
||||
var isFirst:Boolean?
|
||||
var isLast:Boolean?
|
||||
var isFirst: Boolean?
|
||||
var isLast: Boolean?
|
||||
|
||||
val nameLower: String
|
||||
get() = name.toLowerCase()
|
||||
|
||||
fun isAscending(): Boolean {
|
||||
return ((mangaSort?.minus('a') ?: 0) % 2) != 1
|
||||
return ((mangaSort?.minus('a') ?: 0) % 2) != 1
|
||||
}
|
||||
|
||||
fun sortingMode(): Int? = when (mangaSort) {
|
||||
@ -42,9 +42,9 @@ interface Category : Serializable {
|
||||
fun sortRes(): Int = when (mangaSort) {
|
||||
ALPHA_ASC, ALPHA_DSC -> R.string.title
|
||||
UPDATED_ASC, UPDATED_DSC -> R.string.action_sort_latest_chapter
|
||||
UNREAD_ASC, UNREAD_DSC -> R.string.action_filter_unread
|
||||
LAST_READ_ASC, LAST_READ_DSC -> R.string.action_sort_last_read
|
||||
TOTAL_ASC, TOTAL_DSC -> R.string.action_sort_total
|
||||
UNREAD_ASC, UNREAD_DSC -> R.string.action_filter_unread
|
||||
LAST_READ_ASC, LAST_READ_DSC -> R.string.action_sort_last_read
|
||||
TOTAL_ASC, TOTAL_DSC -> R.string.action_sort_total
|
||||
else -> R.string.action_sort_drag_and_drop
|
||||
}
|
||||
|
||||
@ -111,5 +111,4 @@ interface Category : Serializable {
|
||||
isLast = true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -30,5 +30,4 @@ class CategoryImpl : Category {
|
||||
override fun hashCode(): Int {
|
||||
return name.hashCode()
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -39,5 +39,4 @@ class ChapterImpl : Chapter {
|
||||
override fun hashCode(): Int {
|
||||
return url.hashCode()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ interface History : Serializable {
|
||||
* @param chapter chapter object
|
||||
* @return history object
|
||||
*/
|
||||
fun create(chapter: Chapter): History = HistoryImpl().apply {
|
||||
fun create(chapter: Chapter): History = HistoryImpl().apply {
|
||||
this.chapter_id = chapter.id!!
|
||||
}
|
||||
}
|
||||
|
@ -5,5 +5,4 @@ class LibraryManga : MangaImpl() {
|
||||
var unread: Int = 0
|
||||
|
||||
var category: Int = 0
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,9 @@ package eu.kanade.tachiyomi.data.database.models
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||
import java.util.Locale
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.Locale
|
||||
|
||||
interface Manga : SManga {
|
||||
|
||||
@ -82,7 +82,7 @@ interface Manga : SManga {
|
||||
tag.startsWith("chinese") || tag == "manhua" ||
|
||||
tag.startsWith("english") || tag == "comic"
|
||||
} == true || isComicSource(sourceName) ||
|
||||
sourceName.contains("manhua", true) )
|
||||
sourceName.contains("manhua", true))
|
||||
ReaderActivity.LEFT_TO_RIGHT
|
||||
else 0
|
||||
}
|
||||
@ -168,5 +168,4 @@ interface Manga : SManga {
|
||||
this.source = source
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -17,5 +17,4 @@ class MangaCategory {
|
||||
return mc
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,6 +5,6 @@ package eu.kanade.tachiyomi.data.database.models
|
||||
*
|
||||
* @param manga object containing manga
|
||||
* @param chapter object containing chater
|
||||
* @param history object containing history
|
||||
* @param history object containing history
|
||||
*/
|
||||
data class MangaChapterHistory(val manga: Manga, val chapter: Chapter, val history: History)
|
||||
|
@ -3,8 +3,8 @@ package eu.kanade.tachiyomi.data.database.models
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.download.DownloadProvider
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import kotlin.collections.set
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
open class MangaImpl : Manga {
|
||||
|
||||
@ -47,9 +47,9 @@ open class MangaImpl : Manga {
|
||||
title = if (currentTitle() != originalTitle()) {
|
||||
val customTitle = currentTitle()
|
||||
val trueTitle = other.title
|
||||
"${customTitle}${SManga.splitter}${trueTitle}"
|
||||
"${customTitle}${SManga.splitter}$trueTitle"
|
||||
} else other.title
|
||||
val db:DownloadManager by injectLazy()
|
||||
val db: DownloadManager by injectLazy()
|
||||
val provider = DownloadProvider(db.context)
|
||||
provider.renameMangaFolder(oldTitle, title, source)
|
||||
}
|
||||
@ -63,7 +63,6 @@ open class MangaImpl : Manga {
|
||||
val manga = other as Manga
|
||||
|
||||
return url == manga.url
|
||||
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
@ -71,7 +70,7 @@ open class MangaImpl : Manga {
|
||||
}
|
||||
|
||||
companion object {
|
||||
private var lastCoverFetch:HashMap<Long, Long> = hashMapOf()
|
||||
private var lastCoverFetch: HashMap<Long, Long> = hashMapOf()
|
||||
|
||||
fun setLastCoverFetch(id: Long, time: Long) {
|
||||
lastCoverFetch[id] = time
|
||||
@ -79,5 +78,4 @@ open class MangaImpl : Manga {
|
||||
|
||||
fun getLastCoverFetch(id: Long) = lastCoverFetch[id] ?: 0
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,4 +18,4 @@ data class SearchMetadata(
|
||||
) {
|
||||
// Transient information attached to this piece of metadata, useful for caching
|
||||
var transientCache: Map<String, Any>? = null
|
||||
}
|
||||
}
|
||||
|
@ -37,5 +37,4 @@ interface Track : Serializable {
|
||||
sync_id = serviceId
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -41,5 +41,4 @@ class TrackImpl : Track {
|
||||
result = 31 * result + media_id
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -32,5 +32,4 @@ interface CategoryQueries : DbProvider {
|
||||
fun deleteCategory(category: Category) = db.delete().`object`(category).prepare()
|
||||
|
||||
fun deleteCategories(categories: List<Category>) = db.delete().objects(categories).prepare()
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import eu.kanade.tachiyomi.data.database.resolvers.ChapterProgressPutResolver
|
||||
import eu.kanade.tachiyomi.data.database.resolvers.ChapterSourceOrderPutResolver
|
||||
import eu.kanade.tachiyomi.data.database.resolvers.MangaChapterGetResolver
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable
|
||||
import java.util.*
|
||||
import java.util.Date
|
||||
|
||||
interface ChapterQueries : DbProvider {
|
||||
|
||||
@ -88,5 +88,4 @@ interface ChapterQueries : DbProvider {
|
||||
.objects(chapters)
|
||||
.withPutResolver(ChapterSourceOrderPutResolver())
|
||||
.prepare()
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
|
||||
import eu.kanade.tachiyomi.data.database.resolvers.HistoryLastReadPutResolver
|
||||
import eu.kanade.tachiyomi.data.database.resolvers.MangaChapterHistoryGetResolver
|
||||
import eu.kanade.tachiyomi.data.database.tables.HistoryTable
|
||||
import java.util.*
|
||||
import java.util.Date
|
||||
|
||||
interface HistoryQueries : DbProvider {
|
||||
|
||||
|
@ -28,5 +28,4 @@ interface MangaCategoryQueries : DbProvider {
|
||||
insertMangasCategories(mangasCategories).executeAsBlocking()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -145,5 +145,5 @@ interface MangaQueries : DbProvider {
|
||||
.prepare()
|
||||
|
||||
fun getTotalChapterManga() = db.get().listOfObjects(Manga::class.java)
|
||||
.withQuery(RawQuery.builder().query(getTotalChapterMangaQuery()).observesTables(MangaTable.TABLE).build()).prepare();
|
||||
.withQuery(RawQuery.builder().query(getTotalChapterMangaQuery()).observesTables(MangaTable.TABLE).build()).prepare()
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ fun getRecentMangasQuery(offset: Int = 0, search: String = "") = """
|
||||
ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = max_last_read.${Chapter.COL_MANGA_ID}
|
||||
WHERE ${History.TABLE}.${History.COL_LAST_READ} > ?
|
||||
AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID}
|
||||
AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%${search}%'
|
||||
AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%$search%'
|
||||
ORDER BY max_last_read.${History.COL_LAST_READ} DESC
|
||||
LIMIT 25 OFFSET $offset
|
||||
"""
|
||||
@ -109,7 +109,7 @@ fun getRecentMangasLimitQuery(limit: Int = 25, search: String = "") = """
|
||||
ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = max_last_read.${Chapter.COL_MANGA_ID}
|
||||
WHERE ${History.TABLE}.${History.COL_LAST_READ} > ?
|
||||
AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID}
|
||||
AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%${search}%'
|
||||
AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%$search%'
|
||||
ORDER BY max_last_read.${History.COL_LAST_READ} DESC
|
||||
LIMIT $limit
|
||||
"""
|
||||
@ -142,7 +142,7 @@ fun getLastReadMangaQuery() = """
|
||||
ORDER BY max DESC
|
||||
"""
|
||||
|
||||
fun getTotalChapterMangaQuery()= """
|
||||
fun getTotalChapterMangaQuery() = """
|
||||
SELECT ${Manga.TABLE}.*
|
||||
FROM ${Manga.TABLE}
|
||||
JOIN ${Chapter.TABLE}
|
||||
@ -159,4 +159,4 @@ fun getCategoriesForMangaQuery() = """
|
||||
JOIN ${MangaCategory.TABLE} ON ${Category.TABLE}.${Category.COL_ID} =
|
||||
${MangaCategory.TABLE}.${MangaCategory.COL_CATEGORY_ID}
|
||||
WHERE ${MangaCategory.COL_MANGA_ID} = ?
|
||||
"""
|
||||
"""
|
||||
|
@ -1,6 +1,5 @@
|
||||
package eu.kanade.tachiyomi.data.database.queries
|
||||
|
||||
|
||||
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
|
||||
import com.pushtorefresh.storio.sqlite.queries.Query
|
||||
import eu.kanade.tachiyomi.data.database.DbProvider
|
||||
@ -42,4 +41,4 @@ interface SearchMetadataQueries : DbProvider {
|
||||
.table(SearchMetadataTable.TABLE)
|
||||
.build())
|
||||
.prepare()
|
||||
}
|
||||
}
|
||||
|
@ -30,5 +30,4 @@ interface TrackQueries : DbProvider {
|
||||
.whereArgs(manga.id, sync.id)
|
||||
.build())
|
||||
.prepare()
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,4 @@ class ChapterBackupPutResolver : PutResolver<Chapter>() {
|
||||
put(ChapterTable.COL_BOOKMARK, chapter.bookmark)
|
||||
put(ChapterTable.COL_LAST_PAGE_READ, chapter.last_page_read)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,4 @@ class ChapterProgressPutResolver : PutResolver<Chapter>() {
|
||||
put(ChapterTable.COL_LAST_PAGE_READ, chapter.last_page_read)
|
||||
put(ChapterTable.COL_PAGES_LEFT, chapter.pages_left)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -28,5 +28,4 @@ class ChapterSourceOrderPutResolver : PutResolver<Chapter>() {
|
||||
fun mapToContentValues(chapter: Chapter) = ContentValues(1).apply {
|
||||
put(ChapterTable.COL_SOURCE_ORDER, chapter.source_order)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -60,5 +60,4 @@ class HistoryLastReadPutResolver : HistoryPutResolver() {
|
||||
fun mapToUpdateContentValues(history: History) = ContentValues(1).apply {
|
||||
put(HistoryTable.COL_LAST_READ, history.last_read)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,5 +21,4 @@ class LibraryMangaGetResolver : DefaultGetResolver<LibraryManga>(), BaseMangaGet
|
||||
|
||||
return manga
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,5 +24,4 @@ class MangaChapterGetResolver : DefaultGetResolver<MangaChapter>() {
|
||||
|
||||
return MangaChapter(manga, chapter)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,6 +28,4 @@ class MangaFavoritePutResolver : PutResolver<Manga>() {
|
||||
fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
|
||||
put(MangaTable.COL_FAVORITE, manga.favorite)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,4 @@ class MangaFlagsPutResolver : PutResolver<Manga>() {
|
||||
fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
|
||||
put(MangaTable.COL_CHAPTER_FLAGS, manga.chapter_flags)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,6 @@ import com.pushtorefresh.storio.sqlite.operations.put.PutResolver
|
||||
import com.pushtorefresh.storio.sqlite.operations.put.PutResult
|
||||
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
|
||||
import eu.kanade.tachiyomi.data.database.inTransactionReturn
|
||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
||||
|
||||
@ -29,5 +28,4 @@ class MangaHideTitlePutResolver : PutResolver<Manga>() {
|
||||
fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
|
||||
put(MangaTable.COL_HIDE_TITLE, manga.hide_title)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import eu.kanade.tachiyomi.data.database.inTransactionReturn
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
||||
|
||||
class MangaInfoPutResolver(val reset:Boolean = false): PutResolver<Manga>() {
|
||||
class MangaInfoPutResolver(val reset: Boolean = false) : PutResolver<Manga>() {
|
||||
|
||||
override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
|
||||
val updateQuery = mapToUpdateQuery(manga)
|
||||
@ -40,6 +40,4 @@ class MangaInfoPutResolver(val reset:Boolean = false): PutResolver<Manga>() {
|
||||
put(MangaTable.COL_ARTIST, manga.originalArtist())
|
||||
put(MangaTable.COL_DESCRIPTION, manga.originalDesc())
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,4 @@ class MangaLastUpdatedPutResolver : PutResolver<Manga>() {
|
||||
fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
|
||||
put(MangaTable.COL_LAST_UPDATE, manga.last_update)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -28,5 +28,4 @@ class MangaTitlePutResolver : PutResolver<Manga>() {
|
||||
fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
|
||||
put(MangaTable.COL_TITLE, manga.title)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,5 +28,4 @@ class MangaViewerPutResolver : PutResolver<Manga>() {
|
||||
fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
|
||||
put(MangaTable.COL_VIEWER, manga.viewer)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,7 +23,6 @@ object CategoryTable {
|
||||
$COL_MANGA_ORDER TEXT NOT NULL
|
||||
)"""
|
||||
|
||||
|
||||
val addMangaOrder: String
|
||||
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_MANGA_ORDER TEXT"
|
||||
}
|
||||
|
@ -67,5 +67,4 @@ object ChapterTable {
|
||||
|
||||
val pagesLeftQuery: String
|
||||
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_PAGES_LEFT INTEGER DEFAULT 0"
|
||||
|
||||
}
|
||||
|
@ -20,5 +20,4 @@ object MangaCategoryTable {
|
||||
FOREIGN KEY($COL_MANGA_ID) REFERENCES ${MangaTable.TABLE} (${MangaTable.COL_ID})
|
||||
ON DELETE CASCADE
|
||||
)"""
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package eu.kanade.tachiyomi.data.database.tables
|
||||
|
||||
|
||||
object SearchMetadataTable {
|
||||
const val TABLE = "search_metadata"
|
||||
|
||||
|
@ -10,10 +10,10 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||
import java.util.concurrent.TimeUnit
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* Cache where we dump the downloads directory from the filesystem. This class is needed because
|
||||
@ -27,10 +27,10 @@ import java.util.concurrent.TimeUnit
|
||||
* @param preferences the preferences of the app.
|
||||
*/
|
||||
class DownloadCache(
|
||||
private val context: Context,
|
||||
private val provider: DownloadProvider,
|
||||
private val sourceManager: SourceManager,
|
||||
private val preferences: PreferencesHelper = Injekt.get()
|
||||
private val context: Context,
|
||||
private val provider: DownloadProvider,
|
||||
private val sourceManager: SourceManager,
|
||||
private val preferences: PreferencesHelper = Injekt.get()
|
||||
) {
|
||||
|
||||
/**
|
||||
@ -119,7 +119,7 @@ class DownloadCache(
|
||||
onlineSources.find { provider.getSourceDirName(it) == entry.key }?.id
|
||||
}
|
||||
|
||||
val db:DatabaseHelper by injectLazy()
|
||||
val db: DatabaseHelper by injectLazy()
|
||||
val mangas = db.getMangas().executeAsBlocking().groupBy { it.source }
|
||||
|
||||
sourceDirs.forEach { sourceValue ->
|
||||
@ -143,8 +143,8 @@ class DownloadCache(
|
||||
val trueMangaDirs = mangaDirs.mapNotNull { mangaDir ->
|
||||
val manga = sourceMangas.firstOrNull()?.find { DiskUtil.buildValidFilename(
|
||||
it.originalTitle()).toLowerCase() == mangaDir.key
|
||||
.toLowerCase() && it.source == sourceValue.key } ?:
|
||||
sourceMangas.lastOrNull()?.find { DiskUtil.buildValidFilename(
|
||||
.toLowerCase() && it.source == sourceValue.key }
|
||||
?: sourceMangas.lastOrNull()?.find { DiskUtil.buildValidFilename(
|
||||
it.originalTitle()).toLowerCase() == mangaDir.key
|
||||
.toLowerCase() && it.source == sourceValue.key }
|
||||
val id = manga?.id ?: return@mapNotNull null
|
||||
@ -169,8 +169,7 @@ class DownloadCache(
|
||||
val files = mangaFiles[id]
|
||||
if (files == null) {
|
||||
mangaFiles[id] = mutableSetOf(chapterDirName)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
mangaFiles[id]?.add(chapterDirName)
|
||||
}
|
||||
}
|
||||
@ -216,7 +215,6 @@ class DownloadCache(
|
||||
sourceDir.files = list
|
||||
}*/
|
||||
|
||||
|
||||
/**
|
||||
* Removes a manga that has been deleted from this cache.
|
||||
*
|
||||
@ -230,20 +228,26 @@ class DownloadCache(
|
||||
/**
|
||||
* Class to store the files under the root downloads directory.
|
||||
*/
|
||||
private class RootDirectory(val dir: UniFile,
|
||||
var files: Map<Long, SourceDirectory> = hashMapOf())
|
||||
private class RootDirectory(
|
||||
val dir: UniFile,
|
||||
var files: Map<Long, SourceDirectory> = hashMapOf()
|
||||
)
|
||||
|
||||
/**
|
||||
* Class to store the files under a source directory.
|
||||
*/
|
||||
private class SourceDirectory(val dir: UniFile,
|
||||
var files: Map<Long, MutableSet<String>> = hashMapOf())
|
||||
private class SourceDirectory(
|
||||
val dir: UniFile,
|
||||
var files: Map<Long, MutableSet<String>> = hashMapOf()
|
||||
)
|
||||
|
||||
/**
|
||||
* Class to store the files under a manga directory.
|
||||
*/
|
||||
private class MangaDirectory(val dir: UniFile,
|
||||
var files: MutableSet<String> = hashSetOf())
|
||||
private class MangaDirectory(
|
||||
val dir: UniFile,
|
||||
var files: MutableSet<String> = hashSetOf()
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns a new map containing only the key entries of [transform] that are not null.
|
||||
@ -267,5 +271,4 @@ class DownloadCache(
|
||||
}
|
||||
return destination
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ class DownloadManager(val context: Context) {
|
||||
downloader.pause()
|
||||
downloader.queue.clear()
|
||||
downloader.queue.addAll(downloads)
|
||||
if(!wasPaused){
|
||||
if (!wasPaused) {
|
||||
downloader.start()
|
||||
}
|
||||
}
|
||||
@ -221,10 +221,9 @@ class DownloadManager(val context: Context) {
|
||||
}
|
||||
downloader.pause()
|
||||
downloader.queue.remove(chapters)
|
||||
if(!wasPaused && downloader.queue.isNotEmpty()){
|
||||
if (!wasPaused && downloader.queue.isNotEmpty()) {
|
||||
downloader.start()
|
||||
}
|
||||
else if (downloader.queue.isEmpty() && DownloadService.isRunning(context)) {
|
||||
} else if (downloader.queue.isEmpty() && DownloadService.isRunning(context)) {
|
||||
DownloadService.stop(context)
|
||||
}
|
||||
queue.remove(chapters)
|
||||
@ -255,7 +254,7 @@ class DownloadManager(val context: Context) {
|
||||
cleaned += readChapterDirs.size
|
||||
cache.removeChapters(readChapters, manga)
|
||||
if (cache.getDownloadCount(manga) == 0) {
|
||||
provider.findChapterDirs(allChapters, manga, source).firstOrNull()?.parentFile?.delete()// Delete manga directory if empty
|
||||
provider.findChapterDirs(allChapters, manga, source).firstOrNull()?.parentFile?.delete() // Delete manga directory if empty
|
||||
}
|
||||
return cleaned
|
||||
}
|
||||
@ -295,5 +294,5 @@ class DownloadManager(val context: Context) {
|
||||
}
|
||||
|
||||
fun addListener(listener: DownloadQueue.DownloadListener) = queue.addListener(listener)
|
||||
fun removeListener(listener: DownloadQueue.DownloadListener) = queue.removeListener(listener)
|
||||
fun removeListener(listener: DownloadQueue.DownloadListener) = queue.removeListener(listener)
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.data.download.model.DownloadQueue
|
||||
import eu.kanade.tachiyomi.data.notification.NotificationHandler
|
||||
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
@ -93,8 +92,7 @@ internal class DownloadNotifier(private val context: Context) {
|
||||
setContentText(
|
||||
context.getString(R.string.chapter_downloading)
|
||||
)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
setContentTitle(
|
||||
context.getString(
|
||||
R.string.chapter_downloading
|
||||
@ -102,12 +100,11 @@ internal class DownloadNotifier(private val context: Context) {
|
||||
)
|
||||
setContentText(null)
|
||||
}
|
||||
setProgress(0,0, true)
|
||||
setProgress(0, 0, true)
|
||||
setStyle(null)
|
||||
}
|
||||
// Displays the progress bar on notification
|
||||
notification.show()
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -164,7 +161,7 @@ internal class DownloadNotifier(private val context: Context) {
|
||||
context.getString(R.string.action_resume),
|
||||
NotificationReceiver.resumeDownloadsPendingBroadcast(context)
|
||||
)
|
||||
//Clear action
|
||||
// Clear action
|
||||
addAction(
|
||||
R.drawable.ic_clear_grey_24dp_img,
|
||||
context.getString(R.string.action_cancel_all),
|
||||
|
@ -136,28 +136,28 @@ class DownloadPendingDeleter(context: Context) {
|
||||
* Class used to save an entry of chapters with their manga into preferences.
|
||||
*/
|
||||
private data class Entry(
|
||||
val chapters: List<ChapterEntry>,
|
||||
val manga: MangaEntry
|
||||
val chapters: List<ChapterEntry>,
|
||||
val manga: MangaEntry
|
||||
)
|
||||
|
||||
/**
|
||||
* Class used to save an entry for a chapter into preferences.
|
||||
*/
|
||||
private data class ChapterEntry(
|
||||
val id: Long,
|
||||
val url: String,
|
||||
val name: String,
|
||||
val scanlator: String?
|
||||
val id: Long,
|
||||
val url: String,
|
||||
val name: String,
|
||||
val scanlator: String?
|
||||
)
|
||||
|
||||
/**
|
||||
* Class used to save an entry for a manga into preferences.
|
||||
*/
|
||||
private data class MangaEntry(
|
||||
val id: Long,
|
||||
val url: String,
|
||||
val title: String,
|
||||
val source: Long
|
||||
val id: Long,
|
||||
val url: String,
|
||||
val title: String,
|
||||
val source: Long
|
||||
)
|
||||
|
||||
/**
|
||||
@ -194,5 +194,4 @@ class DownloadPendingDeleter(context: Context) {
|
||||
it.name = name
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -37,9 +37,8 @@ class DownloadProvider(private val context: Context) {
|
||||
}
|
||||
|
||||
init {
|
||||
preferences.downloadsDirectory().asObservable()
|
||||
.skip(1)
|
||||
.subscribe { downloadsDir = UniFile.fromUri(context, Uri.parse(it)) }
|
||||
preferences.downloadsDirectory().asObservable().skip(1)
|
||||
.subscribe { downloadsDir = UniFile.fromUri(context, Uri.parse(it)) }
|
||||
}
|
||||
|
||||
/**
|
||||
@ -50,9 +49,8 @@ class DownloadProvider(private val context: Context) {
|
||||
*/
|
||||
internal fun getMangaDir(manga: Manga, source: Source): UniFile {
|
||||
try {
|
||||
return downloadsDir
|
||||
.createDirectory(getSourceDirName(source))
|
||||
.createDirectory(getMangaDirName(manga))
|
||||
return downloadsDir.createDirectory(getSourceDirName(source))
|
||||
.createDirectory(getMangaDirName(manga))
|
||||
} catch (e: NullPointerException) {
|
||||
throw Exception(context.getString(R.string.invalid_download_dir))
|
||||
}
|
||||
@ -136,8 +134,6 @@ class DownloadProvider(private val context: Context) {
|
||||
val sourceDir = findSourceDir(source)
|
||||
val mangaDir = sourceDir?.findFile(DiskUtil.buildValidFilename(from))
|
||||
mangaDir?.renameTo(to)
|
||||
// val downloadManager:DownloadManager by injectLazy()
|
||||
// downloadManager.renameCache(from, to, sourceId)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -147,7 +143,11 @@ class DownloadProvider(private val context: Context) {
|
||||
* @param manga the manga of the chapter.
|
||||
* @param source the source of the chapter.
|
||||
*/
|
||||
fun findUnmatchedChapterDirs(chapters: List<Chapter>, manga: Manga, source: Source): List<UniFile> {
|
||||
fun findUnmatchedChapterDirs(
|
||||
chapters: List<Chapter>,
|
||||
manga: Manga,
|
||||
source: Source
|
||||
): List<UniFile> {
|
||||
val mangaDir = findMangaDir(manga, source) ?: return emptyList()
|
||||
return mangaDir.listFiles()!!.asList().filter {
|
||||
(chapters.find { chp ->
|
||||
@ -170,7 +170,6 @@ class DownloadProvider(private val context: Context) {
|
||||
return chapters.mapNotNull { mangaDir.findFile("${getChapterDirName(it)}_tmp") }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the download directory name for a source.
|
||||
*
|
||||
@ -213,5 +212,4 @@ class DownloadProvider(private val context: Context) {
|
||||
DiskUtil.buildValidFilename(chapter.name)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -221,7 +221,6 @@ class DownloadService : Service() {
|
||||
.setContentTitle(getString(R.string.download_notifier_downloader_title))
|
||||
.build()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface DownloadServiceListener {
|
||||
|
@ -15,8 +15,8 @@ import uy.kohesive.injekt.injectLazy
|
||||
* @param context the application context.
|
||||
*/
|
||||
class DownloadStore(
|
||||
context: Context,
|
||||
private val sourceManager: SourceManager
|
||||
context: Context,
|
||||
private val sourceManager: SourceManager
|
||||
) {
|
||||
|
||||
/**
|
||||
@ -133,5 +133,4 @@ class DownloadStore(
|
||||
* @param order the order of the download in the queue.
|
||||
*/
|
||||
data class DownloadObject(val mangaId: Long, val chapterId: Long, val order: Int)
|
||||
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import eu.kanade.tachiyomi.util.storage.saveTo
|
||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||
import eu.kanade.tachiyomi.util.system.launchNow
|
||||
import eu.kanade.tachiyomi.util.system.launchUI
|
||||
import java.io.File
|
||||
import kotlinx.coroutines.async
|
||||
import okhttp3.Response
|
||||
import rx.Observable
|
||||
@ -28,7 +29,6 @@ import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
import rx.subscriptions.CompositeSubscription
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* This class is the one in charge of downloading chapters.
|
||||
@ -45,10 +45,10 @@ import java.io.File
|
||||
* @param sourceManager the source manager.
|
||||
*/
|
||||
class Downloader(
|
||||
private val context: Context,
|
||||
private val provider: DownloadProvider,
|
||||
private val cache: DownloadCache,
|
||||
private val sourceManager: SourceManager
|
||||
private val context: Context,
|
||||
private val provider: DownloadProvider,
|
||||
private val cache: DownloadCache,
|
||||
private val sourceManager: SourceManager
|
||||
) {
|
||||
|
||||
/**
|
||||
@ -129,12 +129,11 @@ class Downloader(
|
||||
if (notifier.paused) {
|
||||
if (queue.isEmpty()) {
|
||||
notifier.dismiss()
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
notifier.paused = false
|
||||
notifier.onDownloadPaused()
|
||||
}
|
||||
}else {
|
||||
} else {
|
||||
notifier.dismiss()
|
||||
}
|
||||
}
|
||||
@ -164,7 +163,7 @@ class Downloader(
|
||||
fun clearQueue(isNotification: Boolean = false) {
|
||||
destroySubscriptions()
|
||||
|
||||
//Needed to update the chapter view
|
||||
// Needed to update the chapter view
|
||||
if (isNotification) {
|
||||
queue
|
||||
.filter { it.status == Download.QUEUE }
|
||||
@ -180,7 +179,7 @@ class Downloader(
|
||||
* @param isNotification value that determines if status is set (needed for view updates)
|
||||
*/
|
||||
fun clearQueue(manga: Manga, isNotification: Boolean = false) {
|
||||
//Needed to update the chapter view
|
||||
// Needed to update the chapter view
|
||||
if (isNotification) {
|
||||
queue
|
||||
.filter { it.status == Download.QUEUE && it.manga.id == manga.id }
|
||||
@ -318,7 +317,6 @@ class Downloader(
|
||||
notifier.onError(error.message, download.chapter.name)
|
||||
download
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -448,8 +446,12 @@ class Downloader(
|
||||
* @param tmpDir the directory where the download is currently stored.
|
||||
* @param dirname the real (non temporary) directory name of the download.
|
||||
*/
|
||||
private fun ensureSuccessfulDownload(download: Download, mangaDir: UniFile,
|
||||
tmpDir: UniFile, dirname: String) {
|
||||
private fun ensureSuccessfulDownload(
|
||||
download: Download,
|
||||
mangaDir: UniFile,
|
||||
tmpDir: UniFile,
|
||||
dirname: String
|
||||
) {
|
||||
|
||||
// Ensure that the chapter folder has all the images.
|
||||
val downloadedImages = tmpDir.listFiles().orEmpty().filterNot { it.name!!.endsWith(".tmp") }
|
||||
@ -497,5 +499,4 @@ class Downloader(
|
||||
companion object {
|
||||
const val TMP_DIR_SUFFIX = "_tmp"
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -47,4 +47,4 @@ class Download(val source: HttpSource, val manga: Manga, val chapter: Chapter) {
|
||||
const val DOWNLOADED = 3
|
||||
const val ERROR = 4
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,14 +5,15 @@ import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.download.DownloadStore
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import rx.Observable
|
||||
import rx.subjects.PublishSubject
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
|
||||
class DownloadQueue(
|
||||
private val store: DownloadStore,
|
||||
private val queue: MutableList<Download> = CopyOnWriteArrayList<Download>())
|
||||
: List<Download> by queue {
|
||||
private val store: DownloadStore,
|
||||
private val queue: MutableList<Download> = CopyOnWriteArrayList<Download>()
|
||||
) :
|
||||
List<Download> by queue {
|
||||
|
||||
private val statusSubject = PublishSubject.create<Download>()
|
||||
|
||||
@ -89,8 +90,7 @@ class DownloadQueue(
|
||||
} else if (download.status == Download.DOWNLOADED || download.status == Download.ERROR) {
|
||||
setPagesSubject(download.pages, null)
|
||||
downloadListeners.forEach { it.updateDownload(download) }
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
downloadListeners.forEach { it.updateDownload(download) }
|
||||
}
|
||||
}
|
||||
@ -111,7 +111,6 @@ class DownloadQueue(
|
||||
.onBackpressureBuffer()
|
||||
.filter { it == Page.READY }
|
||||
.map { download }
|
||||
|
||||
} else if (download.status == Download.DOWNLOADED || download.status == Download.ERROR) {
|
||||
setPagesSubject(download.pages, null)
|
||||
downloadListeners.forEach { it.updateDownload(download) }
|
||||
@ -140,5 +139,4 @@ class DownloadQueue(
|
||||
interface DownloadListener {
|
||||
fun updateDownload(download: Download)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,11 @@ import android.util.Log
|
||||
import com.bumptech.glide.Priority
|
||||
import com.bumptech.glide.load.DataSource
|
||||
import com.bumptech.glide.load.data.DataFetcher
|
||||
import java.io.*
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
|
||||
open class FileFetcher(private val file: File) : DataFetcher<InputStream> {
|
||||
|
||||
@ -48,4 +52,4 @@ open class FileFetcher(private val file: File) : DataFetcher<InputStream> {
|
||||
override fun getDataSource(): DataSource {
|
||||
return DataSource.LOCAL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,10 +16,12 @@ import java.io.InputStream
|
||||
* @param manga the manga of the cover to load.
|
||||
* @param file the file where this cover should be. It may exists or not.
|
||||
*/
|
||||
class LibraryMangaUrlFetcher(private val networkFetcher: DataFetcher<InputStream>,
|
||||
private val manga: Manga,
|
||||
private val file: File)
|
||||
: FileFetcher(file) {
|
||||
class LibraryMangaUrlFetcher(
|
||||
private val networkFetcher: DataFetcher<InputStream>,
|
||||
private val manga: Manga,
|
||||
private val file: File
|
||||
) :
|
||||
FileFetcher(file) {
|
||||
|
||||
override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) {
|
||||
if (!file.exists()) {
|
||||
@ -52,7 +54,6 @@ class LibraryMangaUrlFetcher(private val networkFetcher: DataFetcher<InputStream
|
||||
override fun onLoadFailed(e: Exception) {
|
||||
callback.onLoadFailed(e)
|
||||
}
|
||||
|
||||
})
|
||||
} else {
|
||||
loadFromFile(callback)
|
||||
@ -68,5 +69,4 @@ class LibraryMangaUrlFetcher(private val networkFetcher: DataFetcher<InputStream
|
||||
super.cancel()
|
||||
networkFetcher.cancel()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -3,18 +3,22 @@ package eu.kanade.tachiyomi.data.glide
|
||||
import android.util.LruCache
|
||||
import com.bumptech.glide.integration.okhttp3.OkHttpStreamFetcher
|
||||
import com.bumptech.glide.load.Options
|
||||
import com.bumptech.glide.load.model.*
|
||||
import com.bumptech.glide.load.model.GlideUrl
|
||||
import com.bumptech.glide.load.model.Headers
|
||||
import com.bumptech.glide.load.model.LazyHeaders
|
||||
import com.bumptech.glide.load.model.ModelLoader
|
||||
import com.bumptech.glide.load.model.ModelLoaderFactory
|
||||
import com.bumptech.glide.load.model.MultiModelLoaderFactory
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
|
||||
|
||||
/**
|
||||
* A class for loading a cover associated with a [Manga] that can be present in our own cache.
|
||||
@ -78,8 +82,12 @@ class MangaModelLoader : ModelLoader<Manga, InputStream> {
|
||||
* @param width the width of the view where the resource will be loaded.
|
||||
* @param height the height of the view where the resource will be loaded.
|
||||
*/
|
||||
override fun buildLoadData(manga: Manga, width: Int, height: Int,
|
||||
options: Options): ModelLoader.LoadData<InputStream>? {
|
||||
override fun buildLoadData(
|
||||
manga: Manga,
|
||||
width: Int,
|
||||
height: Int,
|
||||
options: Options
|
||||
): ModelLoader.LoadData<InputStream>? {
|
||||
// Check thumbnail is not null or empty
|
||||
val url = manga.thumbnail_url
|
||||
if (url == null || url.isEmpty()) {
|
||||
@ -142,5 +150,4 @@ class MangaModelLoader : ModelLoader<Manga, InputStream> {
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,4 +24,4 @@ class MangaSignature(manga: Manga, file: File) : Key {
|
||||
override fun updateDiskCacheKey(md: MessageDigest) {
|
||||
md.update(key.toByteArray(Key.CHARSET))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,10 +14,10 @@ import java.io.InputStream
|
||||
class PassthroughModelLoader : ModelLoader<InputStream, InputStream> {
|
||||
|
||||
override fun buildLoadData(
|
||||
model: InputStream,
|
||||
width: Int,
|
||||
height: Int,
|
||||
options: Options
|
||||
model: InputStream,
|
||||
width: Int,
|
||||
height: Int,
|
||||
options: Options
|
||||
): ModelLoader.LoadData<InputStream>? {
|
||||
return ModelLoader.LoadData(ObjectKey(model), Fetcher(model))
|
||||
}
|
||||
@ -49,12 +49,11 @@ class PassthroughModelLoader : ModelLoader<InputStream, InputStream> {
|
||||
}
|
||||
|
||||
override fun loadData(
|
||||
priority: Priority,
|
||||
callback: DataFetcher.DataCallback<in InputStream>
|
||||
priority: Priority,
|
||||
callback: DataFetcher.DataCallback<in InputStream>
|
||||
) {
|
||||
callback.onDataReady(stream)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -63,12 +62,11 @@ class PassthroughModelLoader : ModelLoader<InputStream, InputStream> {
|
||||
class Factory : ModelLoaderFactory<InputStream, InputStream> {
|
||||
|
||||
override fun build(
|
||||
multiFactory: MultiModelLoaderFactory
|
||||
multiFactory: MultiModelLoaderFactory
|
||||
): ModelLoader<InputStream, InputStream> {
|
||||
return PassthroughModelLoader()
|
||||
}
|
||||
|
||||
override fun teardown() {}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,9 +13,9 @@ import com.bumptech.glide.module.AppGlideModule
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import java.io.InputStream
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.InputStream
|
||||
|
||||
/**
|
||||
* Class used to update Glide module settings
|
||||
@ -26,8 +26,8 @@ class TachiGlideModule : AppGlideModule() {
|
||||
override fun applyOptions(context: Context, builder: GlideBuilder) {
|
||||
builder.setDiskCache(InternalCacheDiskCacheFactory(context, 50 * 1024 * 1024))
|
||||
builder.setDefaultRequestOptions(RequestOptions().format(DecodeFormat.PREFER_RGB_565))
|
||||
//val memoryCacheSizeBytes = 1024 * 1024 * 100 // 100mb
|
||||
//builder.setMemoryCache(LruResourceCache(memoryCacheSizeBytes.toLong()))
|
||||
// val memoryCacheSizeBytes = 1024 * 1024 * 100 // 100mb
|
||||
// builder.setMemoryCache(LruResourceCache(memoryCacheSizeBytes.toLong()))
|
||||
|
||||
/* builder.setDefaultTransitionOptions(
|
||||
Drawable::class.java,
|
||||
|
@ -5,9 +5,9 @@ import com.evernote.android.job.JobManager
|
||||
import com.evernote.android.job.JobRequest
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import java.util.concurrent.TimeUnit
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class LibraryUpdateJob : Job() {
|
||||
|
||||
|
@ -39,5 +39,4 @@ object LibraryUpdateRanker {
|
||||
compareValues(mangaFirst.currentTitle(), mangaSecond.currentTitle())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,10 @@ import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||
import eu.kanade.tachiyomi.util.lang.chop
|
||||
import eu.kanade.tachiyomi.util.system.notification
|
||||
import eu.kanade.tachiyomi.util.system.notificationManager
|
||||
import java.util.ArrayList
|
||||
import java.util.Date
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
@ -50,10 +54,6 @@ import rx.schedulers.Schedulers
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.ArrayList
|
||||
import java.util.Date
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
/**
|
||||
* This class will take care of updating the chapters of the manga from the library. It can be
|
||||
@ -127,8 +127,8 @@ class LibraryUpdateService(
|
||||
*/
|
||||
enum class Target {
|
||||
CHAPTERS, // Manga chapters
|
||||
DETAILS, // Manga metadata
|
||||
TRACKING // Tracking metadata
|
||||
DETAILS, // Manga metadata
|
||||
TRACKING // Tracking metadata
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -10,6 +10,7 @@ import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.backup.BackupRestoreService
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
@ -27,12 +28,10 @@ import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||
import eu.kanade.tachiyomi.util.system.notificationManager
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import java.io.File
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.File
|
||||
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
|
||||
|
||||
|
||||
/**
|
||||
* Global [BroadcastReceiver] that runs on UI thread
|
||||
@ -113,7 +112,6 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
type = "image/*"
|
||||
}
|
||||
// Close Navigation Shade
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -217,7 +215,6 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
// Called to cancel restore
|
||||
private const val ACTION_CANCEL_RESTORE = "$ID.$NAME.CANCEL_RESTORE"
|
||||
|
||||
|
||||
// Called to open chapter
|
||||
private const val ACTION_OPEN_CHAPTER = "$ID.$NAME.ACTION_OPEN_CHAPTER"
|
||||
|
||||
@ -322,8 +319,12 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
* @param notificationId id of notification
|
||||
* @return [PendingIntent]
|
||||
*/
|
||||
internal fun dismissNotification(context: Context, notificationId: Int, groupId: Int? =
|
||||
null) {
|
||||
internal fun dismissNotification(
|
||||
context: Context,
|
||||
notificationId: Int,
|
||||
groupId: Int? =
|
||||
null
|
||||
) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
val groupKey = context.notificationManager.activeNotifications.find {
|
||||
it.id == notificationId
|
||||
@ -350,7 +351,7 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
* @return [PendingIntent]
|
||||
*/
|
||||
internal fun shareImagePendingBroadcast(context: Context, path: String, notificationId: Int): PendingIntent {
|
||||
//val shareIntent = ShareStartingActivity.newIntent(context, path)
|
||||
// val shareIntent = ShareStartingActivity.newIntent(context, path)
|
||||
val shareIntent = Intent(Intent.ACTION_SEND).apply {
|
||||
val uri = File(path).getUriCompat(context)
|
||||
putExtra(Intent.EXTRA_STREAM, uri)
|
||||
@ -358,7 +359,7 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
clipData = ClipData.newRawUri(null, uri)
|
||||
type = "image/*"
|
||||
}
|
||||
//val shareIntent2 = Intent.createChooser(shareIntent, context.getString(R.string.action_share))
|
||||
// val shareIntent2 = Intent.createChooser(shareIntent, context.getString(R.string.action_share))
|
||||
return PendingIntent.getActivity(context, 0, shareIntent, PendingIntent
|
||||
.FLAG_CANCEL_CURRENT)
|
||||
}
|
||||
@ -387,8 +388,12 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
* @param manga manga of chapter
|
||||
* @param chapter chapter that needs to be opened
|
||||
*/
|
||||
internal fun openChapterPendingActivity(context: Context, manga: Manga, chapter:
|
||||
Chapter): PendingIntent {
|
||||
internal fun openChapterPendingActivity(
|
||||
context: Context,
|
||||
manga: Manga,
|
||||
chapter:
|
||||
Chapter
|
||||
): PendingIntent {
|
||||
val newIntent = ReaderActivity.newIntent(context, manga, chapter)
|
||||
return PendingIntent.getActivity(context, manga.id.hashCode(), newIntent, PendingIntent
|
||||
.FLAG_UPDATE_CURRENT)
|
||||
@ -440,15 +445,19 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
return PendingIntent.getActivity(context, 0, toLaunch, 0)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns [PendingIntent] that marks a chapter as read and deletes it if preferred
|
||||
*
|
||||
* @param context context of application
|
||||
* @param manga manga of chapter
|
||||
*/
|
||||
internal fun markAsReadPendingBroadcast(context: Context, manga: Manga, chapters:
|
||||
Array<Chapter>, groupId: Int):
|
||||
internal fun markAsReadPendingBroadcast(
|
||||
context: Context,
|
||||
manga: Manga,
|
||||
chapters:
|
||||
Array<Chapter>,
|
||||
groupId: Int
|
||||
):
|
||||
PendingIntent {
|
||||
val newIntent = Intent(context, NotificationReceiver::class.java).apply {
|
||||
action = ACTION_MARK_AS_READ
|
||||
@ -486,4 +495,4 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ object Notifications {
|
||||
const val CHANNEL_NEW_CHAPTERS = "new_chapters_channel"
|
||||
const val ID_NEW_CHAPTERS = -301
|
||||
const val GROUP_NEW_CHAPTERS = "eu.kanade.tachiyomi.NEW_CHAPTERS"
|
||||
|
||||
/**
|
||||
* Notification channel and ids used by the library updater.
|
||||
*/
|
||||
@ -49,7 +50,6 @@ object Notifications {
|
||||
const val ID_RESTORE_COMPLETE = -502
|
||||
const val ID_RESTORE_ERROR = -503
|
||||
|
||||
|
||||
/**
|
||||
* Creates the notification channels introduced in Android Oreo.
|
||||
*
|
||||
@ -58,36 +58,37 @@ object Notifications {
|
||||
fun createChannels(context: Context) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
|
||||
|
||||
val channels = listOf(
|
||||
NotificationChannel(
|
||||
CHANNEL_COMMON,
|
||||
context.getString(R.string.channel_common),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
), NotificationChannel(
|
||||
CHANNEL_LIBRARY,
|
||||
context.getString(R.string.channel_library_updates),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
).apply {
|
||||
setShowBadge(false)
|
||||
}, NotificationChannel(
|
||||
CHANNEL_DOWNLOADER,
|
||||
context.getString(R.string.channel_downloader),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
).apply {
|
||||
setShowBadge(false)
|
||||
}, NotificationChannel(
|
||||
CHANNEL_UPDATES_TO_EXTS,
|
||||
context.getString(R.string.channel_ext_updates),
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
), NotificationChannel(
|
||||
CHANNEL_NEW_CHAPTERS,
|
||||
context.getString(R.string.channel_new_chapters),
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
), NotificationChannel(CHANNEL_RESTORE, context.getString(R.string.channel_backup_restore),
|
||||
NotificationManager.IMPORTANCE_LOW).apply {
|
||||
setShowBadge(false)
|
||||
}
|
||||
)
|
||||
val channels = listOf(NotificationChannel(
|
||||
CHANNEL_COMMON,
|
||||
context.getString(R.string.channel_common),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
), NotificationChannel(
|
||||
CHANNEL_LIBRARY,
|
||||
context.getString(R.string.channel_library_updates),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
).apply {
|
||||
setShowBadge(false)
|
||||
}, NotificationChannel(
|
||||
CHANNEL_DOWNLOADER,
|
||||
context.getString(R.string.channel_downloader),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
).apply {
|
||||
setShowBadge(false)
|
||||
}, NotificationChannel(
|
||||
CHANNEL_UPDATES_TO_EXTS,
|
||||
context.getString(R.string.channel_ext_updates),
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
), NotificationChannel(
|
||||
CHANNEL_NEW_CHAPTERS,
|
||||
context.getString(R.string.channel_new_chapters),
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
), NotificationChannel(
|
||||
CHANNEL_RESTORE,
|
||||
context.getString(R.string.channel_backup_restore),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
).apply {
|
||||
setShowBadge(false)
|
||||
})
|
||||
context.notificationManager.createNotificationChannels(channels)
|
||||
}
|
||||
}
|
||||
|
@ -155,11 +155,9 @@ object PreferenceKeys {
|
||||
|
||||
fun sourceSharedPref(sourceId: Long) = "source_$sourceId"
|
||||
|
||||
|
||||
fun trackUsername(syncId: Int) = "pref_mangasync_username_$syncId"
|
||||
|
||||
fun trackPassword(syncId: Int) = "pref_mangasync_password_$syncId"
|
||||
|
||||
fun trackToken(syncId: Int) = "track_token_$syncId"
|
||||
|
||||
}
|
||||
|
@ -8,13 +8,13 @@ import androidx.preference.PreferenceManager
|
||||
import com.f2prateek.rx.preferences.Preference
|
||||
import com.f2prateek.rx.preferences.RxSharedPreferences
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import java.io.File
|
||||
import java.text.DateFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
|
||||
fun <T> Preference<T>.getOrDefault(): T = get() ?: defaultValue()!!
|
||||
|
||||
|
@ -2,10 +2,10 @@ package eu.kanade.tachiyomi.data.track
|
||||
|
||||
import android.content.Context
|
||||
import eu.kanade.tachiyomi.data.track.anilist.Anilist
|
||||
import eu.kanade.tachiyomi.data.track.bangumi.Bangumi
|
||||
import eu.kanade.tachiyomi.data.track.kitsu.Kitsu
|
||||
import eu.kanade.tachiyomi.data.track.myanimelist.MyAnimeList
|
||||
import eu.kanade.tachiyomi.data.track.shikimori.Shikimori
|
||||
import eu.kanade.tachiyomi.data.track.bangumi.Bangumi
|
||||
|
||||
class TrackManager(context: Context) {
|
||||
|
||||
@ -32,5 +32,4 @@ class TrackManager(context: Context) {
|
||||
fun getService(id: Int) = services.find { it.id == id }
|
||||
|
||||
fun hasLoggedServices() = services.any { it.isLogged }
|
||||
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ package eu.kanade.tachiyomi.data.track
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.annotation.DrawableRes
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import okhttp3.OkHttpClient
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
@ -7,7 +7,6 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
@ -144,25 +143,24 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.total_chapters = remoteTrack.total_chapters
|
||||
return track
|
||||
|
||||
}
|
||||
|
||||
override suspend fun login(username: String, password: String) = login(password)
|
||||
|
||||
suspend fun login(token: String): Boolean {
|
||||
suspend fun login(token: String): Boolean {
|
||||
val oauth = api.createOAuth(token)
|
||||
interceptor.setAuth(oauth)
|
||||
|
||||
return try {
|
||||
val currentUser = api.getCurrentUser()
|
||||
scorePreference.set(currentUser.second)
|
||||
saveCredentials(currentUser.first.toString(), oauth.access_token)
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e)
|
||||
logout()
|
||||
false
|
||||
}
|
||||
return try {
|
||||
val currentUser = api.getCurrentUser()
|
||||
scorePreference.set(currentUser.second)
|
||||
saveCredentials(currentUser.first.toString(), oauth.access_token)
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e)
|
||||
logout()
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun logout() {
|
||||
@ -184,7 +182,6 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
const val READING = 1
|
||||
const val COMPLETED = 2
|
||||
@ -202,6 +199,4 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
|
||||
const val POINT_5 = "POINT_5"
|
||||
const val POINT_3 = "POINT_3"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,8 @@ import com.google.gson.JsonParser
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.network.jsonType
|
||||
import java.util.Calendar
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.MediaType
|
||||
@ -19,8 +21,6 @@ import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import okhttp3.Response
|
||||
import java.util.Calendar
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
|
||||
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.data.track.anilist
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
|
||||
|
||||
class AnilistInterceptor(private val anilist: Anilist, private var token: String?) : Interceptor {
|
||||
|
||||
/**
|
||||
@ -23,7 +22,7 @@ class AnilistInterceptor(private val anilist: Anilist, private var token: String
|
||||
if (token.isNullOrEmpty()) {
|
||||
throw Exception("Not authenticated with Anilist")
|
||||
}
|
||||
if (oauth == null){
|
||||
if (oauth == null) {
|
||||
oauth = anilist.loadOAuth()
|
||||
}
|
||||
// Refresh access token if null or expired.
|
||||
@ -54,5 +53,4 @@ class AnilistInterceptor(private val anilist: Anilist, private var token: String
|
||||
this.oauth = oauth
|
||||
anilist.saveOAuth(oauth)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -5,28 +5,30 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
data class OAuth(
|
||||
val access_token: String,
|
||||
val token_type: String,
|
||||
val expires: Long,
|
||||
val expires_in: Long) {
|
||||
val expires_in: Long
|
||||
) {
|
||||
|
||||
fun isExpired() = System.currentTimeMillis() > expires
|
||||
}
|
||||
|
||||
data class ALManga(
|
||||
val media_id: Int,
|
||||
val title_romaji: String,
|
||||
val image_url_lge: String,
|
||||
val description: String?,
|
||||
val type: String,
|
||||
val publishing_status: String,
|
||||
val start_date_fuzzy: Long,
|
||||
val total_chapters: Int) {
|
||||
val media_id: Int,
|
||||
val title_romaji: String,
|
||||
val image_url_lge: String,
|
||||
val description: String?,
|
||||
val type: String,
|
||||
val publishing_status: String,
|
||||
val start_date_fuzzy: Long,
|
||||
val total_chapters: Int
|
||||
) {
|
||||
|
||||
fun toTrack() = TrackSearch.create(TrackManager.ANILIST).apply {
|
||||
media_id = this@ALManga.media_id
|
||||
|
@ -60,12 +60,12 @@ class Bangumi(private val context: Context, id: Int) : TrackService(id) {
|
||||
override suspend fun refresh(track: Track): Track {
|
||||
val statusTrack = api.statusLibManga(track)
|
||||
track.copyPersonalFrom(statusTrack!!)
|
||||
val remoteTrack = api.findLibManga(track)
|
||||
if(remoteTrack != null){
|
||||
val remoteTrack = api.findLibManga(track)
|
||||
if (remoteTrack != null) {
|
||||
track.total_chapters = remoteTrack.total_chapters
|
||||
track.status = remoteTrack.status
|
||||
}
|
||||
return track
|
||||
return track
|
||||
}
|
||||
|
||||
override fun getLogo() = R.drawable.tracker_bangumi
|
||||
|
@ -11,6 +11,7 @@ import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.network.await
|
||||
import java.net.URLEncoder
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.CacheControl
|
||||
@ -18,7 +19,6 @@ import okhttp3.FormBody
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.net.URLEncoder
|
||||
|
||||
class BangumiApi(private val client: OkHttpClient, interceptor: BangumiInterceptor) {
|
||||
|
||||
@ -26,14 +26,10 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
||||
private val authClient = client.newBuilder().addInterceptor(interceptor).build()
|
||||
|
||||
suspend fun addLibManga(track: Track): Track {
|
||||
val body = FormBody.Builder()
|
||||
.add("rating", track.score.toInt().toString())
|
||||
.add("status", track.toBangumiStatus())
|
||||
.build()
|
||||
val request = Request.Builder()
|
||||
.url("$apiUrl/collection/${track.media_id}/update")
|
||||
.post(body)
|
||||
.build()
|
||||
val body = FormBody.Builder().add("rating", track.score.toInt().toString())
|
||||
.add("status", track.toBangumiStatus()).build()
|
||||
val request =
|
||||
Request.Builder().url("$apiUrl/collection/${track.media_id}/update").post(body).build()
|
||||
val response = authClient.newCall(request).await()
|
||||
return track
|
||||
}
|
||||
@ -41,22 +37,17 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
||||
suspend fun updateLibManga(track: Track): Track {
|
||||
// chapter update
|
||||
return withContext(Dispatchers.IO) {
|
||||
val body = FormBody.Builder()
|
||||
.add("watched_eps", track.last_chapter_read.toString())
|
||||
.build()
|
||||
val request = Request.Builder()
|
||||
.url("$apiUrl/subject/${track.media_id}/update/watched_eps")
|
||||
.post(body)
|
||||
.build()
|
||||
val body =
|
||||
FormBody.Builder().add("watched_eps", track.last_chapter_read.toString()).build()
|
||||
val request =
|
||||
Request.Builder().url("$apiUrl/subject/${track.media_id}/update/watched_eps")
|
||||
.post(body).build()
|
||||
|
||||
// read status update
|
||||
val sbody = FormBody.Builder()
|
||||
.add("status", track.toBangumiStatus())
|
||||
.build()
|
||||
val srequest = Request.Builder()
|
||||
.url("$apiUrl/collection/${track.media_id}/update")
|
||||
.post(sbody)
|
||||
.build()
|
||||
val sbody = FormBody.Builder().add("status", track.toBangumiStatus()).build()
|
||||
val srequest =
|
||||
Request.Builder().url("$apiUrl/collection/${track.media_id}/update").post(sbody)
|
||||
.build()
|
||||
authClient.newCall(srequest).execute()
|
||||
authClient.newCall(request).execute()
|
||||
track
|
||||
@ -67,13 +58,8 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
||||
return withContext(Dispatchers.IO) {
|
||||
val url = Uri.parse(
|
||||
"$apiUrl/search/subject/${URLEncoder.encode(search, Charsets.UTF_8.name())}"
|
||||
).buildUpon()
|
||||
.appendQueryParameter("max_results", "20")
|
||||
.build()
|
||||
val request = Request.Builder()
|
||||
.url(url.toString())
|
||||
.get()
|
||||
.build()
|
||||
).buildUpon().appendQueryParameter("max_results", "20").build()
|
||||
val request = Request.Builder().url(url.toString()).get().build()
|
||||
|
||||
val netResponse = authClient.newCall(request).await()
|
||||
var responseBody = netResponse.body?.string().orEmpty()
|
||||
@ -106,9 +92,9 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
||||
return Track.create(TrackManager.BANGUMI).apply {
|
||||
title = mangas["name"].asString
|
||||
media_id = mangas["id"].asInt
|
||||
score = if (mangas["rating"] != null)
|
||||
(if (mangas["rating"].isJsonObject) mangas["rating"].obj["score"].asFloat else 0f)
|
||||
else 0f
|
||||
score =
|
||||
if (mangas["rating"] != null) (if (mangas["rating"].isJsonObject) mangas["rating"].obj["score"].asFloat else 0f)
|
||||
else 0f
|
||||
status = Bangumi.DEFAULT_STATUS
|
||||
tracking_url = mangas["url"].asString
|
||||
}
|
||||
@ -117,10 +103,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
||||
suspend fun findLibManga(track: Track): Track? {
|
||||
return withContext(Dispatchers.IO) {
|
||||
val urlMangas = "$apiUrl/subject/${track.media_id}"
|
||||
val requestMangas = Request.Builder()
|
||||
.url(urlMangas)
|
||||
.get()
|
||||
.build()
|
||||
val requestMangas = Request.Builder().url(urlMangas).get().build()
|
||||
val netResponse = authClient.newCall(requestMangas).execute()
|
||||
val responseBody = netResponse.body?.string().orEmpty()
|
||||
jsonToTrack(JsonParser.parseString(responseBody).obj)
|
||||
@ -129,11 +112,9 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
||||
|
||||
suspend fun statusLibManga(track: Track): Track? {
|
||||
val urlUserRead = "$apiUrl/collection/${track.media_id}"
|
||||
val requestUserRead = Request.Builder()
|
||||
.url(urlUserRead)
|
||||
.cacheControl(CacheControl.FORCE_NETWORK)
|
||||
.get()
|
||||
.build()
|
||||
val requestUserRead =
|
||||
Request.Builder().url(urlUserRead).cacheControl(CacheControl.FORCE_NETWORK).get()
|
||||
.build()
|
||||
|
||||
// todo get user readed chapter here
|
||||
val response = authClient.newCall(requestUserRead).await()
|
||||
@ -145,10 +126,10 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
||||
}
|
||||
|
||||
suspend fun accessToken(code: String): OAuth {
|
||||
return withContext(Dispatchers.IO){
|
||||
val netResponse = client.newCall(accessTokenRequest(code)).execute()
|
||||
return withContext(Dispatchers.IO) {
|
||||
val netResponse = client.newCall(accessTokenRequest(code)).execute()
|
||||
val responseBody = netResponse.body?.string().orEmpty()
|
||||
if(responseBody.isEmpty()){
|
||||
if (responseBody.isEmpty()) {
|
||||
throw Exception("Null Response")
|
||||
}
|
||||
gson.fromJson(responseBody, OAuth::class.java)
|
||||
@ -157,12 +138,8 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
||||
|
||||
private fun accessTokenRequest(code: String) = POST(
|
||||
oauthUrl,
|
||||
body = FormBody.Builder()
|
||||
.add("grant_type", "authorization_code")
|
||||
.add("client_id", clientId)
|
||||
.add("client_secret", clientSecret)
|
||||
.add("code", code)
|
||||
.add("redirect_uri", redirectUrl)
|
||||
body = FormBody.Builder().add("grant_type", "authorization_code").add("client_id", clientId)
|
||||
.add("client_secret", clientSecret).add("code", code).add("redirect_uri", redirectUrl)
|
||||
.build()
|
||||
)
|
||||
|
||||
@ -182,22 +159,15 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
||||
return "$baseMangaUrl/$remoteId"
|
||||
}
|
||||
|
||||
fun authUrl() =
|
||||
Uri.parse(loginUrl).buildUpon()
|
||||
.appendQueryParameter("client_id", clientId)
|
||||
.appendQueryParameter("response_type", "code")
|
||||
.appendQueryParameter("redirect_uri", redirectUrl)
|
||||
.build()
|
||||
fun authUrl() = Uri.parse(loginUrl).buildUpon().appendQueryParameter("client_id", clientId)
|
||||
.appendQueryParameter("response_type", "code")
|
||||
.appendQueryParameter("redirect_uri", redirectUrl).build()
|
||||
|
||||
fun refreshTokenRequest(token: String) = POST(
|
||||
oauthUrl,
|
||||
body = FormBody.Builder()
|
||||
.add("grant_type", "refresh_token")
|
||||
.add("client_id", clientId)
|
||||
.add("client_secret", clientSecret)
|
||||
.add("refresh_token", token)
|
||||
.add("redirect_uri", redirectUrl)
|
||||
.build()
|
||||
body = FormBody.Builder().add("grant_type", "refresh_token").add("client_id", clientId)
|
||||
.add("client_secret", clientSecret).add("refresh_token", token)
|
||||
.add("redirect_uri", redirectUrl).build()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ class BangumiInterceptor(val bangumi: Bangumi, val gson: Gson) : Interceptor {
|
||||
bangumi.saveToken(oauth)
|
||||
}
|
||||
|
||||
fun clearOauth(){
|
||||
fun clearOauth() {
|
||||
bangumi.saveToken(null)
|
||||
}
|
||||
}
|
||||
|
@ -1,49 +1,47 @@
|
||||
package eu.kanade.tachiyomi.data.track.bangumi
|
||||
|
||||
data class Collection(
|
||||
val `private`: Int? = 0,
|
||||
val comment: String? = "",
|
||||
val ep_status: Int? = 0,
|
||||
val lasttouch: Int? = 0,
|
||||
val rating: Int? = 0,
|
||||
val status: Status? = Status(),
|
||||
val tag: List<String?>? = listOf(),
|
||||
val user: User? = User(),
|
||||
val vol_status: Int? = 0
|
||||
val `private`: Int? = 0,
|
||||
val comment: String? = "",
|
||||
val ep_status: Int? = 0,
|
||||
val lasttouch: Int? = 0,
|
||||
val rating: Int? = 0,
|
||||
val status: Status? = Status(),
|
||||
val tag: List<String?>? = listOf(),
|
||||
val user: User? = User(),
|
||||
val vol_status: Int? = 0
|
||||
)
|
||||
|
||||
data class OAuth(
|
||||
val access_token: String,
|
||||
val token_type: String,
|
||||
val created_at: Long,
|
||||
val expires_in: Long,
|
||||
val refresh_token: String?,
|
||||
val user_id: Long?
|
||||
val access_token: String,
|
||||
val token_type: String,
|
||||
val created_at: Long,
|
||||
val expires_in: Long,
|
||||
val refresh_token: String?,
|
||||
val user_id: Long?
|
||||
) {
|
||||
// Access token refresh before expired
|
||||
fun isExpired() = (System.currentTimeMillis() / 1000) > (created_at + expires_in - 3600)
|
||||
}
|
||||
|
||||
data class Status(
|
||||
val id: Int? = 0,
|
||||
val name: String? = "",
|
||||
val type: String? = ""
|
||||
val id: Int? = 0,
|
||||
val name: String? = "",
|
||||
val type: String? = ""
|
||||
)
|
||||
|
||||
data class User(
|
||||
val avatar: Avatar? = Avatar(),
|
||||
val id: Int? = 0,
|
||||
val nickname: String? = "",
|
||||
val sign: String? = "",
|
||||
val url: String? = "",
|
||||
val usergroup: Int? = 0,
|
||||
val username: String? = ""
|
||||
val avatar: Avatar? = Avatar(),
|
||||
val id: Int? = 0,
|
||||
val nickname: String? = "",
|
||||
val sign: String? = "",
|
||||
val url: String? = "",
|
||||
val usergroup: Int? = 0,
|
||||
val username: String? = ""
|
||||
)
|
||||
|
||||
data class Avatar(
|
||||
val large: String? = "",
|
||||
val medium: String? = "",
|
||||
val small: String? = ""
|
||||
val large: String? = "",
|
||||
val medium: String? = "",
|
||||
val small: String? = ""
|
||||
)
|
||||
|
||||
|
||||
|
@ -7,9 +7,9 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import java.text.DecimalFormat
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.DecimalFormat
|
||||
|
||||
class Kitsu(private val context: Context, id: Int) : TrackService(id) {
|
||||
|
||||
|
@ -42,5 +42,4 @@ class KitsuInterceptor(val kitsu: Kitsu, val gson: Gson) : Interceptor {
|
||||
this.oauth = oauth
|
||||
kitsu.saveToken(oauth)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,13 +1,19 @@
|
||||
package eu.kanade.tachiyomi.data.track.kitsu
|
||||
|
||||
import androidx.annotation.CallSuper
|
||||
import com.github.salomonbrys.kotson.*
|
||||
import com.github.salomonbrys.kotson.byInt
|
||||
import com.github.salomonbrys.kotson.byString
|
||||
import com.github.salomonbrys.kotson.nullInt
|
||||
import com.github.salomonbrys.kotson.nullObj
|
||||
import com.github.salomonbrys.kotson.nullString
|
||||
import com.github.salomonbrys.kotson.obj
|
||||
import com.google.gson.JsonObject
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
class KitsuSearchManga(obj: JsonObject) {
|
||||
val id by obj.byInt
|
||||
@ -40,7 +46,6 @@ class KitsuSearchManga(obj: JsonObject) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class KitsuLibManga(obj: JsonObject, manga: JsonObject) {
|
||||
val id by manga.byInt
|
||||
private val canonicalTitle by manga["attributes"].byString
|
||||
@ -77,7 +82,6 @@ class KitsuLibManga(obj: JsonObject, manga: JsonObject) {
|
||||
"planned" -> Kitsu.PLAN_TO_READ
|
||||
else -> throw Exception("Unknown status")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun Track.toKitsuStatus() = when (status) {
|
||||
|
@ -1,11 +1,12 @@
|
||||
package eu.kanade.tachiyomi.data.track.kitsu
|
||||
|
||||
data class OAuth(
|
||||
val access_token: String,
|
||||
val token_type: String,
|
||||
val created_at: Long,
|
||||
val expires_in: Long,
|
||||
val refresh_token: String?) {
|
||||
val access_token: String,
|
||||
val token_type: String,
|
||||
val created_at: Long,
|
||||
val expires_in: Long,
|
||||
val refresh_token: String?
|
||||
) {
|
||||
|
||||
fun isExpired() = (System.currentTimeMillis() / 1000) > (created_at + expires_in - 3600)
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,5 @@ class TrackSearch : Track {
|
||||
fun create(serviceId: Int): TrackSearch = TrackSearch().apply {
|
||||
sync_id = serviceId
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user