From ce7729ed6dbca94ca39fedc14d7d303c9a6ff6d6 Mon Sep 17 00:00:00 2001 From: Simon <9295182+grimsi@users.noreply.github.com> Date: Sat, 19 Jul 2025 22:15:02 +0200 Subject: [PATCH] Implement title extraction using Regex (closes #636) (#637) * Implement #636 * Fix potential bug in Regex parsing Add validation in UI Adjust log entries --- .../administration/LibraryManagement.tsx | 13 +++++++++++- .../gameyfin/app/config/ConfigProperties.kt | 14 +++++++++++++ .../org/gameyfin/app/games/GameService.kt | 21 ++++++++++++++++++- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/app/src/main/frontend/components/administration/LibraryManagement.tsx b/app/src/main/frontend/components/administration/LibraryManagement.tsx index 14da06f..ee6485d 100644 --- a/app/src/main/frontend/components/administration/LibraryManagement.tsx +++ b/app/src/main/frontend/components/administration/LibraryManagement.tsx @@ -45,8 +45,11 @@ function LibraryManagementLayout({getConfig, formik}: any) {
- + +
+ @@ -95,6 +98,14 @@ const validationSchema = Yup.object({ // @ts-ignore schedule: Yup.string().cron() }) + }), + scan: Yup.object({ + "extract-title-using-regex": Yup.boolean(), + "title-extraction-regex": Yup.string().when("extract-title-using-regex", { + is: true, + then: (schema) => schema.trim().required("Title extraction regex is required when enabled") + }), + "title-match-min-ratio": Yup.number().min(1, "Must be between 1-100").max(100, "Must be between 1-100") }) }) }); diff --git a/app/src/main/kotlin/org/gameyfin/app/config/ConfigProperties.kt b/app/src/main/kotlin/org/gameyfin/app/config/ConfigProperties.kt index 3f90350..c5caccb 100644 --- a/app/src/main/kotlin/org/gameyfin/app/config/ConfigProperties.kt +++ b/app/src/main/kotlin/org/gameyfin/app/config/ConfigProperties.kt @@ -36,6 +36,20 @@ sealed class ConfigProperties( false ) + data object ExtractTitleUsingRegex : ConfigProperties( + Boolean::class, + "library.scan.extract-title-using-regex", + "Extract title from file names using regex", + false + ) + + data object TitleExtractionRegex : ConfigProperties( + String::class, + "library.scan.title-extraction-regex", + "Regex to extract title from file names", + "^[^\\[]+" + ) + data object TitleMatchMinRatio : ConfigProperties( Int::class, "library.scan.title-match-min-ratio", diff --git a/app/src/main/kotlin/org/gameyfin/app/games/GameService.kt b/app/src/main/kotlin/org/gameyfin/app/games/GameService.kt index 88cbef1..067628b 100644 --- a/app/src/main/kotlin/org/gameyfin/app/games/GameService.kt +++ b/app/src/main/kotlin/org/gameyfin/app/games/GameService.kt @@ -603,7 +603,26 @@ class GameService( } fun matchFromFile(path: Path, library: Library): Game? { - val query = FilenameUtils.removeExtension(path.fileName.toString()) + var query = FilenameUtils.removeExtension(path.fileName.toString()) + + // (Optional) Step -1: Extract title from filename using regex + if (config.get(ConfigProperties.Libraries.Scan.ExtractTitleUsingRegex) == true) { + val regexString = config.get(ConfigProperties.Libraries.Scan.TitleExtractionRegex) + if (regexString != null && regexString.isNotEmpty()) { + try { + val regex = Regex(regexString) + val originalQuery = query + query = regex.find(query)?.value?.trim() ?: query.also { + log.warn { "No match found for regex '$regexString' in filename '$query'. Using full filename." } + } + log.debug { "Extracted title '$query' from filename '$originalQuery'" } + } catch (_: Exception) { + log.error { "Title extraction regex ($regexString) is invalid, using fill filename." } + } + } else { + log.warn { "No regex configured for title extraction, using full filename '$query'" } + } + } // Step 0: Query all metadata plugins for metadata on the provided game title val metadataResults = queryPlugins(query)