diff --git a/apps/channels/tasks.py b/apps/channels/tasks.py index 25c0bfa0..8d49287b 100755 --- a/apps/channels/tasks.py +++ b/apps/channels/tasks.py @@ -139,7 +139,7 @@ COMMON_EXTRANEOUS_WORDS = [ def normalize_name(name: str) -> str: """ A more aggressive normalization that: - - Removes user-configured prefixes/suffixes/custom strings (if configured) + - Removes user-configured prefixes/suffixes/custom strings (only if mode is 'advanced') - Lowercases - Removes bracketed/parenthesized text - Removes punctuation @@ -157,17 +157,23 @@ def normalize_name(name: str) -> str: try: from core.models import CoreSettings settings = CoreSettings.get_epg_settings() - prefixes = settings.get("epg_match_ignore_prefixes", []) - suffixes = settings.get("epg_match_ignore_suffixes", []) - custom_strings = settings.get("epg_match_ignore_custom", []) - # Ensure we have lists - if not isinstance(prefixes, list): - prefixes = [] - if not isinstance(suffixes, list): - suffixes = [] - if not isinstance(custom_strings, list): - custom_strings = [] + # Check if user has enabled advanced mode + mode = settings.get("epg_match_mode", "default") + + # Only use custom settings if mode is 'advanced' + if mode == "advanced": + prefixes = settings.get("epg_match_ignore_prefixes", []) + suffixes = settings.get("epg_match_ignore_suffixes", []) + custom_strings = settings.get("epg_match_ignore_custom", []) + + # Ensure we have lists + if not isinstance(prefixes, list): + prefixes = [] + if not isinstance(suffixes, list): + suffixes = [] + if not isinstance(custom_strings, list): + custom_strings = [] except Exception as e: # Settings unavailable or error - continue with empty lists (graceful degradation) diff --git a/core/models.py b/core/models.py index 1037a6e3..c72192db 100644 --- a/core/models.py +++ b/core/models.py @@ -233,6 +233,7 @@ class CoreSettings(models.Model): def get_epg_settings(cls): """Get all EPG-related settings.""" return cls._get_group(EPG_SETTINGS_KEY, { + "epg_match_mode": "default", "epg_match_ignore_prefixes": [], "epg_match_ignore_suffixes": [], "epg_match_ignore_custom": [], diff --git a/frontend/src/components/modals/EPGMatchModal.jsx b/frontend/src/components/modals/EPGMatchModal.jsx index fc773d94..64873643 100644 --- a/frontend/src/components/modals/EPGMatchModal.jsx +++ b/frontend/src/components/modals/EPGMatchModal.jsx @@ -1,4 +1,4 @@ -import { useMemo, useState, useEffect } from 'react'; +import { useMemo, useState, useEffect, useRef } from 'react'; import { Modal, Stack, @@ -7,6 +7,7 @@ import { Group, Button, Loader, + Radio, } from '@mantine/core'; import { notifications } from '@mantine/notifications'; import useSettingsStore from '../../store/settings'; @@ -20,6 +21,7 @@ import { const getEpgSettingsFromStore = (settings) => { const epgSettings = settings?.['epg_settings']?.value; return { + epg_match_mode: epgSettings?.epg_match_mode || 'default', epg_match_ignore_prefixes: Array.isArray(epgSettings?.epg_match_ignore_prefixes) ? epgSettings.epg_match_ignore_prefixes : [], @@ -40,6 +42,7 @@ const EPGMatchModal = ({ const settings = useSettingsStore((s) => s.settings); const [loading, setLoading] = useState(false); + const [settingsMode, setSettingsMode] = useState('default'); // Compute form values directly from settings - memoized for performance const storedValues = useMemo( @@ -50,18 +53,28 @@ const EPGMatchModal = ({ // Local form state const [formValues, setFormValues] = useState(storedValues); - // Reset to stored values when modal opens + // Track previous opened state to detect transitions + const prevOpened = useRef(false); + + // Reset to stored values and mode only when modal opens (not on storedValues changes) useEffect(() => { - if (opened) { + // Only reset when transitioning from closed to open + if (opened && !prevOpened.current) { setFormValues(storedValues); + setSettingsMode(storedValues.epg_match_mode); } + prevOpened.current = opened; }, [opened, storedValues]); const handleConfirm = async () => { setLoading(true); try { - // Save settings first - const changedSettings = getChangedSettings(formValues, settings); + // Save mode and settings (backend will ignore custom settings if mode is 'default') + const settingsToSave = { + ...formValues, + epg_match_mode: settingsMode, + }; + const changedSettings = getChangedSettings(settingsToSave, settings); if (Object.keys(changedSettings).length > 0) { await saveChangedSettings(settings, changedSettings); } @@ -108,59 +121,81 @@ const EPGMatchModal = ({ > - Configure how channel names are normalized during matching, then start - the auto-match process for {scopeText}. + Match channels to EPG data for {scopeText}. - - setFormValues((prev) => ({ - ...prev, - epg_match_ignore_prefixes: value, - })) - } - splitChars={[]} - clearable - /> + + + + + + - - setFormValues((prev) => ({ - ...prev, - epg_match_ignore_suffixes: value, - })) - } - splitChars={[]} - clearable - /> + {settingsMode === 'advanced' && ( + <> + + setFormValues((prev) => ({ + ...prev, + epg_match_ignore_prefixes: value, + })) + } + splitChars={[]} + clearable + /> - - setFormValues((prev) => ({ - ...prev, - epg_match_ignore_custom: value, - })) - } - splitChars={[]} - clearable - /> + + setFormValues((prev) => ({ + ...prev, + epg_match_ignore_suffixes: value, + })) + } + splitChars={[]} + clearable + /> - - Channel display names are never modified. These settings only affect - the matching algorithm. - + + setFormValues((prev) => ({ + ...prev, + epg_match_ignore_custom: value, + })) + } + splitChars={[]} + clearable + /> + + + Channel display names are never modified. These settings only affect + the matching algorithm. + + + )}