From 6e3670ef7540ccb79bb015351f3c04fecaa6135a Mon Sep 17 00:00:00 2001 From: FlaminSarge Date: Thu, 8 May 2025 15:09:32 -0700 Subject: [PATCH] Add advanced option to always update manga title from source (mihonapp/mihon#1182) Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> (cherry picked from commit 8b45ef0e5d5d368e0925df9816ae423defaed4d9) --- CHANGELOG.md | 1 + .../domain/manga/interactor/UpdateManga.kt | 25 ++++++------ .../settings/screen/SettingsAdvancedScreen.kt | 13 ++++++- .../tachiyomi/data/download/DownloadCache.kt | 35 +++++++++++++++++ .../data/download/DownloadManager.kt | 39 +++++++++++++++---- .../library/service/LibraryPreferences.kt | 2 + .../moko-resources/base/strings.xml | 2 + 7 files changed, 97 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e65a3ded..c0bb2a19c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co - Use Github markdown flavour for Github releases & fix bullet list alignment ([@Secozzi](https://github.com/Secozzi)) ([#2024](https://github.com/mihonapp/mihon/pull/2024)) - Add Nord Theme ([@Riztard](https://github.com/Riztard)) ([#1951](https://github.com/mihonapp/mihon/pull/1951)) - Option to keep read manga when clearing database ([@AwkwardPeak7](https://github.com/AwkwardPeak7)) ([#1979](https://github.com/mihonapp/mihon/pull/1979)) +- Add advanced option to always update manga title from source ([@FlaminSarge](https://github.com/FlaminSarge)) ([#1182](https://github.com/mihonapp/mihon/pull/1182)) ### Improved - Significantly improve browsing speed (near instantaneous) ([@AntsyLich](https://github.com/AntsyLich)) ([#1946](https://github.com/mihonapp/mihon/pull/1946)) diff --git a/app/src/main/java/eu/kanade/domain/manga/interactor/UpdateManga.kt b/app/src/main/java/eu/kanade/domain/manga/interactor/UpdateManga.kt index 9aa7d7d1f..7117e07af 100644 --- a/app/src/main/java/eu/kanade/domain/manga/interactor/UpdateManga.kt +++ b/app/src/main/java/eu/kanade/domain/manga/interactor/UpdateManga.kt @@ -4,6 +4,7 @@ import eu.kanade.domain.manga.model.hasCustomCover import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.source.model.SManga +import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.domain.manga.interactor.FetchInterval import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.MangaUpdate @@ -32,9 +33,8 @@ class UpdateManga( remoteManga: SManga, manualFetch: Boolean, coverCache: CoverCache = Injekt.get(), - // SY --> + libraryPreferences: LibraryPreferences = Injekt.get(), downloadManager: DownloadManager = Injekt.get(), - // SY <-- ): Boolean { val remoteTitle = try { remoteManga.title @@ -42,14 +42,13 @@ class UpdateManga( "" } - // SY --> - val title = if (remoteTitle.isNotBlank() && localManga.ogTitle != remoteTitle) { - downloadManager.renameMangaDir(localManga.ogTitle, remoteTitle, localManga.source) - remoteTitle - } else { - null - } - // SY <-- + // if the manga isn't a favorite (or 'update titles' preference is enabled), set its title from source and update in db + val title = + if (remoteTitle.isNotEmpty() && (!localManga.favorite || libraryPreferences.updateMangaTitles().get())) { + remoteTitle + } else { + null + } val coverLastModified = when { @@ -69,7 +68,7 @@ class UpdateManga( val thumbnailUrl = remoteManga.thumbnail_url?.takeIf { it.isNotEmpty() } - return mangaRepository.update( + val success = mangaRepository.update( MangaUpdate( id = localManga.id, title = title, @@ -84,6 +83,10 @@ class UpdateManga( initialized = true, ), ) + if (success && title != null) { + downloadManager.renameManga(localManga, title) + } + return success } suspend fun awaitUpdateFetchInterval( diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt index a910aea98..ab9c9dc26 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt @@ -87,6 +87,7 @@ import tachiyomi.core.common.util.system.ImageUtil import tachiyomi.core.common.util.system.logcat import tachiyomi.domain.UnsortedPreferences import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId +import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.domain.manga.interactor.GetAllManga import tachiyomi.domain.manga.interactor.ResetViewerFlags import tachiyomi.domain.release.service.AppUpdatePolicy @@ -116,6 +117,7 @@ object SettingsAdvancedScreen : SearchableSettings { val basePreferences = remember { Injekt.get() } val networkPreferences = remember { Injekt.get() } + val libraryPreferences = remember { Injekt.get() } val unsortedPreferences = remember { Injekt.get() } return listOf( @@ -175,7 +177,7 @@ object SettingsAdvancedScreen : SearchableSettings { getBackgroundActivityGroup(), getDataGroup(), getNetworkGroup(networkPreferences = networkPreferences), - getLibraryGroup(), + getLibraryGroup(libraryPreferences = libraryPreferences), getReaderGroup(basePreferences = basePreferences), getExtensionsGroup(basePreferences = basePreferences), // SY --> @@ -343,7 +345,9 @@ object SettingsAdvancedScreen : SearchableSettings { } @Composable - private fun getLibraryGroup(): Preference.PreferenceGroup { + private fun getLibraryGroup( + libraryPreferences: LibraryPreferences, + ): Preference.PreferenceGroup { val scope = rememberCoroutineScope() val context = LocalContext.current // KMK --> @@ -380,6 +384,11 @@ object SettingsAdvancedScreen : SearchableSettings { } }, ), + Preference.PreferenceItem.SwitchPreference( + preference = libraryPreferences.updateMangaTitles(), + title = stringResource(MR.strings.pref_update_library_manga_titles), + subtitle = stringResource(MR.strings.pref_update_library_manga_titles_summary), + ), ), ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt index 5cccdf8a8..29b12ac50 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt @@ -322,6 +322,41 @@ class DownloadCache( notifyChanges() } + /** + * Renames a manga in this cache. + * + * @param manga the manga being renamed. + * @param mangaUniFile the manga's new directory. + * @param newTitle the manga's new title. + */ + suspend fun renameManga(manga: Manga, mangaUniFile: UniFile, newTitle: String) { + rootDownloadsDirMutex.withLock { + val sourceDir = rootDownloadsDir.sourceDirs[manga.source] ?: return + val oldMangaDirName = provider.getMangaDirName(/* KMK --> */ manga.ogTitle /* KMK --> */) + var oldChapterDirs: MutableSet? = null + // Save the old name's cached chapter dirs + if (sourceDir.mangaDirs.containsKey(oldMangaDirName)) { + oldChapterDirs = sourceDir.mangaDirs[oldMangaDirName]?.chapterDirs + sourceDir.mangaDirs -= oldMangaDirName + } + + // Retrieve/create the cached manga directory for new name + val newMangaDirName = provider.getMangaDirName(newTitle) + var mangaDir = sourceDir.mangaDirs[newMangaDirName] + if (mangaDir == null) { + mangaDir = MangaDirectory(mangaUniFile) + sourceDir.mangaDirs += newMangaDirName to mangaDir + } + + // Add the old chapters to new name's cache + if (!oldChapterDirs.isNullOrEmpty()) { + mangaDir.chapterDirs += oldChapterDirs + } + } + + notifyChanges() + } + suspend fun removeSource(source: Source) { rootDownloadsDirMutex.withLock { rootDownloadsDir.sourceDirs -= source.id diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt index 6897f502a..a02085989 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt @@ -5,7 +5,6 @@ import com.hippo.unifile.UniFile import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.model.Page -import eu.kanade.tachiyomi.util.storage.DiskUtil import exh.log.xLogE import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.asFlow @@ -415,6 +414,38 @@ class DownloadManager( } } + /** + * Renames manga download folder + * + * @param manga the manga + * @param newTitle the new manga title. + */ + suspend fun renameManga(manga: Manga, newTitle: String) { + val source = sourceManager.getOrStub(manga.source) + val oldFolder = provider.findMangaDir(/* KMK --> */ manga.ogTitle /* KMK --> */, source) ?: return + val newName = provider.getMangaDirName(newTitle) + + if (oldFolder.name == newName) return + + // just to be safe, don't allow downloads for this manga while renaming it + downloader.removeFromQueue(manga) + + val capitalizationChanged = oldFolder.name.equals(newName, ignoreCase = true) + if (capitalizationChanged) { + val tempName = newName + Downloader.TMP_DIR_SUFFIX + if (!oldFolder.renameTo(tempName)) { + logcat(LogPriority.ERROR) { "Failed to rename manga download folder: ${oldFolder.name}" } + return + } + } + + if (oldFolder.renameTo(newName)) { + cache.renameManga(manga, oldFolder, newTitle) + } else { + logcat(LogPriority.ERROR) { "Failed to rename manga download folder: ${oldFolder.name}" } + } + } + /** * Renames an already downloaded chapter * @@ -516,10 +547,4 @@ class DownloadManager( .asFlow(), ) } - - fun renameMangaDir(oldTitle: String, newTitle: String, source: Long) { - val sourceDir = provider.findSourceDir(sourceManager.getOrStub(source)) ?: return - val mangaDir = sourceDir.findFile(DiskUtil.buildValidFilename(oldTitle)) ?: return - mangaDir.renameTo(DiskUtil.buildValidFilename(newTitle)) - } } diff --git a/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt b/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt index 0f4c686a5..f667642c0 100644 --- a/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt +++ b/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt @@ -226,6 +226,8 @@ class LibraryPreferences( ChapterSwipeAction.ToggleRead, ) + fun updateMangaTitles() = preferenceStore.getBoolean("pref_update_library_manga_titles", false) + // endregion enum class ChapterSwipeAction { diff --git a/i18n/src/commonMain/moko-resources/base/strings.xml b/i18n/src/commonMain/moko-resources/base/strings.xml index 9c45dd809..384e9533d 100644 --- a/i18n/src/commonMain/moko-resources/base/strings.xml +++ b/i18n/src/commonMain/moko-resources/base/strings.xml @@ -628,6 +628,8 @@ Verbose logging Print verbose logs to system log (reduces app performance) Debug info + Update library manga titles to match source + Warning: if a manga is renamed, it will be removed from the download queue (if present). Website