mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 08:08:55 +01:00 
			
		
		
		
	Merge branch 'master' of https://github.com/inorichi/tachiyomi
# Conflicts: # app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt # app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt # app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt
This commit is contained in:
		@@ -33,7 +33,8 @@ import timber.log.Timber
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
import java.io.File
 | 
			
		||||
import java.text.SimpleDateFormat
 | 
			
		||||
import java.util.*
 | 
			
		||||
import java.util.Date
 | 
			
		||||
import java.util.Locale
 | 
			
		||||
import java.util.concurrent.ExecutorService
 | 
			
		||||
import java.util.concurrent.Executors
 | 
			
		||||
 | 
			
		||||
@@ -295,7 +296,7 @@ class BackupRestoreService : Service() {
 | 
			
		||||
                                          categories: List<String>, history: List<DHistory>,
 | 
			
		||||
                                          tracks: List<Track>): Observable<Manga>? {
 | 
			
		||||
        // Get source
 | 
			
		||||
        val source = backupManager.sourceManager.get(manga.source) ?: return null
 | 
			
		||||
        val source = backupManager.sourceManager.getOrStub(manga.source)
 | 
			
		||||
        val dbManga = backupManager.getMangaFromDatabase(manga)
 | 
			
		||||
 | 
			
		||||
        return if (dbManga == null) {
 | 
			
		||||
@@ -441,4 +442,4 @@ class BackupRestoreService : Service() {
 | 
			
		||||
        sendLocalBroadcast(intent)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -304,9 +304,6 @@ class LibraryUpdateService(
 | 
			
		||||
                }
 | 
			
		||||
                // Add manga with new chapters to the list.
 | 
			
		||||
                .doOnNext { manga ->
 | 
			
		||||
                    // Set last updated time
 | 
			
		||||
                    manga.last_update = Date().time
 | 
			
		||||
                    db.updateLastUpdated(manga).executeAsBlocking()
 | 
			
		||||
                    // Add to the list
 | 
			
		||||
                    newUpdates.add(manga)
 | 
			
		||||
                }
 | 
			
		||||
 
 | 
			
		||||
@@ -55,6 +55,7 @@ data class ALUserManga(
 | 
			
		||||
        score = score_raw.toFloat()
 | 
			
		||||
        last_chapter_read = chapters_read
 | 
			
		||||
        library_id = this@ALUserManga.library_id
 | 
			
		||||
        total_chapters = manga.total_chapters
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun toTrackStatus() = when (list_status) {
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,22 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
 | 
			
		||||
            .build()
 | 
			
		||||
            .create(KitsuApi.Rest::class.java)
 | 
			
		||||
 | 
			
		||||
    private val searchRest = Retrofit.Builder()
 | 
			
		||||
            .baseUrl(algoliaKeyUrl)
 | 
			
		||||
            .client(client)
 | 
			
		||||
            .addConverterFactory(GsonConverterFactory.create())
 | 
			
		||||
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
 | 
			
		||||
            .build()
 | 
			
		||||
            .create(KitsuApi.SearchKeyRest::class.java)
 | 
			
		||||
 | 
			
		||||
    private val algoliaRest = Retrofit.Builder()
 | 
			
		||||
            .baseUrl(algoliaUrl)
 | 
			
		||||
            .client(client)
 | 
			
		||||
            .addConverterFactory(GsonConverterFactory.create())
 | 
			
		||||
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
 | 
			
		||||
            .build()
 | 
			
		||||
            .create(KitsuApi.AgoliaSearchRest::class.java)
 | 
			
		||||
 | 
			
		||||
    fun addLibManga(track: Track, userId: String): Observable<Track> {
 | 
			
		||||
        return Observable.defer {
 | 
			
		||||
            // @formatter:off
 | 
			
		||||
@@ -48,7 +64,6 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
 | 
			
		||||
                            )
 | 
			
		||||
                    )
 | 
			
		||||
            )
 | 
			
		||||
            // @formatter:on
 | 
			
		||||
 | 
			
		||||
            rest.addLibManga(jsonObject("data" to data))
 | 
			
		||||
                    .map { json ->
 | 
			
		||||
@@ -77,12 +92,25 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    fun search(query: String): Observable<List<TrackSearch>> {
 | 
			
		||||
        return rest.search(query)
 | 
			
		||||
        return searchRest
 | 
			
		||||
                .getKey().map { json ->
 | 
			
		||||
                    json["media"].asJsonObject["key"].string
 | 
			
		||||
                }.flatMap { key ->
 | 
			
		||||
                    algoliaSearch(key, query)
 | 
			
		||||
                }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    private fun algoliaSearch(key: String, query: String): Observable<List<TrackSearch>> {
 | 
			
		||||
        val jsonObject = jsonObject("params" to "query=$query$algoliaFilter")
 | 
			
		||||
        return algoliaRest
 | 
			
		||||
                .getSearchQuery(algoliaAppId, key, jsonObject)
 | 
			
		||||
                .map { json ->
 | 
			
		||||
                    val data = json["data"].array
 | 
			
		||||
                    data.map { KitsuManga(it.obj) }
 | 
			
		||||
                            .filter { it.type != "novel" }
 | 
			
		||||
                    val data = json["hits"].array
 | 
			
		||||
                    data.map { KitsuSearchManga(it.obj) }
 | 
			
		||||
                            .filter { it.subType != "novel" }
 | 
			
		||||
                            .map { it.toTrack() }
 | 
			
		||||
                }
 | 
			
		||||
    }
 | 
			
		||||
@@ -143,10 +171,6 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
 | 
			
		||||
                @Body data: JsonObject
 | 
			
		||||
        ): Observable<JsonObject>
 | 
			
		||||
 | 
			
		||||
        @GET("manga")
 | 
			
		||||
        fun search(
 | 
			
		||||
                @Query("filter[text]", encoded = true) query: String
 | 
			
		||||
        ): Observable<JsonObject>
 | 
			
		||||
 | 
			
		||||
        @GET("library-entries")
 | 
			
		||||
        fun findLibManga(
 | 
			
		||||
@@ -168,6 +192,16 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private interface SearchKeyRest {
 | 
			
		||||
        @GET("media/")
 | 
			
		||||
        fun getKey(): Observable<JsonObject>
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private interface AgoliaSearchRest {
 | 
			
		||||
        @POST("query/")
 | 
			
		||||
        fun getSearchQuery(@Header("X-Algolia-Application-Id") appid: String, @Header("X-Algolia-API-Key") key: String, @Body json: JsonObject): Observable<JsonObject>
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private interface LoginRest {
 | 
			
		||||
 | 
			
		||||
        @FormUrlEncoded
 | 
			
		||||
@@ -188,6 +222,11 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
 | 
			
		||||
        private const val baseUrl = "https://kitsu.io/api/edge/"
 | 
			
		||||
        private const val loginUrl = "https://kitsu.io/api/"
 | 
			
		||||
        private const val baseMangaUrl = "https://kitsu.io/manga/"
 | 
			
		||||
        private const val algoliaKeyUrl = "https://kitsu.io/api/edge/algolia-keys/"
 | 
			
		||||
        private const val algoliaUrl = "https://AWQO5J657S-dsn.algolia.net/1/indexes/production_media/"
 | 
			
		||||
        private const val algoliaAppId = "AWQO5J657S"
 | 
			
		||||
        private const val algoliaFilter = "&facetFilters=%5B%22kind%3Amanga%22%5D&attributesToRetrieve=%5B%22synopsis%22%2C%22canonicalTitle%22%2C%22chapterCount%22%2C%22posterImage%22%2C%22startDate%22%2C%22subtype%22%2C%22endDate%22%2C%20%22id%22%5D"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        fun mangaUrl(remoteId: Int): String {
 | 
			
		||||
            return baseMangaUrl + remoteId
 | 
			
		||||
 
 | 
			
		||||
@@ -6,39 +6,65 @@ 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.*
 | 
			
		||||
 | 
			
		||||
open class KitsuManga(obj: JsonObject) {
 | 
			
		||||
class KitsuSearchManga(obj: JsonObject) {
 | 
			
		||||
    val id by obj.byInt
 | 
			
		||||
    val canonicalTitle by obj["attributes"].byString
 | 
			
		||||
    val chapterCount = obj["attributes"].obj.get("chapterCount").nullInt
 | 
			
		||||
    val type = obj["attributes"].obj.get("mangaType").nullString.orEmpty()
 | 
			
		||||
    val original by obj["attributes"].obj["posterImage"].byString
 | 
			
		||||
    val synopsis by obj["attributes"].byString
 | 
			
		||||
    val startDate = obj["attributes"].obj.get("startDate").nullString.orEmpty()
 | 
			
		||||
    open val status = obj["attributes"].obj.get("status").nullString.orEmpty()
 | 
			
		||||
    private val canonicalTitle by obj.byString
 | 
			
		||||
    private val chapterCount = obj.get("chapterCount").nullInt
 | 
			
		||||
    val subType = obj.get("subtype").nullString
 | 
			
		||||
    val original by obj["posterImage"].byString
 | 
			
		||||
    private val synopsis by obj.byString
 | 
			
		||||
    private var startDate = obj.get("startDate").nullString?.let {
 | 
			
		||||
        val outputDf = SimpleDateFormat("yyyy-MM-dd", Locale.US)
 | 
			
		||||
        outputDf.format(Date(it!!.toLong() * 1000))
 | 
			
		||||
    }
 | 
			
		||||
    private val endDate = obj.get("endDate").nullString
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @CallSuper
 | 
			
		||||
    open fun toTrack() = TrackSearch.create(TrackManager.KITSU).apply {
 | 
			
		||||
        media_id = this@KitsuManga.id
 | 
			
		||||
        media_id = this@KitsuSearchManga.id
 | 
			
		||||
        title = canonicalTitle
 | 
			
		||||
        total_chapters = chapterCount ?: 0
 | 
			
		||||
        cover_url = original
 | 
			
		||||
        summary = synopsis
 | 
			
		||||
        tracking_url = KitsuApi.mangaUrl(media_id)
 | 
			
		||||
        publishing_status = this@KitsuManga.status
 | 
			
		||||
        publishing_type = type
 | 
			
		||||
        start_date = startDate.orEmpty()
 | 
			
		||||
        if (endDate == null) {
 | 
			
		||||
            publishing_status = "Publishing"
 | 
			
		||||
        } else {
 | 
			
		||||
            publishing_status = "Finished"
 | 
			
		||||
        }
 | 
			
		||||
        publishing_type = subType ?: ""
 | 
			
		||||
        start_date = startDate ?: ""
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class KitsuLibManga(obj: JsonObject, manga: JsonObject) : KitsuManga(manga) {
 | 
			
		||||
    val libraryId by obj.byInt("id")
 | 
			
		||||
    override val status by obj["attributes"].byString
 | 
			
		||||
    val ratingTwenty = obj["attributes"].obj.get("ratingTwenty").nullString
 | 
			
		||||
 | 
			
		||||
class KitsuLibManga(obj: JsonObject, manga: JsonObject) {
 | 
			
		||||
    val id by manga.byInt
 | 
			
		||||
    private val canonicalTitle by manga["attributes"].byString
 | 
			
		||||
    private val chapterCount = manga["attributes"].obj.get("chapterCount").nullInt
 | 
			
		||||
    val type = manga["attributes"].obj.get("mangaType").nullString.orEmpty()
 | 
			
		||||
    val original by manga["attributes"].obj["posterImage"].byString
 | 
			
		||||
    private val synopsis by manga["attributes"].byString
 | 
			
		||||
    private val startDate = manga["attributes"].obj.get("startDate").nullString.orEmpty()
 | 
			
		||||
    private val libraryId by obj.byInt("id")
 | 
			
		||||
    val status by obj["attributes"].byString
 | 
			
		||||
    private val ratingTwenty = obj["attributes"].obj.get("ratingTwenty").nullString
 | 
			
		||||
    val progress by obj["attributes"].byInt
 | 
			
		||||
 | 
			
		||||
    override fun toTrack() = super.toTrack().apply {
 | 
			
		||||
        media_id = libraryId // TODO migrate media ids to library ids
 | 
			
		||||
    open fun toTrack() = TrackSearch.create(TrackManager.KITSU).apply {
 | 
			
		||||
        media_id = libraryId
 | 
			
		||||
        title = canonicalTitle
 | 
			
		||||
        total_chapters = chapterCount ?: 0
 | 
			
		||||
        cover_url = original
 | 
			
		||||
        summary = synopsis
 | 
			
		||||
        tracking_url = KitsuApi.mangaUrl(media_id)
 | 
			
		||||
        publishing_status = this@KitsuLibManga.status
 | 
			
		||||
        publishing_type = type
 | 
			
		||||
        start_date = startDate
 | 
			
		||||
        status = toTrackStatus()
 | 
			
		||||
        score = ratingTwenty?.let { it.toInt() / 2f } ?: 0f
 | 
			
		||||
        last_chapter_read = progress
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,10 @@
 | 
			
		||||
package eu.kanade.tachiyomi.source
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.source.model.Page
 | 
			
		||||
import eu.kanade.tachiyomi.source.model.SChapter
 | 
			
		||||
import eu.kanade.tachiyomi.source.model.SManga
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
 | 
			
		||||
import eu.kanade.tachiyomi.source.online.HttpSource
 | 
			
		||||
@@ -13,12 +17,12 @@ import eu.kanade.tachiyomi.source.online.german.WieManga
 | 
			
		||||
import eu.kanade.tachiyomi.source.online.russian.Mangachan
 | 
			
		||||
import eu.kanade.tachiyomi.source.online.russian.Mintmanga
 | 
			
		||||
import eu.kanade.tachiyomi.source.online.russian.Readmanga
 | 
			
		||||
import rx.Observable
 | 
			
		||||
import exh.EH_SOURCE_ID
 | 
			
		||||
import exh.EXH_SOURCE_ID
 | 
			
		||||
import exh.PERV_EDEN_EN_SOURCE_ID
 | 
			
		||||
import exh.PERV_EDEN_IT_SOURCE_ID
 | 
			
		||||
import exh.metadata.models.PervEdenLang
 | 
			
		||||
import rx.Observable
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
 | 
			
		||||
open class SourceManager(private val context: Context) {
 | 
			
		||||
@@ -27,6 +31,8 @@ open class SourceManager(private val context: Context) {
 | 
			
		||||
 | 
			
		||||
    private val sourcesMap = mutableMapOf<Long, Source>()
 | 
			
		||||
 | 
			
		||||
    private val stubSourcesMap = mutableMapOf<Long, StubSource>()
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        createInternalSources().forEach { registerSource(it) }
 | 
			
		||||
 | 
			
		||||
@@ -49,13 +55,19 @@ open class SourceManager(private val context: Context) {
 | 
			
		||||
        return sourcesMap[sourceKey]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getOrStub(sourceKey: Long): Source {
 | 
			
		||||
        return sourcesMap[sourceKey] ?: stubSourcesMap.getOrPut(sourceKey) {
 | 
			
		||||
            StubSource(sourceKey)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getOnlineSources() = sourcesMap.values.filterIsInstance<HttpSource>()
 | 
			
		||||
 | 
			
		||||
    fun getCatalogueSources() = sourcesMap.values.filterIsInstance<CatalogueSource>()
 | 
			
		||||
 | 
			
		||||
    internal fun registerSource(source: Source, overwrite: Boolean = false) {
 | 
			
		||||
        if (overwrite || !sourcesMap.containsKey(source.id)) {
 | 
			
		||||
            sourcesMap.put(source.id, source)
 | 
			
		||||
            sourcesMap[source.id] = source
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -92,4 +104,30 @@ open class SourceManager(private val context: Context) {
 | 
			
		||||
        exSrcs += Hitomi(context)
 | 
			
		||||
        return exSrcs
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private inner class StubSource(override val id: Long) : Source {
 | 
			
		||||
 | 
			
		||||
        override val name: String
 | 
			
		||||
            get() = id.toString()
 | 
			
		||||
 | 
			
		||||
        override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
 | 
			
		||||
            return Observable.error(getSourceNotInstalledException())
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
 | 
			
		||||
            return Observable.error(getSourceNotInstalledException())
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override fun fetchPageList(chapter: SChapter): Observable<List<Page>> {
 | 
			
		||||
            return Observable.error(getSourceNotInstalledException())
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override fun toString(): String {
 | 
			
		||||
            return name
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private fun getSourceNotInstalledException(): Exception {
 | 
			
		||||
            return Exception(context.getString(R.string.source_not_installed, id.toString()))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -95,16 +95,16 @@ class Mintmanga : ParsedHttpSource() {
 | 
			
		||||
        } else {
 | 
			
		||||
            chapter.name = urlText
 | 
			
		||||
        }
 | 
			
		||||
        chapter.date_upload = element.select("td:eq(1)").first()?.text()?.let {
 | 
			
		||||
        chapter.date_upload = element.select("td.hidden-xxs").last()?.text()?.let {
 | 
			
		||||
            SimpleDateFormat("dd/MM/yy", Locale.US).parse(it).time
 | 
			
		||||
        } ?: 0
 | 
			
		||||
        return chapter
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun prepareNewChapter(chapter: SChapter, manga: SManga) {
 | 
			
		||||
        val basic = Regex("""\s([0-9]+)(\s-\s)([0-9]+)\s*""")
 | 
			
		||||
        val extra = Regex("""\s([0-9]+\sЭкстра)\s*""")
 | 
			
		||||
        val single = Regex("""\sСингл\s*""")
 | 
			
		||||
        val basic = Regex("""\s*([0-9]+)(\s-\s)([0-9]+)\s*""")
 | 
			
		||||
        val extra = Regex("""\s*([0-9]+\sЭкстра)\s*""")
 | 
			
		||||
        val single = Regex("""\s*Сингл\s*""")
 | 
			
		||||
        when {
 | 
			
		||||
            basic.containsMatchIn(chapter.name) -> {
 | 
			
		||||
                basic.find(chapter.name)?.let {
 | 
			
		||||
 
 | 
			
		||||
@@ -95,16 +95,16 @@ class Readmanga : ParsedHttpSource() {
 | 
			
		||||
        } else {
 | 
			
		||||
            chapter.name = urlText
 | 
			
		||||
        }
 | 
			
		||||
        chapter.date_upload = element.select("td:eq(1)").first()?.text()?.let {
 | 
			
		||||
        chapter.date_upload = element.select("td.hidden-xxs").last()?.text()?.let {
 | 
			
		||||
            SimpleDateFormat("dd/MM/yy", Locale.US).parse(it).time
 | 
			
		||||
        } ?: 0
 | 
			
		||||
        return chapter
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun prepareNewChapter(chapter: SChapter, manga: SManga) {
 | 
			
		||||
        val basic = Regex("""\s([0-9]+)(\s-\s)([0-9]+)\s*""")
 | 
			
		||||
        val extra = Regex("""\s([0-9]+\sЭкстра)\s*""")
 | 
			
		||||
        val single = Regex("""\sСингл\s*""")
 | 
			
		||||
        val basic = Regex("""\s*([0-9]+)(\s-\s)([0-9]+)\s*""")
 | 
			
		||||
        val extra = Regex("""\s*([0-9]+\sЭкстра)\s*""")
 | 
			
		||||
        val single = Regex("""\s*Сингл\s*""")
 | 
			
		||||
        when {
 | 
			
		||||
            basic.containsMatchIn(chapter.name) -> {
 | 
			
		||||
                basic.find(chapter.name)?.let {
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,9 @@ import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
import java.io.IOException
 | 
			
		||||
import java.io.InputStream
 | 
			
		||||
import java.util.*
 | 
			
		||||
import java.util.ArrayList
 | 
			
		||||
import java.util.Collections
 | 
			
		||||
import java.util.Comparator
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class containing library information.
 | 
			
		||||
@@ -118,9 +120,6 @@ class LibraryPresenter(
 | 
			
		||||
        val filterCompleted = preferences.filterCompleted().getOrDefault()
 | 
			
		||||
 | 
			
		||||
        val filterFn: (LibraryItem) -> Boolean = f@ { item ->
 | 
			
		||||
            // Filter out manga without source.
 | 
			
		||||
            sourceManager.get(item.manga.source) ?: return@f false
 | 
			
		||||
 | 
			
		||||
            // Filter when there isn't unread chapters.
 | 
			
		||||
            if (filterUnread && item.manga.unread == 0) {
 | 
			
		||||
                return@f false
 | 
			
		||||
@@ -202,8 +201,8 @@ class LibraryPresenter(
 | 
			
		||||
                    manga1TotalChapter.compareTo(mange2TotalChapter)
 | 
			
		||||
                }
 | 
			
		||||
                LibrarySort.SOURCE -> {
 | 
			
		||||
                    val source1Name = sourceManager.get(i1.manga.source)?.name ?: ""
 | 
			
		||||
                    val source2Name = sourceManager.get(i2.manga.source)?.name ?: ""
 | 
			
		||||
                    val source1Name = sourceManager.getOrStub(i1.manga.source).name
 | 
			
		||||
                    val source2Name = sourceManager.getOrStub(i2.manga.source).name
 | 
			
		||||
                    source1Name.compareTo(source2Name)
 | 
			
		||||
                }
 | 
			
		||||
                else -> throw Exception("Unknown sorting mode")
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@ import kotlinx.android.synthetic.main.manga_controller.*
 | 
			
		||||
import rx.Subscription
 | 
			
		||||
import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
import java.util.*
 | 
			
		||||
import java.util.Date
 | 
			
		||||
 | 
			
		||||
class MangaController : RxController, TabbedController {
 | 
			
		||||
 | 
			
		||||
@@ -44,7 +44,7 @@ class MangaController : RxController, TabbedController {
 | 
			
		||||
    }) {
 | 
			
		||||
        this.manga = manga
 | 
			
		||||
        if (manga != null) {
 | 
			
		||||
            source = Injekt.get<SourceManager>().get(manga.source)
 | 
			
		||||
            source = Injekt.get<SourceManager>().getOrStub(manga.source)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -329,10 +329,9 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
 | 
			
		||||
        val source = presenter.source as? HttpSource ?: return
 | 
			
		||||
        try {
 | 
			
		||||
            val url = source.mangaDetailsRequest(presenter.manga).url().toString()
 | 
			
		||||
            val title = presenter.manga.title
 | 
			
		||||
            val intent = Intent(Intent.ACTION_SEND).apply {
 | 
			
		||||
                type = "text/plain"
 | 
			
		||||
                putExtra(Intent.EXTRA_TEXT, context.getString(R.string.share_text, title, url))
 | 
			
		||||
                putExtra(Intent.EXTRA_TEXT, url)
 | 
			
		||||
            }
 | 
			
		||||
            startActivity(Intent.createChooser(intent, context.getString(R.string.action_share)))
 | 
			
		||||
        } catch (e: Exception) {
 | 
			
		||||
 
 | 
			
		||||
@@ -71,7 +71,7 @@ class MigrationPresenter(
 | 
			
		||||
    private fun findSourcesWithManga(library: List<Manga>): List<SourceItem> {
 | 
			
		||||
        val header = SelectionHeader()
 | 
			
		||||
        return library.map { it.source }.toSet()
 | 
			
		||||
                .mapNotNull { if (it != LocalSource.ID) sourceManager.get(it) else null }
 | 
			
		||||
                .mapNotNull { if (it != LocalSource.ID) sourceManager.getOrStub(it) else null }
 | 
			
		||||
                .map { SourceItem(it, header) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,8 @@ import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
import java.io.File
 | 
			
		||||
import java.net.URLConnection
 | 
			
		||||
import java.util.*
 | 
			
		||||
import java.util.Comparator
 | 
			
		||||
import java.util.Date
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Presenter of [ReaderActivity].
 | 
			
		||||
@@ -75,7 +76,7 @@ class ReaderPresenter(
 | 
			
		||||
    /**
 | 
			
		||||
     * Source of the manga.
 | 
			
		||||
     */
 | 
			
		||||
    /* private */ val source by lazy { sourceManager.get(manga.source)!! }
 | 
			
		||||
    /* private */ val source by lazy { sourceManager.getOrStub(manga.source) }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Chapter list for the active manga. It's retrieved lazily and should be accessed for the first
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,9 @@ import rx.schedulers.Schedulers
 | 
			
		||||
import timber.log.Timber
 | 
			
		||||
import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
import java.util.*
 | 
			
		||||
import java.util.Calendar
 | 
			
		||||
import java.util.Date
 | 
			
		||||
import java.util.TreeMap
 | 
			
		||||
 | 
			
		||||
class RecentChaptersPresenter(
 | 
			
		||||
        val preferences: PreferencesHelper = Injekt.get(),
 | 
			
		||||
@@ -57,7 +59,6 @@ class RecentChaptersPresenter(
 | 
			
		||||
                .map { mangaChapters ->
 | 
			
		||||
                    val map = TreeMap<Date, MutableList<MangaChapter>> { d1, d2 -> d2.compareTo(d1) }
 | 
			
		||||
                    val byDay = mangaChapters
 | 
			
		||||
                            .filter { sourceManager.get(it.manga.source) != null }
 | 
			
		||||
                            .groupByTo(map, { getMapKey(it.chapter.date_fetch) })
 | 
			
		||||
                    byDay.flatMap {
 | 
			
		||||
                        val dateItem = DateItem(it.key)
 | 
			
		||||
@@ -195,4 +196,4 @@ class RecentChaptersPresenter(
 | 
			
		||||
        item.download = null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
 | 
			
		||||
import eu.kanade.tachiyomi.data.glide.GlideApp
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
 | 
			
		||||
import kotlinx.android.synthetic.main.recently_read_item.*
 | 
			
		||||
import java.util.*
 | 
			
		||||
import java.util.Date
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Holder that contains recent manga item
 | 
			
		||||
@@ -52,7 +52,7 @@ class RecentlyReadHolder(
 | 
			
		||||
        // Set source + chapter title
 | 
			
		||||
        val formattedNumber = adapter.decimalFormat.format(chapter.chapter_number.toDouble())
 | 
			
		||||
        manga_source.text = itemView.context.getString(R.string.recent_manga_source)
 | 
			
		||||
                .format(adapter.sourceManager.get(manga.source)?.toString(), formattedNumber)
 | 
			
		||||
                .format(adapter.sourceManager.getOrStub(manga.source).toString(), formattedNumber)
 | 
			
		||||
 | 
			
		||||
        // Set last read timestamp title
 | 
			
		||||
        last_read.text = adapter.dateFormat.format(Date(history.last_read))
 | 
			
		||||
 
 | 
			
		||||
@@ -5,12 +5,13 @@ import eu.kanade.tachiyomi.data.database.DatabaseHelper
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Chapter
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.History
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.source.SourceManager
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
 | 
			
		||||
import rx.Observable
 | 
			
		||||
import rx.android.schedulers.AndroidSchedulers
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
import java.util.*
 | 
			
		||||
import java.util.Calendar
 | 
			
		||||
import java.util.Comparator
 | 
			
		||||
import java.util.Date
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Presenter of RecentlyReadFragment.
 | 
			
		||||
@@ -24,8 +25,6 @@ class RecentlyReadPresenter : BasePresenter<RecentlyReadController>() {
 | 
			
		||||
     */
 | 
			
		||||
    val db: DatabaseHelper by injectLazy()
 | 
			
		||||
 | 
			
		||||
    private val sourceManager: SourceManager by injectLazy()
 | 
			
		||||
 | 
			
		||||
    override fun onCreate(savedState: Bundle?) {
 | 
			
		||||
        super.onCreate(savedState)
 | 
			
		||||
 | 
			
		||||
@@ -45,10 +44,7 @@ class RecentlyReadPresenter : BasePresenter<RecentlyReadController>() {
 | 
			
		||||
        cal.add(Calendar.MONTH, -1)
 | 
			
		||||
 | 
			
		||||
        return db.getRecentManga(cal.time).asRxObservable()
 | 
			
		||||
                .map { recents ->
 | 
			
		||||
                    recents.filter { sourceManager.get(it.manga.source) != null }
 | 
			
		||||
                            .map(::RecentlyReadItem)
 | 
			
		||||
                }
 | 
			
		||||
                .map { recents -> recents.map(::RecentlyReadItem) }
 | 
			
		||||
                .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -122,6 +122,10 @@ fun syncChaptersWithSource(db: DatabaseHelper,
 | 
			
		||||
 | 
			
		||||
        // Fix order in source.
 | 
			
		||||
        db.fixChaptersSourceOrder(sourceChapters).executeAsBlocking()
 | 
			
		||||
 | 
			
		||||
        // Set this manga as updated since chapters were changed
 | 
			
		||||
        manga.last_update = Date().time
 | 
			
		||||
        db.updateLastUpdated(manga).executeAsBlocking()
 | 
			
		||||
    }
 | 
			
		||||
    return Pair(toAdd.subtract(readded).toList(), toDelete.subtract(readded).toList())
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user