Implement scanlator filter (#8803)
* Implement scanlator filter * Visual improvement to scanlator filter dialog * Review changes + Bug fixes Backup not containing filtered chapters and similar issue fix * Review Changes + Fix SQL query * Lint mamma mia (cherry picked from commit b97aa235480e35b5514b7b1489b9d4413cea66d9) # Conflicts: # app/build.gradle.kts # app/src/main/java/eu/kanade/presentation/manga/ChapterSettingsDialog.kt # app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt # app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt # app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt # app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt # app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt # data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt # data/src/main/sqldelight/tachiyomi/migrations/23.sqm # data/src/main/sqldelight/tachiyomi/migrations/26.sqm # domain/src/main/java/tachiyomi/domain/history/interactor/GetNextChapters.kt
This commit is contained in:
@@ -27,16 +27,3 @@ object UpdateStrategyColumnAdapter : ColumnAdapter<UpdateStrategy, Long> {
|
||||
|
||||
override fun encode(value: UpdateStrategy): Long = value.ordinal.toLong()
|
||||
}
|
||||
|
||||
// SY -->
|
||||
private const val LIST_OF_STRINGS_AND_SEPARATOR = " & "
|
||||
object StringListAndColumnAdapter : ColumnAdapter<List<String>, String> {
|
||||
override fun decode(databaseValue: String) =
|
||||
if (databaseValue.isEmpty()) {
|
||||
emptyList()
|
||||
} else {
|
||||
databaseValue.split(LIST_OF_STRINGS_AND_SEPARATOR)
|
||||
}
|
||||
override fun encode(value: List<String>) = value.joinToString(separator = LIST_OF_STRINGS_AND_SEPARATOR)
|
||||
}
|
||||
// SY <--
|
||||
|
||||
@@ -27,7 +27,7 @@ private val mapper = { cursor: SqlCursor ->
|
||||
chapter_flags = cursor.getLong(15)!!,
|
||||
cover_last_modified = cursor.getLong(16)!!,
|
||||
date_added = cursor.getLong(17)!!,
|
||||
filtered_scanlators = cursor.getString(18)?.let(StringListAndColumnAdapter::decode),
|
||||
filtered_scanlators = null,
|
||||
update_strategy = UpdateStrategyColumnAdapter.decode(cursor.getLong(19)!!),
|
||||
calculate_interval = cursor.getLong(20)!!,
|
||||
last_modified_at = cursor.getLong(21)!!,
|
||||
@@ -71,8 +71,12 @@ class LibraryQuery(
|
||||
coalesce(max(chapters.date_fetch), 0) AS fetchedAt,
|
||||
sum(chapters.bookmark) AS bookmarkCount
|
||||
FROM chapters
|
||||
LEFT JOIN excluded_scanlators
|
||||
ON chapters.manga_id = excluded_scanlators.manga_id
|
||||
AND chapters.scanlator = excluded_scanlators.scanlator
|
||||
LEFT JOIN history
|
||||
ON chapters._id = history.chapter_id
|
||||
WHERE excluded_scanlators.scanlator IS NULL
|
||||
GROUP BY chapters.manga_id
|
||||
) AS C
|
||||
ON M._id = C.manga_id
|
||||
@@ -106,10 +110,14 @@ class LibraryQuery(
|
||||
coalesce(max(chapters.date_fetch), 0) AS fetchedAt,
|
||||
sum(chapters.bookmark) AS bookmarkCount
|
||||
FROM chapters
|
||||
LEFT JOIN excluded_scanlators
|
||||
ON chapters.manga_id = excluded_scanlators.manga_id
|
||||
AND chapters.scanlator = excluded_scanlators.scanlator
|
||||
LEFT JOIN history
|
||||
ON chapters._id = history.chapter_id
|
||||
LEFT JOIN merged as ME
|
||||
ON ME.manga_id = chapters.manga_id
|
||||
WHERE excluded_scanlators.scanlator IS NULL
|
||||
GROUP BY ME.merge_id
|
||||
) AS C
|
||||
ON ME.merge_id = C.merge_id
|
||||
|
||||
@@ -2,6 +2,7 @@ package tachiyomi.data.chapter
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.util.lang.toLong
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.data.DatabaseHandler
|
||||
import tachiyomi.domain.chapter.model.Chapter
|
||||
@@ -76,8 +77,22 @@ class ChapterRepositoryImpl(
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getChapterByMangaId(mangaId: Long): List<Chapter> {
|
||||
return handler.awaitList { chaptersQueries.getChaptersByMangaId(mangaId, ChapterMapper::mapChapter) }
|
||||
override suspend fun getChapterByMangaId(mangaId: Long, applyScanlatorFilter: Boolean): List<Chapter> {
|
||||
return handler.awaitList {
|
||||
chaptersQueries.getChaptersByMangaId(mangaId, applyScanlatorFilter.toLong(), ChapterMapper::mapChapter)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getScanlatorsByMangaId(mangaId: Long): List<String> {
|
||||
return handler.awaitList {
|
||||
chaptersQueries.getScanlatorsByMangaId(mangaId) { it.orEmpty() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun getScanlatorsByMangaIdAsFlow(mangaId: Long): Flow<List<String>> {
|
||||
return handler.subscribeToList {
|
||||
chaptersQueries.getScanlatorsByMangaId(mangaId) { it.orEmpty() }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getBookmarkedChaptersByMangaId(mangaId: Long): List<Chapter> {
|
||||
@@ -93,12 +108,9 @@ class ChapterRepositoryImpl(
|
||||
return handler.awaitOneOrNull { chaptersQueries.getChapterById(id, ChapterMapper::mapChapter) }
|
||||
}
|
||||
|
||||
override suspend fun getChapterByMangaIdAsFlow(mangaId: Long): Flow<List<Chapter>> {
|
||||
override suspend fun getChapterByMangaIdAsFlow(mangaId: Long, applyScanlatorFilter: Boolean): Flow<List<Chapter>> {
|
||||
return handler.subscribeToList {
|
||||
chaptersQueries.getChaptersByMangaId(
|
||||
mangaId,
|
||||
ChapterMapper::mapChapter,
|
||||
)
|
||||
chaptersQueries.getChaptersByMangaId(mangaId, applyScanlatorFilter.toLong(), ChapterMapper::mapChapter)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,13 +129,13 @@ class ChapterRepositoryImpl(
|
||||
return handler.awaitList { chaptersQueries.getChapterByUrl(url, ChapterMapper::mapChapter) }
|
||||
}
|
||||
|
||||
override suspend fun getMergedChapterByMangaId(mangaId: Long): List<Chapter> {
|
||||
return handler.awaitList { chaptersQueries.getMergedChaptersByMangaId(mangaId, ChapterMapper::mapChapter) }
|
||||
override suspend fun getMergedChapterByMangaId(mangaId: Long, applyScanlatorFilter: Boolean): List<Chapter> {
|
||||
return handler.awaitList { chaptersQueries.getMergedChaptersByMangaId(mangaId, applyScanlatorFilter.toLong(), ChapterMapper::mapChapter) }
|
||||
}
|
||||
|
||||
override suspend fun getMergedChapterByMangaIdAsFlow(mangaId: Long): Flow<List<Chapter>> {
|
||||
override suspend fun getMergedChapterByMangaIdAsFlow(mangaId: Long, applyScanlatorFilter: Boolean): Flow<List<Chapter>> {
|
||||
return handler.subscribeToList {
|
||||
chaptersQueries.getMergedChaptersByMangaId(mangaId, ChapterMapper::mapChapter)
|
||||
chaptersQueries.getMergedChaptersByMangaId(mangaId, applyScanlatorFilter.toLong(), ChapterMapper::mapChapter)
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
|
||||
@@ -25,7 +25,10 @@ object MangaMapper {
|
||||
chapterFlags: Long,
|
||||
coverLastModified: Long,
|
||||
dateAdded: Long,
|
||||
filteredScanlators: List<String>?,
|
||||
// SY -->
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
filteredScanlators: String?,
|
||||
// SY <--
|
||||
updateStrategy: UpdateStrategy,
|
||||
calculateInterval: Long,
|
||||
lastModifiedAt: Long,
|
||||
@@ -53,9 +56,6 @@ object MangaMapper {
|
||||
thumbnailUrl = thumbnailUrl,
|
||||
updateStrategy = updateStrategy,
|
||||
initialized = initialized,
|
||||
// SY -->
|
||||
filteredScanlators = filteredScanlators,
|
||||
// SY <--
|
||||
lastModifiedAt = lastModifiedAt,
|
||||
favoriteModifiedAt = favoriteModifiedAt,
|
||||
)
|
||||
@@ -79,7 +79,10 @@ object MangaMapper {
|
||||
chapterFlags: Long,
|
||||
coverLastModified: Long,
|
||||
dateAdded: Long,
|
||||
filteredScanlators: List<String>?,
|
||||
// SY -->
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
filteredScanlators: String?,
|
||||
// SY <--
|
||||
updateStrategy: UpdateStrategy,
|
||||
calculateInterval: Long,
|
||||
lastModifiedAt: Long,
|
||||
@@ -112,7 +115,7 @@ object MangaMapper {
|
||||
coverLastModified,
|
||||
dateAdded,
|
||||
// SY -->
|
||||
filteredScanlators,
|
||||
null,
|
||||
// SY <--
|
||||
updateStrategy,
|
||||
calculateInterval,
|
||||
@@ -150,7 +153,6 @@ object MangaMapper {
|
||||
thumbnailUrl = libraryView.thumbnail_url,
|
||||
updateStrategy = libraryView.update_strategy,
|
||||
initialized = libraryView.initialized,
|
||||
filteredScanlators = libraryView.filtered_scanlators,
|
||||
fetchInterval = libraryView.calculate_interval.toInt(),
|
||||
lastModifiedAt = libraryView.last_modified_at,
|
||||
favoriteModifiedAt = libraryView.favorite_modified_at,
|
||||
|
||||
@@ -6,7 +6,6 @@ import logcat.LogPriority
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.data.AndroidDatabaseHandler
|
||||
import tachiyomi.data.DatabaseHandler
|
||||
import tachiyomi.data.StringListAndColumnAdapter
|
||||
import tachiyomi.data.StringListColumnAdapter
|
||||
import tachiyomi.data.UpdateStrategyColumnAdapter
|
||||
import tachiyomi.domain.library.model.LibraryManga
|
||||
@@ -119,9 +118,6 @@ class MangaRepositoryImpl(
|
||||
chapterFlags = manga.chapterFlags,
|
||||
coverLastModified = manga.coverLastModified,
|
||||
dateAdded = manga.dateAdded,
|
||||
// SY -->
|
||||
filteredScanlators = manga.filteredScanlators,
|
||||
// SY <--
|
||||
updateStrategy = manga.updateStrategy,
|
||||
)
|
||||
mangasQueries.selectLastInsertedRowId()
|
||||
@@ -170,9 +166,6 @@ class MangaRepositoryImpl(
|
||||
chapterFlags = value.chapterFlags,
|
||||
coverLastModified = value.coverLastModified,
|
||||
dateAdded = value.dateAdded,
|
||||
// SY -->
|
||||
filteredScanlators = value.filteredScanlators?.let(StringListAndColumnAdapter::encode),
|
||||
// SY <--
|
||||
mangaId = value.id,
|
||||
updateStrategy = value.updateStrategy?.let(UpdateStrategyColumnAdapter::encode),
|
||||
)
|
||||
|
||||
@@ -36,7 +36,19 @@ FROM chapters
|
||||
WHERE _id = :id;
|
||||
|
||||
getChaptersByMangaId:
|
||||
SELECT *
|
||||
SELECT C.*
|
||||
FROM chapters C
|
||||
LEFT JOIN excluded_scanlators ES
|
||||
ON C.manga_id = ES.manga_id
|
||||
AND C.scanlator = ES.scanlator
|
||||
WHERE C.manga_id = :mangaId
|
||||
AND (
|
||||
:applyScanlatorFilter = 0
|
||||
OR ES.scanlator IS NULL
|
||||
);
|
||||
|
||||
getScanlatorsByMangaId:
|
||||
SELECT scanlator
|
||||
FROM chapters
|
||||
WHERE manga_id = :mangaId;
|
||||
|
||||
@@ -58,12 +70,20 @@ WHERE url = :chapterUrl
|
||||
AND manga_id = :mangaId;
|
||||
|
||||
getMergedChaptersByMangaId:
|
||||
SELECT chapters.*
|
||||
FROM (
|
||||
SELECT manga_id FROM merged WHERE merge_id = ?
|
||||
SELECT C.*
|
||||
FROM chapters C
|
||||
JOIN (
|
||||
SELECT manga_id FROM merged WHERE merge_id = :mangaId
|
||||
) AS M
|
||||
JOIN chapters
|
||||
ON chapters.manga_id = M.manga_id;
|
||||
ON C.manga_id = M.manga_id
|
||||
LEFT JOIN excluded_scanlators ES
|
||||
ON C.manga_id = ES.manga_id
|
||||
AND C.scanlator = ES.scanlator
|
||||
WHERE C.manga_id = :mangaId
|
||||
AND (
|
||||
:applyScanlatorFilter = 0
|
||||
OR ES.scanlator IS NULL
|
||||
);
|
||||
|
||||
removeChaptersWithIds:
|
||||
DELETE FROM chapters
|
||||
|
||||
@@ -9,10 +9,6 @@ WHERE source = :oldId;
|
||||
getChaptersByMangaIds:
|
||||
SELECT * FROM chapters WHERE manga_id IN :mangaIds;
|
||||
|
||||
resetFilteredScanlatorsForAllManga:
|
||||
UPDATE mangas
|
||||
SET filtered_scanlators = NULL;
|
||||
|
||||
migrateAllNhentaiToOtherLang:
|
||||
UPDATE mangas
|
||||
SET source = :nh
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
CREATE TABLE excluded_scanlators(
|
||||
manga_id INTEGER NOT NULL,
|
||||
scanlator TEXT NOT NULL,
|
||||
FOREIGN KEY(manga_id) REFERENCES mangas (_id)
|
||||
ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX excluded_scanlators_manga_id_index ON excluded_scanlators(manga_id);
|
||||
|
||||
insert:
|
||||
INSERT INTO excluded_scanlators(manga_id, scanlator)
|
||||
VALUES (:mangaId, :scanlator);
|
||||
|
||||
remove:
|
||||
DELETE FROM excluded_scanlators
|
||||
WHERE manga_id = :mangaId
|
||||
AND scanlator IN :scanlators;
|
||||
|
||||
getExcludedScanlatorsByMangaId:
|
||||
SELECT scanlator
|
||||
FROM excluded_scanlators
|
||||
WHERE manga_id = :mangaId;
|
||||
@@ -22,7 +22,7 @@ CREATE TABLE mangas(
|
||||
chapter_flags INTEGER NOT NULL,
|
||||
cover_last_modified INTEGER NOT NULL,
|
||||
date_added INTEGER NOT NULL,
|
||||
filtered_scanlators TEXT AS List<String>,
|
||||
filtered_scanlators TEXT,
|
||||
update_strategy INTEGER AS UpdateStrategy NOT NULL DEFAULT 0,
|
||||
calculate_interval INTEGER DEFAULT 0 NOT NULL,
|
||||
last_modified_at INTEGER NOT NULL DEFAULT 0,
|
||||
@@ -131,8 +131,8 @@ WHERE favorite = 0 AND source IN :sourceIdsAND AND _id NOT IN (
|
||||
);
|
||||
|
||||
insert:
|
||||
INSERT INTO mangas(source, url, artist, author, description, genre, title, status, thumbnail_url, favorite, last_update, next_update, initialized, viewer, chapter_flags, cover_last_modified, date_added, filtered_scanlators, update_strategy, calculate_interval, last_modified_at)
|
||||
VALUES (:source, :url, :artist, :author, :description, :genre, :title, :status, :thumbnailUrl, :favorite, :lastUpdate, :nextUpdate, :initialized, :viewerFlags, :chapterFlags, :coverLastModified, :dateAdded, :filteredScanlators, :updateStrategy, :calculateInterval, strftime('%s', 'now'));
|
||||
INSERT INTO mangas(source, url, artist, author, description, genre, title, status, thumbnail_url, favorite, last_update, next_update, initialized, viewer, chapter_flags, cover_last_modified, date_added, update_strategy, calculate_interval, last_modified_at)
|
||||
VALUES (:source, :url, :artist, :author, :description, :genre, :title, :status, :thumbnailUrl, :favorite, :lastUpdate, :nextUpdate, :initialized, :viewerFlags, :chapterFlags, :coverLastModified, :dateAdded, :updateStrategy, :calculateInterval, strftime('%s', 'now'));
|
||||
|
||||
update:
|
||||
UPDATE mangas SET
|
||||
@@ -153,7 +153,6 @@ UPDATE mangas SET
|
||||
chapter_flags = coalesce(:chapterFlags, chapter_flags),
|
||||
cover_last_modified = coalesce(:coverLastModified, cover_last_modified),
|
||||
date_added = coalesce(:dateAdded, date_added),
|
||||
filtered_scanlators = coalesce(:filteredScanlators, filtered_scanlators),
|
||||
update_strategy = coalesce(:updateStrategy, update_strategy),
|
||||
calculate_interval = coalesce(:calculateInterval, calculate_interval)
|
||||
WHERE _id = :mangaId;
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
CREATE TABLE excluded_scanlators(
|
||||
manga_id INTEGER NOT NULL,
|
||||
scanlator TEXT NOT NULL,
|
||||
FOREIGN KEY(manga_id) REFERENCES mangas (_id)
|
||||
ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX excluded_scanlators_manga_id_index ON excluded_scanlators(manga_id);
|
||||
|
||||
DROP VIEW IF EXISTS libraryView;
|
||||
|
||||
CREATE VIEW libraryView AS
|
||||
SELECT
|
||||
M.*,
|
||||
coalesce(C.total, 0) AS totalCount,
|
||||
coalesce(C.readCount, 0) AS readCount,
|
||||
coalesce(C.latestUpload, 0) AS latestUpload,
|
||||
coalesce(C.fetchedAt, 0) AS chapterFetchedAt,
|
||||
coalesce(C.lastRead, 0) AS lastRead,
|
||||
coalesce(C.bookmarkCount, 0) AS bookmarkCount,
|
||||
coalesce(MC.category_id, 0) AS category
|
||||
FROM mangas M
|
||||
LEFT JOIN(
|
||||
SELECT
|
||||
chapters.manga_id,
|
||||
count(*) AS total,
|
||||
sum(read) AS readCount,
|
||||
coalesce(max(chapters.date_upload), 0) AS latestUpload,
|
||||
coalesce(max(history.last_read), 0) AS lastRead,
|
||||
coalesce(max(chapters.date_fetch), 0) AS fetchedAt,
|
||||
sum(chapters.bookmark) AS bookmarkCount
|
||||
FROM chapters
|
||||
LEFT JOIN excluded_scanlators
|
||||
ON chapters.manga_id = excluded_scanlators.manga_id
|
||||
AND chapters.scanlator = excluded_scanlators.scanlator
|
||||
LEFT JOIN history
|
||||
ON chapters._id = history.chapter_id
|
||||
WHERE excluded_scanlators.scanlator IS NULL
|
||||
GROUP BY chapters.manga_id
|
||||
) AS C
|
||||
ON M._id = C.manga_id
|
||||
LEFT JOIN mangas_categories AS MC
|
||||
ON MC.manga_id = M._id
|
||||
WHERE M.favorite = 1;
|
||||
@@ -19,8 +19,12 @@ LEFT JOIN(
|
||||
coalesce(max(chapters.date_fetch), 0) AS fetchedAt,
|
||||
sum(chapters.bookmark) AS bookmarkCount
|
||||
FROM chapters
|
||||
LEFT JOIN excluded_scanlators
|
||||
ON chapters.manga_id = excluded_scanlators.manga_id
|
||||
AND chapters.scanlator = excluded_scanlators.scanlator
|
||||
LEFT JOIN history
|
||||
ON chapters._id = history.chapter_id
|
||||
WHERE excluded_scanlators.scanlator IS NULL
|
||||
GROUP BY chapters.manga_id
|
||||
) AS C
|
||||
ON M._id = C.manga_id
|
||||
|
||||
Reference in New Issue
Block a user