mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 10:44:42 +00:00
fix: Don't download filtered chapters when trying to download unread
This commit is contained in:
parent
0f0187b730
commit
4087506bc1
15 changed files with 192 additions and 26 deletions
|
@ -1,9 +1,13 @@
|
||||||
package dev.yokai.core.di
|
package dev.yokai.core.di
|
||||||
|
|
||||||
|
import dev.yokai.data.chapter.ChapterRepositoryImpl
|
||||||
import dev.yokai.domain.extension.repo.ExtensionRepoRepository
|
import dev.yokai.domain.extension.repo.ExtensionRepoRepository
|
||||||
import dev.yokai.data.extension.repo.ExtensionRepoRepositoryImpl
|
import dev.yokai.data.extension.repo.ExtensionRepoRepositoryImpl
|
||||||
import dev.yokai.data.library.custom.CustomMangaRepositoryImpl
|
import dev.yokai.data.library.custom.CustomMangaRepositoryImpl
|
||||||
import dev.yokai.data.manga.MangaRepositoryImpl
|
import dev.yokai.data.manga.MangaRepositoryImpl
|
||||||
|
import dev.yokai.domain.chapter.ChapterRepository
|
||||||
|
import dev.yokai.domain.chapter.interactor.GetAvailableScanlators
|
||||||
|
import dev.yokai.domain.chapter.interactor.GetChapters
|
||||||
import dev.yokai.domain.extension.interactor.TrustExtension
|
import dev.yokai.domain.extension.interactor.TrustExtension
|
||||||
import dev.yokai.domain.extension.repo.interactor.CreateExtensionRepo
|
import dev.yokai.domain.extension.repo.interactor.CreateExtensionRepo
|
||||||
import dev.yokai.domain.extension.repo.interactor.DeleteExtensionRepo
|
import dev.yokai.domain.extension.repo.interactor.DeleteExtensionRepo
|
||||||
|
@ -44,5 +48,9 @@ class DomainModule : InjektModule {
|
||||||
|
|
||||||
addSingletonFactory<MangaRepository> { MangaRepositoryImpl(get()) }
|
addSingletonFactory<MangaRepository> { MangaRepositoryImpl(get()) }
|
||||||
addFactory { GetLibraryManga(get()) }
|
addFactory { GetLibraryManga(get()) }
|
||||||
|
|
||||||
|
addSingletonFactory<ChapterRepository> { ChapterRepositoryImpl(get()) }
|
||||||
|
addFactory { GetAvailableScanlators(get()) }
|
||||||
|
addFactory { GetChapters(get()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package dev.yokai.data.chapter
|
||||||
|
|
||||||
|
import dev.yokai.data.DatabaseHandler
|
||||||
|
import dev.yokai.domain.chapter.ChapterRepository
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
|
import eu.kanade.tachiyomi.util.system.toInt
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
class ChapterRepositoryImpl(private val handler: DatabaseHandler) : ChapterRepository {
|
||||||
|
override suspend fun getChapters(mangaId: Long, filterScanlators: Boolean): List<Chapter> =
|
||||||
|
handler.awaitList { chaptersQueries.getChaptersByMangaId(mangaId, filterScanlators.toInt().toLong(), Chapter::mapper) }
|
||||||
|
|
||||||
|
override fun getChaptersAsFlow(mangaId: Long, filterScanlators: Boolean): Flow<List<Chapter>> =
|
||||||
|
handler.subscribeToList { chaptersQueries.getChaptersByMangaId(mangaId, filterScanlators.toInt().toLong(), Chapter::mapper) }
|
||||||
|
|
||||||
|
override suspend fun getScanlatorsByChapter(mangaId: Long): List<String> =
|
||||||
|
handler.awaitList { chaptersQueries.getScanlatorsByMangaId(mangaId) { it.orEmpty() } }
|
||||||
|
|
||||||
|
override fun getScanlatorsByChapterAsFlow(mangaId: Long): Flow<List<String>> =
|
||||||
|
handler.subscribeToList { chaptersQueries.getScanlatorsByMangaId(mangaId) { it.orEmpty() } }
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package dev.yokai.domain.chapter
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
interface ChapterRepository {
|
||||||
|
suspend fun getChapters(mangaId: Long, filterScanlators: Boolean): List<Chapter>
|
||||||
|
fun getChaptersAsFlow(mangaId: Long, filterScanlators: Boolean): Flow<List<Chapter>>
|
||||||
|
|
||||||
|
suspend fun getScanlatorsByChapter(mangaId: Long): List<String>
|
||||||
|
fun getScanlatorsByChapterAsFlow(mangaId: Long): Flow<List<String>>
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package dev.yokai.domain.chapter.interactor
|
||||||
|
|
||||||
|
import dev.yokai.domain.chapter.ChapterRepository
|
||||||
|
|
||||||
|
class GetAvailableScanlators(
|
||||||
|
private val chapterRepository: ChapterRepository,
|
||||||
|
) {
|
||||||
|
suspend fun await(mangaId: Long) = chapterRepository.getScanlatorsByChapter(mangaId)
|
||||||
|
fun subscribe(mangaId: Long) = chapterRepository.getScanlatorsByChapterAsFlow(mangaId)
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package dev.yokai.domain.chapter.interactor
|
||||||
|
|
||||||
|
import dev.yokai.domain.chapter.ChapterRepository
|
||||||
|
|
||||||
|
class GetChapters(
|
||||||
|
private val chapterRepository: ChapterRepository,
|
||||||
|
) {
|
||||||
|
suspend fun await(mangaId: Long, filterScanlators: Boolean) = chapterRepository.getChapters(mangaId, filterScanlators)
|
||||||
|
fun subscribe(mangaId: Long, filterScanlators: Boolean) = chapterRepository.getChaptersAsFlow(mangaId, filterScanlators)
|
||||||
|
|
||||||
|
}
|
|
@ -37,6 +37,36 @@ interface Chapter : SChapter, Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun mapper(
|
||||||
|
id: Long,
|
||||||
|
mangaId: Long,
|
||||||
|
url: String,
|
||||||
|
name: String,
|
||||||
|
scanlator: String?,
|
||||||
|
read: Boolean,
|
||||||
|
bookmark: Boolean,
|
||||||
|
lastPageRead: Long,
|
||||||
|
pagesLeft: Long,
|
||||||
|
chapterNumber: Double,
|
||||||
|
sourceOrder: Long,
|
||||||
|
dateFetch: Long,
|
||||||
|
dateUpload: Long,
|
||||||
|
): Chapter = create().apply {
|
||||||
|
this.id = id
|
||||||
|
this.manga_id = mangaId
|
||||||
|
this.url = url
|
||||||
|
this.name = name
|
||||||
|
this.scanlator = scanlator
|
||||||
|
this.read = read
|
||||||
|
this.bookmark = bookmark
|
||||||
|
this.last_page_read = lastPageRead.toInt()
|
||||||
|
this.pages_left = pagesLeft.toInt()
|
||||||
|
this.chapter_number = chapterNumber.toFloat()
|
||||||
|
this.source_order = sourceOrder.toInt()
|
||||||
|
this.date_fetch = dateFetch
|
||||||
|
this.date_upload = dateUpload
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun copyFrom(other: Chapter) {
|
fun copyFrom(other: Chapter) {
|
||||||
|
|
|
@ -13,8 +13,7 @@ class LibraryManga : MangaImpl() {
|
||||||
|
|
||||||
var bookmarkCount: Int = 0
|
var bookmarkCount: Int = 0
|
||||||
|
|
||||||
val totalChapters
|
var totalChapters: Int = 0
|
||||||
get() = read + unread
|
|
||||||
|
|
||||||
val hasRead
|
val hasRead
|
||||||
get() = read > 0
|
get() = read > 0
|
||||||
|
@ -79,6 +78,7 @@ class LibraryManga : MangaImpl() {
|
||||||
this.update_strategy = updateStrategy.toInt().let(updateStrategyAdapter::decode)
|
this.update_strategy = updateStrategy.toInt().let(updateStrategyAdapter::decode)
|
||||||
this.read = readCount.roundToInt()
|
this.read = readCount.roundToInt()
|
||||||
this.unread = maxOf((total - readCount).roundToInt(), 0)
|
this.unread = maxOf((total - readCount).roundToInt(), 0)
|
||||||
|
this.totalChapters = readCount.roundToInt()
|
||||||
this.bookmarkCount = bookmarkCount.roundToInt()
|
this.bookmarkCount = bookmarkCount.roundToInt()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package eu.kanade.tachiyomi.ui.library
|
package eu.kanade.tachiyomi.ui.library
|
||||||
|
|
||||||
|
import dev.yokai.domain.chapter.interactor.GetChapters
|
||||||
import dev.yokai.domain.manga.interactor.GetLibraryManga
|
import dev.yokai.domain.manga.interactor.GetLibraryManga
|
||||||
import dev.yokai.util.isLewd
|
import dev.yokai.util.isLewd
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
@ -75,6 +76,8 @@ class LibraryPresenter(
|
||||||
) : BaseCoroutinePresenter<LibraryController>(), DownloadQueue.DownloadListener {
|
) : BaseCoroutinePresenter<LibraryController>(), DownloadQueue.DownloadListener {
|
||||||
private val getLibraryManga: GetLibraryManga by injectLazy()
|
private val getLibraryManga: GetLibraryManga by injectLazy()
|
||||||
|
|
||||||
|
private val getChapters: GetChapters by injectLazy()
|
||||||
|
|
||||||
private val context = preferences.context
|
private val context = preferences.context
|
||||||
private val viewContext
|
private val viewContext
|
||||||
get() = view?.view?.context
|
get() = view?.view?.context
|
||||||
|
@ -1295,7 +1298,7 @@ class LibraryPresenter(
|
||||||
presenterScope.launch {
|
presenterScope.launch {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
mangaList.forEach { list ->
|
mangaList.forEach { list ->
|
||||||
val chapters = db.getChapters(list).executeAsBlocking().filter { !it.read }
|
val chapters = runBlocking { getChapters.await(list.id!!, true) }.filter { !it.read }
|
||||||
downloadManager.downloadChapters(list, chapters)
|
downloadManager.downloadChapters(list, chapters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1364,7 +1364,7 @@ class MangaDetailsController :
|
||||||
rangeMode = RangeMode.Download
|
rangeMode = RangeMode.Download
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
R.id.download_unread -> presenter.allChapters.filter { !it.read }
|
R.id.download_unread -> presenter.chapters.filter { !it.read }
|
||||||
R.id.download_all -> presenter.allChapters
|
R.id.download_all -> presenter.allChapters
|
||||||
else -> emptyList()
|
else -> emptyList()
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@ import coil3.request.CachePolicy
|
||||||
import coil3.request.ImageRequest
|
import coil3.request.ImageRequest
|
||||||
import coil3.request.SuccessResult
|
import coil3.request.SuccessResult
|
||||||
import com.hippo.unifile.UniFile
|
import com.hippo.unifile.UniFile
|
||||||
|
import dev.yokai.domain.chapter.interactor.GetAvailableScanlators
|
||||||
|
import dev.yokai.domain.chapter.interactor.GetChapters
|
||||||
import dev.yokai.domain.library.custom.model.CustomMangaInfo
|
import dev.yokai.domain.library.custom.model.CustomMangaInfo
|
||||||
import dev.yokai.domain.storage.StorageManager
|
import dev.yokai.domain.storage.StorageManager
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
import eu.kanade.tachiyomi.BuildConfig
|
||||||
|
@ -88,6 +90,8 @@ class MangaDetailsPresenter(
|
||||||
chapterFilter: ChapterFilter = Injekt.get(),
|
chapterFilter: ChapterFilter = Injekt.get(),
|
||||||
internal val storageManager: StorageManager = Injekt.get(),
|
internal val storageManager: StorageManager = Injekt.get(),
|
||||||
) : BaseCoroutinePresenter<MangaDetailsController>(), DownloadQueue.DownloadListener {
|
) : BaseCoroutinePresenter<MangaDetailsController>(), DownloadQueue.DownloadListener {
|
||||||
|
private val getAvailableScanlators: GetAvailableScanlators by injectLazy()
|
||||||
|
private val getChapters: GetChapters by injectLazy()
|
||||||
|
|
||||||
private val customMangaManager: CustomMangaManager by injectLazy()
|
private val customMangaManager: CustomMangaManager by injectLazy()
|
||||||
private val mangaShortcutManager: MangaShortcutManager by injectLazy()
|
private val mangaShortcutManager: MangaShortcutManager by injectLazy()
|
||||||
|
@ -118,6 +122,7 @@ class MangaDetailsPresenter(
|
||||||
val headerItem by lazy { MangaHeaderItem(manga, view?.fromCatalogue == true) }
|
val headerItem by lazy { MangaHeaderItem(manga, view?.fromCatalogue == true) }
|
||||||
var tabletChapterHeaderItem: MangaHeaderItem? = null
|
var tabletChapterHeaderItem: MangaHeaderItem? = null
|
||||||
var allChapterScanlators: Set<String> = emptySet()
|
var allChapterScanlators: Set<String> = emptySet()
|
||||||
|
|
||||||
fun onFirstLoad() {
|
fun onFirstLoad() {
|
||||||
val controller = view ?: return
|
val controller = view ?: return
|
||||||
headerItem.isTablet = controller.isTablet
|
headerItem.isTablet = controller.isTablet
|
||||||
|
@ -170,13 +175,18 @@ class MangaDetailsPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getChapters() {
|
private suspend fun getChapters() {
|
||||||
val chapters = db.getChapters(manga).executeOnIO().map { it.toModel() }
|
val chapters = getChapters.await(manga.id!!, isScanlatorFiltered()).map { it.toModel() }
|
||||||
|
|
||||||
// Find downloaded chapters
|
// Find downloaded chapters
|
||||||
setDownloadedChapters(chapters)
|
setDownloadedChapters(chapters)
|
||||||
allChapterScanlators = chapters.flatMap { ChapterUtil.getScanlators(it.chapter.scanlator) }.toSet()
|
allChapterScanlators =
|
||||||
|
if (!isScanlatorFiltered()) {
|
||||||
|
chapters.flatMap { ChapterUtil.getScanlators(it.chapter.scanlator) }
|
||||||
|
} else {
|
||||||
|
getAvailableScanlators.await(manga.id!!)
|
||||||
|
}.toSet()
|
||||||
// Store the last emission
|
// Store the last emission
|
||||||
allChapters = chapters
|
allChapters = if (!isScanlatorFiltered()) chapters else getChapters.await(manga.id!!, false).map { it.toModel() }
|
||||||
this.chapters = applyChapterFilters(chapters)
|
this.chapters = applyChapterFilters(chapters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,7 +293,7 @@ class MangaDetailsPresenter(
|
||||||
fun hasDownloads(): Boolean = allChapters.any { it.isDownloaded }
|
fun hasDownloads(): Boolean = allChapters.any { it.isDownloaded }
|
||||||
|
|
||||||
fun getUnreadChaptersSorted() =
|
fun getUnreadChaptersSorted() =
|
||||||
allChapters.filter { !it.read && it.status == Download.State.NOT_DOWNLOADED }.distinctBy { it.name }
|
chapters.filter { !it.read && it.status == Download.State.NOT_DOWNLOADED }.distinctBy { it.name }
|
||||||
.sortedWith(chapterSort.sortComparator(true))
|
.sortedWith(chapterSort.sortComparator(true))
|
||||||
|
|
||||||
fun startDownloadingNow(chapter: Chapter) {
|
fun startDownloadingNow(chapter: Chapter) {
|
||||||
|
@ -664,6 +674,8 @@ class MangaDetailsPresenter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isScanlatorFiltered() = manga.filtered_scanlators?.isNotEmpty() == true
|
||||||
|
|
||||||
fun currentFilters(): String {
|
fun currentFilters(): String {
|
||||||
val filtersId = mutableListOf<Int?>()
|
val filtersId = mutableListOf<Int?>()
|
||||||
filtersId.add(if (manga.readFilter(preferences) == Manga.CHAPTER_SHOW_READ) R.string.read else null)
|
filtersId.add(if (manga.readFilter(preferences) == Manga.CHAPTER_SHOW_READ) R.string.read else null)
|
||||||
|
@ -672,7 +684,7 @@ class MangaDetailsPresenter(
|
||||||
filtersId.add(if (manga.downloadedFilter(preferences) == Manga.CHAPTER_SHOW_NOT_DOWNLOADED) R.string.not_downloaded else null)
|
filtersId.add(if (manga.downloadedFilter(preferences) == Manga.CHAPTER_SHOW_NOT_DOWNLOADED) R.string.not_downloaded else null)
|
||||||
filtersId.add(if (manga.bookmarkedFilter(preferences) == Manga.CHAPTER_SHOW_BOOKMARKED) R.string.bookmarked else null)
|
filtersId.add(if (manga.bookmarkedFilter(preferences) == Manga.CHAPTER_SHOW_BOOKMARKED) R.string.bookmarked else null)
|
||||||
filtersId.add(if (manga.bookmarkedFilter(preferences) == Manga.CHAPTER_SHOW_NOT_BOOKMARKED) R.string.not_bookmarked else null)
|
filtersId.add(if (manga.bookmarkedFilter(preferences) == Manga.CHAPTER_SHOW_NOT_BOOKMARKED) R.string.not_bookmarked else null)
|
||||||
filtersId.add(if (manga.filtered_scanlators?.isNotEmpty() == true) R.string.scanlators else null)
|
filtersId.add(if (isScanlatorFiltered()) R.string.scanlators else null)
|
||||||
return filtersId.filterNotNull()
|
return filtersId.filterNotNull()
|
||||||
.joinToString(", ") { view?.view?.context?.getString(it) ?: "" }
|
.joinToString(", ") { view?.view?.context?.getString(it) ?: "" }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
package eu.kanade.tachiyomi.util.system
|
package eu.kanade.tachiyomi.util.system
|
||||||
|
|
||||||
fun Boolean.toInt() = if (this) 1 else 0
|
fun Boolean.toInt() = if (this) 1 else 0
|
||||||
|
fun Int.toBoolean() = this == 1
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
import kotlin.Boolean;
|
import kotlin.Boolean;
|
||||||
import kotlin.Float;
|
|
||||||
import kotlin.Long;
|
|
||||||
|
|
||||||
CREATE TABLE chapters(
|
CREATE TABLE chapters(
|
||||||
_id INTEGER NOT NULL PRIMARY KEY,
|
_id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
@ -12,13 +10,29 @@ CREATE TABLE chapters(
|
||||||
bookmark INTEGER AS Boolean NOT NULL,
|
bookmark INTEGER AS Boolean NOT NULL,
|
||||||
last_page_read INTEGER NOT NULL,
|
last_page_read INTEGER NOT NULL,
|
||||||
pages_left INTEGER NOT NULL,
|
pages_left INTEGER NOT NULL,
|
||||||
chapter_number REAL AS Float NOT NULL,
|
chapter_number REAL NOT NULL,
|
||||||
source_order INTEGER NOT NULL,
|
source_order INTEGER NOT NULL,
|
||||||
date_fetch INTEGER AS Long NOT NULL,
|
date_fetch INTEGER NOT NULL,
|
||||||
date_upload INTEGER AS Long NOT NULL,
|
date_upload INTEGER NOT NULL,
|
||||||
FOREIGN KEY(manga_id) REFERENCES mangas (_id)
|
FOREIGN KEY(manga_id) REFERENCES mangas (_id)
|
||||||
ON DELETE CASCADE
|
ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX chapters_manga_id_index ON chapters(manga_id);
|
CREATE INDEX chapters_manga_id_index ON chapters(manga_id);
|
||||||
CREATE INDEX chapters_unread_by_manga_index ON chapters(manga_id, read) WHERE read = 0;
|
CREATE INDEX chapters_unread_by_manga_index ON chapters(manga_id, read) WHERE read = 0;
|
||||||
|
|
||||||
|
getChaptersByMangaId:
|
||||||
|
SELECT C.*
|
||||||
|
FROM chapters AS C
|
||||||
|
LEFT JOIN scanlators_view AS S
|
||||||
|
ON C.manga_id = S.manga_id
|
||||||
|
AND ifnull(C.scanlator, 'N/A') = ifnull(S.name, '/<INVALID>/') -- I assume if it's N/A it shouldn't be filtered
|
||||||
|
WHERE C.manga_id = :manga_id
|
||||||
|
AND (
|
||||||
|
:apply_filter = 0 OR S.name IS NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
getScanlatorsByMangaId:
|
||||||
|
SELECT scanlator
|
||||||
|
FROM chapters
|
||||||
|
WHERE manga_id = :mangaId;
|
||||||
|
|
41
app/src/main/sqldelight/tachiyomi/migrations/22.sqm
Normal file
41
app/src/main/sqldelight/tachiyomi/migrations/22.sqm
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
CREATE VIEW scanlators_view AS
|
||||||
|
SELECT S.* FROM (
|
||||||
|
WITH RECURSIVE split(seq, _id, name, str) AS ( -- Probably should migrate this to its own table someday
|
||||||
|
SELECT 0, mangas._id, NULL, replace(ifnull(mangas.filtered_scanlators, ''), ' & ', '[.]')||'[.]' FROM mangas WHERE mangas._id
|
||||||
|
UNION ALL SELECT
|
||||||
|
seq+1,
|
||||||
|
_id,
|
||||||
|
substr(str, 0, instr(str, '[.]')),
|
||||||
|
substr(str, instr(str, '[.]')+3)
|
||||||
|
FROM split WHERE str != ''
|
||||||
|
)
|
||||||
|
SELECT _id AS manga_id, name FROM split WHERE split.seq != 0 ORDER BY split.seq ASC
|
||||||
|
) AS S;
|
||||||
|
|
||||||
|
DROP VIEW IF EXISTS library_view;
|
||||||
|
CREATE VIEW library_view AS
|
||||||
|
SELECT
|
||||||
|
M.*,
|
||||||
|
coalesce(C.total, 0) AS total,
|
||||||
|
coalesce(C.read_count, 0) AS has_read,
|
||||||
|
coalesce(C.bookmark_count, 0) AS bookmark_count,
|
||||||
|
coalesce(MC.category_id, 0) AS category
|
||||||
|
FROM mangas AS M
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT
|
||||||
|
chapters.manga_id,
|
||||||
|
count(*) AS total,
|
||||||
|
sum(read) AS read_count,
|
||||||
|
sum(bookmark) AS bookmark_count
|
||||||
|
FROM chapters
|
||||||
|
LEFT JOIN scanlators_view AS filtered_scanlators
|
||||||
|
ON chapters.manga_id = filtered_scanlators.manga_id
|
||||||
|
AND ifnull(chapters.scanlator, 'N/A') = ifnull(filtered_scanlators.name, '/<INVALID>/')
|
||||||
|
WHERE filtered_scanlators.name IS NULL
|
||||||
|
GROUP BY chapters.manga_id
|
||||||
|
) AS C
|
||||||
|
ON M._id = C.manga_id
|
||||||
|
LEFT JOIN (SELECT * FROM mangas_categories) AS MC
|
||||||
|
ON MC.manga_id = M._id
|
||||||
|
WHERE M.favorite = 1
|
||||||
|
ORDER BY M.title;
|
|
@ -13,18 +13,8 @@ LEFT JOIN (
|
||||||
sum(read) AS read_count,
|
sum(read) AS read_count,
|
||||||
sum(bookmark) AS bookmark_count
|
sum(bookmark) AS bookmark_count
|
||||||
FROM chapters
|
FROM chapters
|
||||||
LEFT JOIN (
|
LEFT JOIN scanlators_view AS filtered_scanlators
|
||||||
WITH RECURSIVE split(seq, _id, name, str) AS ( -- Probably should migrate this to its own table someday
|
ON chapters.manga_id = filtered_scanlators.manga_id
|
||||||
SELECT 0, mangas._id, NULL, replace(ifnull(mangas.filtered_scanlators, ''), ' & ', '[.]')||'[.]' FROM mangas
|
|
||||||
UNION ALL SELECT
|
|
||||||
seq+1,
|
|
||||||
_id,
|
|
||||||
substr(str, 0, instr(str, '[.]')),
|
|
||||||
substr(str, instr(str, '[.]')+3)
|
|
||||||
FROM split WHERE str != ''
|
|
||||||
) SELECT _id, name FROM split WHERE split.seq != 0 ORDER BY split.seq ASC
|
|
||||||
) AS filtered_scanlators
|
|
||||||
ON chapters.manga_id = filtered_scanlators._id
|
|
||||||
AND ifnull(chapters.scanlator, 'N/A') = ifnull(filtered_scanlators.name, '/<INVALID>/') -- I assume if it's N/A it shouldn't be filtered
|
AND ifnull(chapters.scanlator, 'N/A') = ifnull(filtered_scanlators.name, '/<INVALID>/') -- I assume if it's N/A it shouldn't be filtered
|
||||||
WHERE filtered_scanlators.name IS NULL
|
WHERE filtered_scanlators.name IS NULL
|
||||||
GROUP BY chapters.manga_id
|
GROUP BY chapters.manga_id
|
||||||
|
|
13
app/src/main/sqldelight/tachiyomi/view/scanlators_view.sq
Normal file
13
app/src/main/sqldelight/tachiyomi/view/scanlators_view.sq
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
CREATE VIEW scanlators_view AS
|
||||||
|
SELECT S.* FROM (
|
||||||
|
WITH RECURSIVE split(seq, _id, name, str) AS ( -- Probably should migrate this to its own table someday
|
||||||
|
SELECT 0, mangas._id, NULL, replace(ifnull(mangas.filtered_scanlators, ''), ' & ', '[.]')||'[.]' FROM mangas WHERE mangas._id
|
||||||
|
UNION ALL SELECT
|
||||||
|
seq+1,
|
||||||
|
_id,
|
||||||
|
substr(str, 0, instr(str, '[.]')),
|
||||||
|
substr(str, instr(str, '[.]')+3)
|
||||||
|
FROM split WHERE str != ''
|
||||||
|
)
|
||||||
|
SELECT _id AS manga_id, name FROM split WHERE split.seq != 0 ORDER BY split.seq ASC
|
||||||
|
) AS S;
|
Loading…
Add table
Add a link
Reference in a new issue