Turned on kt lint

This commit is contained in:
Jay 2020-03-15 22:50:20 -07:00
parent cc28ff7a77
commit da786bbc40
396 changed files with 2539 additions and 2843 deletions

View File

@ -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"))
}

View File

@ -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)
}
}

View File

@ -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>() }
}
}

View File

@ -67,5 +67,4 @@ object Migrations {
}
return false
}
}

View File

@ -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"
}

View File

@ -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)
}
}

View File

@ -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() {

View File

@ -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) {

View File

@ -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.
*

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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}"
}
}

View File

@ -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)

View File

@ -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()
}

View File

@ -22,4 +22,3 @@ inline fun <T> StorIOSQLite.inTransactionReturn(block: () -> T): T {
lowLevel().endTransaction()
}
}

View File

@ -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)
}
}

View File

@ -5,5 +5,4 @@ import com.pushtorefresh.storio.sqlite.impl.DefaultStorIOSQLite
interface DbProvider {
val db: DefaultStorIOSQLite
}

View File

@ -47,7 +47,6 @@ class CategoryPutResolver : DefaultPutResolver<Category>() {
val orderString = obj.mangaOrder.joinToString("/")
put(COL_MANGA_ORDER, orderString)
}
}
}

View File

@ -88,4 +88,3 @@ class ChapterDeleteResolver : DefaultDeleteResolver<Chapter>() {
.whereArgs(obj.id)
.build()
}

View File

@ -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

View File

@ -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)
}
}

View File

@ -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
}
}
}

View File

@ -30,5 +30,4 @@ class CategoryImpl : Category {
override fun hashCode(): Int {
return name.hashCode()
}
}

View File

@ -39,5 +39,4 @@ class ChapterImpl : Chapter {
override fun hashCode(): Int {
return url.hashCode()
}
}

View File

@ -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!!
}
}

View File

@ -5,5 +5,4 @@ class LibraryManga : MangaImpl() {
var unread: Int = 0
var category: Int = 0
}

View File

@ -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
}
}
}

View File

@ -17,5 +17,4 @@ class MangaCategory {
return mc
}
}
}

View File

@ -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)

View File

@ -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
}
}

View File

@ -37,5 +37,4 @@ interface Track : Serializable {
sync_id = serviceId
}
}
}

View File

@ -41,5 +41,4 @@ class TrackImpl : Track {
result = 31 * result + media_id
return result
}
}

View File

@ -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()
}

View File

@ -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()
}

View File

@ -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 {

View File

@ -28,5 +28,4 @@ interface MangaCategoryQueries : DbProvider {
insertMangasCategories(mangasCategories).executeAsBlocking()
}
}
}

View File

@ -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()
}

View File

@ -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}

View File

@ -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

View File

@ -30,5 +30,4 @@ interface TrackQueries : DbProvider {
.whereArgs(manga.id, sync.id)
.build())
.prepare()
}

View File

@ -30,6 +30,4 @@ class ChapterBackupPutResolver : PutResolver<Chapter>() {
put(ChapterTable.COL_BOOKMARK, chapter.bookmark)
put(ChapterTable.COL_LAST_PAGE_READ, chapter.last_page_read)
}
}

View File

@ -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)
}
}

View File

@ -28,5 +28,4 @@ class ChapterSourceOrderPutResolver : PutResolver<Chapter>() {
fun mapToContentValues(chapter: Chapter) = ContentValues(1).apply {
put(ChapterTable.COL_SOURCE_ORDER, chapter.source_order)
}
}

View File

@ -60,5 +60,4 @@ class HistoryLastReadPutResolver : HistoryPutResolver() {
fun mapToUpdateContentValues(history: History) = ContentValues(1).apply {
put(HistoryTable.COL_LAST_READ, history.last_read)
}
}

View File

@ -21,5 +21,4 @@ class LibraryMangaGetResolver : DefaultGetResolver<LibraryManga>(), BaseMangaGet
return manga
}
}

View File

@ -24,5 +24,4 @@ class MangaChapterGetResolver : DefaultGetResolver<MangaChapter>() {
return MangaChapter(manga, chapter)
}
}

View File

@ -28,6 +28,4 @@ class MangaFavoritePutResolver : PutResolver<Manga>() {
fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
put(MangaTable.COL_FAVORITE, manga.favorite)
}
}

View File

@ -28,6 +28,4 @@ class MangaFlagsPutResolver : PutResolver<Manga>() {
fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
put(MangaTable.COL_CHAPTER_FLAGS, manga.chapter_flags)
}
}

View File

@ -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)
}
}

View File

@ -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())
}
}

View File

@ -28,6 +28,4 @@ class MangaLastUpdatedPutResolver : PutResolver<Manga>() {
fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
put(MangaTable.COL_LAST_UPDATE, manga.last_update)
}
}

View File

@ -28,5 +28,4 @@ class MangaTitlePutResolver : PutResolver<Manga>() {
fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
put(MangaTable.COL_TITLE, manga.title)
}
}

View File

@ -28,5 +28,4 @@ class MangaViewerPutResolver : PutResolver<Manga>() {
fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
put(MangaTable.COL_VIEWER, manga.viewer)
}
}

View File

@ -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"
}

View File

@ -67,5 +67,4 @@ object ChapterTable {
val pagesLeftQuery: String
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_PAGES_LEFT INTEGER DEFAULT 0"
}

View File

@ -20,5 +20,4 @@ object MangaCategoryTable {
FOREIGN KEY($COL_MANGA_ID) REFERENCES ${MangaTable.TABLE} (${MangaTable.COL_ID})
ON DELETE CASCADE
)"""
}

View File

@ -1,6 +1,5 @@
package eu.kanade.tachiyomi.data.database.tables
object SearchMetadataTable {
const val TABLE = "search_metadata"

View File

@ -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
}
}

View File

@ -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)
}

View File

@ -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),

View File

@ -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
}
}
}

View File

@ -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)
)
}
}

View File

@ -221,7 +221,6 @@ class DownloadService : Service() {
.setContentTitle(getString(R.string.download_notifier_downloader_title))
.build()
}
}
interface DownloadServiceListener {

View File

@ -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)
}

View File

@ -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"
}
}

View File

@ -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)
}
}

View File

@ -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> {

View File

@ -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()
}
}

View File

@ -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
}
}
}

View File

@ -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() {}
}
}

View File

@ -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,

View File

@ -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() {

View File

@ -39,5 +39,4 @@ object LibraryUpdateRanker {
compareValues(mangaFirst.currentTitle(), mangaSecond.currentTitle())
}
}
}

View File

@ -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 {

View File

@ -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

View File

@ -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)
}
}

View File

@ -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"
}

View File

@ -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()!!

View File

@ -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 }
}

View File

@ -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

View File

@ -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"
}
}

View File

@ -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) {

View File

@ -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)
}
}

View File

@ -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

View File

@ -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

View File

@ -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()
)
}
}

View File

@ -59,7 +59,7 @@ class BangumiInterceptor(val bangumi: Bangumi, val gson: Gson) : Interceptor {
bangumi.saveToken(oauth)
}
fun clearOauth(){
fun clearOauth() {
bangumi.saveToken(null)
}
}

View File

@ -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? = ""
)

View File

@ -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) {

View File

@ -42,5 +42,4 @@ class KitsuInterceptor(val kitsu: Kitsu, val gson: Gson) : Interceptor {
this.oauth = oauth
kitsu.saveToken(oauth)
}
}

View File

@ -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) {

View File

@ -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)
}

View File

@ -58,7 +58,5 @@ class TrackSearch : Track {
fun create(serviceId: Int): TrackSearch = TrackSearch().apply {
sync_id = serviceId
}
}
}

View File

@ -108,7 +108,7 @@ class MyAnimeList(private val context: Context, id: Int) : TrackService(id) {
}
// Attempt to login again if cookies have been cleared but credentials are still filled
suspend fun ensureLoggedIn() {
suspend fun ensureLoggedIn() {
if (isAuthorized) return
if (!isLogged) throw Exception("MAL Login Credentials not found")
@ -131,8 +131,7 @@ class MyAnimeList(private val context: Context, id: Int) : TrackService(id) {
var ckCount = 0
val url = BASE_URL.toHttpUrlOrNull()!!
for (ck in networkService.cookieManager.get(url)) {
if (ck.name == USER_SESSION_COOKIE || ck.name == LOGGED_IN_COOKIE)
ckCount++
if (ck.name == USER_SESSION_COOKIE || ck.name == LOGGED_IN_COOKIE) ckCount++
}
return ckCount == 2

View File

@ -36,12 +36,10 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
val realQuery = query.take(100)
val response = client.newCall(GET(searchUrl(realQuery))).await()
val matches = Jsoup.parse(response.consumeBody())
.select("div.js-categories-seasonal.js-block-list.list")
.select("table").select("tbody")
.select("tr").drop(1)
.select("div.js-categories-seasonal.js-block-list.list").select("table")
.select("tbody").select("tr").drop(1)
matches.filter { row -> row.select(TD)[2].text() != "Novel" }
.map { row ->
matches.filter { row -> row.select(TD)[2].text() != "Novel" }.map { row ->
TrackSearch.create(TrackManager.MYANIMELIST).apply {
title = row.searchTitle()
media_id = row.searchMediaId()
@ -53,8 +51,7 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
publishing_type = row.searchPublishingType()
start_date = row.searchStartDate()
}
}
.toList()
}.toList()
}
}
}
@ -117,9 +114,7 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
private suspend fun getSessionInfo(): String {
val response = client.newCall(GET(loginUrl())).execute()
return Jsoup.parse(response.consumeBody())
.select("meta[name=csrf_token]")
.attr("content")
return Jsoup.parse(response.consumeBody()).select("meta[name=csrf_token]").attr("content")
}
private suspend fun login(username: String, password: String, csrf: String) {
@ -147,18 +142,15 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
total_chapters = it.selectInt("manga_chapters")
tracking_url = mangaUrl(media_id)
}
}
.toList()
}.toList()
}
private suspend fun getListUrl(): String {
return withContext(Dispatchers.IO) {
return withContext(Dispatchers.IO) {
val response =
authClient.newCall(POST(url = exportListUrl(), body = exportPostBody())).execute()
baseUrl + Jsoup.parse(response.consumeBody())
.select("div.goodresult")
.select("a")
baseUrl + Jsoup.parse(response.consumeBody()).select("div.goodresult").select("a")
.attr("href")
}
}
@ -179,66 +171,43 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
private fun mangaUrl(remoteId: Int) = baseMangaUrl + remoteId
private fun loginUrl() = Uri.parse(baseUrl).buildUpon()
.appendPath("login.php")
.toString()
private fun loginUrl() = Uri.parse(baseUrl).buildUpon().appendPath("login.php").toString()
private fun searchUrl(query: String): String {
val col = "c[]"
return Uri.parse(baseUrl).buildUpon()
.appendPath("manga.php")
.appendQueryParameter("q", query)
.appendQueryParameter(col, "a")
.appendQueryParameter(col, "b")
.appendQueryParameter(col, "c")
.appendQueryParameter(col, "d")
.appendQueryParameter(col, "e")
.appendQueryParameter(col, "g")
.toString()
return Uri.parse(baseUrl).buildUpon().appendPath("manga.php")
.appendQueryParameter("q", query).appendQueryParameter(col, "a")
.appendQueryParameter(col, "b").appendQueryParameter(col, "c")
.appendQueryParameter(col, "d").appendQueryParameter(col, "e")
.appendQueryParameter(col, "g").toString()
}
private fun exportListUrl() = Uri.parse(baseUrl).buildUpon()
.appendPath("panel.php")
.appendQueryParameter("go", "export")
.toString()
private fun exportListUrl() = Uri.parse(baseUrl).buildUpon().appendPath("panel.php")
.appendQueryParameter("go", "export").toString()
private fun updateUrl() = Uri.parse(baseModifyListUrl).buildUpon()
.appendPath("edit.json")
.toString()
private fun updateUrl() =
Uri.parse(baseModifyListUrl).buildUpon().appendPath("edit.json").toString()
private fun addUrl() = Uri.parse(baseModifyListUrl).buildUpon()
.appendPath("add.json")
.toString()
private fun addUrl() =
Uri.parse(baseModifyListUrl).buildUpon().appendPath("add.json").toString()
private fun listEntryUrl(mediaId: Int) = Uri.parse(baseModifyListUrl).buildUpon()
.appendPath(mediaId.toString())
.appendPath("edit")
.toString()
private fun listEntryUrl(mediaId: Int) =
Uri.parse(baseModifyListUrl).buildUpon().appendPath(mediaId.toString())
.appendPath("edit").toString()
private fun loginPostBody(username: String, password: String, csrf: String): RequestBody {
return FormBody.Builder()
.add("user_name", username)
.add("password", password)
.add("cookie", "1")
.add("sublogin", "Login")
.add("submit", "1")
.add(CSRF, csrf)
return FormBody.Builder().add("user_name", username).add("password", password)
.add("cookie", "1").add("sublogin", "Login").add("submit", "1").add(CSRF, csrf)
.build()
}
private fun exportPostBody(): RequestBody {
return FormBody.Builder()
.add("type", "2")
.add("subexport", "Export My List")
.build()
return FormBody.Builder().add("type", "2").add("subexport", "Export My List").build()
}
private fun mangaPostPayload(track: Track): RequestBody {
val body = JSONObject()
.put("manga_id", track.media_id)
.put("status", track.status)
.put("score", track.score)
.put("num_read_chapters", track.last_chapter_read)
val body = JSONObject().put("manga_id", track.media_id).put("status", track.status)
.put("score", track.score).put("num_read_chapters", track.last_chapter_read)
return body.toString()
.toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())
@ -249,19 +218,13 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
private fun Element.searchTotalChapters() =
if (select(TD)[4].text() == "-") 0 else select(TD)[4].text().toInt()
private fun Element.searchCoverUrl() = select("img")
.attr("data-src")
.split("\\?")[0]
.replace("/r/50x70/", "/")
private fun Element.searchCoverUrl() =
select("img").attr("data-src").split("\\?")[0].replace("/r/50x70/", "/")
private fun Element.searchMediaId() = select("div.picSurround")
.select("a").attr("id")
.replace("sarea", "")
.toInt()
private fun Element.searchMediaId() =
select("div.picSurround").select("a").attr("id").replace("sarea", "").toInt()
private fun Element.searchSummary() = select("div.pt4")
.first()
.ownText()!!
private fun Element.searchSummary() = select("div.pt4").first().ownText()!!
private fun Element.searchPublishingStatus() =
if (select(TD).last().text() == "-") "Publishing" else "Finished"

View File

@ -22,7 +22,6 @@ class MyAnimeListInterceptor(private val myanimelist: MyAnimeList) : Interceptor
}
val request = chain.request()
return chain.proceed(updateRequest(request))
}
private fun updateRequest(request: Request): Request {

View File

@ -6,7 +6,6 @@ import com.google.gson.Gson
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 timber.log.Timber
import uy.kohesive.injekt.injectLazy

View File

@ -13,7 +13,6 @@ import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.asObservableSuccess
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.FormBody
@ -44,10 +43,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
)
)
val body = payload.toString().toRequestBody(jsonime)
val request = Request.Builder()
.url("$apiUrl/v2/user_rates")
.post(body)
.build()
val request = Request.Builder().url("$apiUrl/v2/user_rates").post(body).build()
authClient.newCall(request).execute()
track
}
@ -55,15 +51,11 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
suspend fun search(search: String): List<TrackSearch> {
return withContext(Dispatchers.IO) {
val url = Uri.parse("$apiUrl/mangas").buildUpon()
.appendQueryParameter("order", "popularity")
.appendQueryParameter("search", search)
.appendQueryParameter("limit", "20")
.build()
val request = Request.Builder()
.url(url.toString())
.get()
.build()
val url =
Uri.parse("$apiUrl/mangas").buildUpon().appendQueryParameter("order", "popularity")
.appendQueryParameter("search", search).appendQueryParameter("limit", "20")
.build()
val request = Request.Builder().url(url.toString()).get().build()
val netResponse = authClient.newCall(request).execute()
val responseBody = netResponse.body?.string().orEmpty()
@ -73,7 +65,6 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
val response = JsonParser.parseString(responseBody).array
response.map { jsonToSearch(it.obj) }
}
}
@ -108,20 +99,13 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
val url = Uri.parse("$apiUrl/v2/user_rates").buildUpon()
.appendQueryParameter("user_id", user_id)
.appendQueryParameter("target_id", track.media_id.toString())
.appendQueryParameter("target_type", "Manga")
.build()
val request = Request.Builder()
.url(url.toString())
.get()
.build()
.appendQueryParameter("target_type", "Manga").build()
val request = Request.Builder().url(url.toString()).get().build()
val urlMangas = Uri.parse("$apiUrl/mangas").buildUpon()
.appendPath(track.media_id.toString())
.build()
val requestMangas = Request.Builder()
.url(urlMangas.toString())
.get()
.build()
val urlMangas =
Uri.parse("$apiUrl/mangas").buildUpon().appendPath(track.media_id.toString())
.build()
val requestMangas = Request.Builder().url(urlMangas.toString()).get().build()
val requestMangasResponse = authClient.newCall(requestMangas).execute()
val requestMangasBody = requestMangasResponse.body?.string().orEmpty()
@ -151,7 +135,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
suspend fun accessToken(code: String): OAuth {
return withContext(Dispatchers.IO) {
val netResponse= client.newCall(accessTokenRequest(code)).execute()
val netResponse = client.newCall(accessTokenRequest(code)).execute()
val responseBody = netResponse.body?.string().orEmpty()
if (responseBody.isEmpty()) {
throw Exception("Null Response")
@ -162,12 +146,8 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
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()
)
@ -189,21 +169,14 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
return "$baseMangaUrl/$remoteId"
}
fun authUrl() =
Uri.parse(loginUrl).buildUpon()
.appendQueryParameter("client_id", clientId)
.appendQueryParameter("redirect_uri", redirectUrl)
.appendQueryParameter("response_type", "code")
.build()
fun authUrl() = Uri.parse(loginUrl).buildUpon().appendQueryParameter("client_id", clientId)
.appendQueryParameter("redirect_uri", redirectUrl)
.appendQueryParameter("response_type", "code").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)
.build()
body = FormBody.Builder().add("grant_type", "refresh_token").add("client_id", clientId)
.add("client_secret", clientSecret).add("refresh_token", token).build()
)
}
}

View File

@ -28,9 +28,9 @@ data class OAuth(
val token_type: String,
val created_at: Long,
val expires_in: Long,
val refresh_token: String?) {
val refresh_token: String?
) {
// Access token lives 1 day
fun isExpired() = (System.currentTimeMillis() / 1000) > (created_at + expires_in - 3600)
}

Some files were not shown because too many files have changed in this diff Show More