mirror of
https://github.com/Dictionarry-Hub/profilarr.git
synced 2026-01-22 10:51:02 +01:00
179 lines
6.3 KiB
Python
179 lines
6.3 KiB
Python
"""Utility functions for import operations."""
|
|
import logging
|
|
import yaml
|
|
from pathlib import Path
|
|
from typing import Dict, List, Any, Set
|
|
from ..data.utils import get_category_directory
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def load_yaml(file_path: str) -> Dict[str, Any]:
|
|
"""
|
|
Load a YAML file.
|
|
|
|
Args:
|
|
file_path: Path to YAML file (relative to data directory)
|
|
|
|
Returns:
|
|
Parsed YAML data
|
|
|
|
Raises:
|
|
FileNotFoundError: If file doesn't exist
|
|
yaml.YAMLError: If YAML is invalid
|
|
"""
|
|
# Handle both absolute and relative paths
|
|
if file_path.startswith('/'):
|
|
full_path = Path(file_path)
|
|
else:
|
|
# Check if it starts with a category
|
|
if file_path.startswith('custom_format/'):
|
|
base_dir = get_category_directory('custom_format')
|
|
filename = file_path.replace('custom_format/', '')
|
|
full_path = Path(base_dir) / filename
|
|
elif file_path.startswith('profile/'):
|
|
base_dir = get_category_directory('profile')
|
|
filename = file_path.replace('profile/', '')
|
|
full_path = Path(base_dir) / filename
|
|
else:
|
|
# Assume it's just a filename, figure out category
|
|
full_path = Path(file_path)
|
|
|
|
if not full_path.exists():
|
|
raise FileNotFoundError(f"File not found: {full_path}")
|
|
|
|
with open(full_path, 'r', encoding='utf-8') as f:
|
|
return yaml.safe_load(f)
|
|
|
|
|
|
def extract_format_names(profile_data: Dict[str, Any], arr_type: str = None) -> Set[str]:
|
|
"""
|
|
Extract all custom format names referenced in a profile.
|
|
|
|
Args:
|
|
profile_data: Profile YAML data
|
|
arr_type: Target arr type ('radarr' or 'sonarr'). If provided, only extracts
|
|
formats for that specific arr type.
|
|
|
|
Returns:
|
|
Set of unique format names
|
|
"""
|
|
format_names = set()
|
|
|
|
# Extract from main custom_formats
|
|
for cf in profile_data.get('custom_formats', []):
|
|
if isinstance(cf, dict) and 'name' in cf:
|
|
format_names.add(cf['name'])
|
|
|
|
# Extract from app-specific custom_formats
|
|
if arr_type:
|
|
# Only extract formats for the specific arr type
|
|
app_key = f'custom_formats_{arr_type.lower()}'
|
|
for cf in profile_data.get(app_key, []):
|
|
if isinstance(cf, dict) and 'name' in cf:
|
|
format_names.add(cf['name'])
|
|
else:
|
|
# Extract from all app-specific sections (backwards compatibility)
|
|
for key in ['custom_formats_radarr', 'custom_formats_sonarr']:
|
|
for cf in profile_data.get(key, []):
|
|
if isinstance(cf, dict) and 'name' in cf:
|
|
format_names.add(cf['name'])
|
|
|
|
return format_names
|
|
|
|
|
|
def generate_language_formats(language: str, arr_type: str) -> List[Dict[str, Any]]:
|
|
"""
|
|
Generate language-specific format configurations.
|
|
|
|
Args:
|
|
language: Language string (e.g., 'must_english', 'only_french')
|
|
arr_type: 'radarr' or 'sonarr'
|
|
|
|
Returns:
|
|
List of format configurations for language handling
|
|
"""
|
|
if language == 'any' or '_' not in language:
|
|
return []
|
|
|
|
behavior, language_code = language.split('_', 1)
|
|
formats = []
|
|
|
|
# Handle behaviors: 'must' and 'only' (matching old working logic)
|
|
if behavior in ['must', 'only']:
|
|
# Load base "Not English" format as template
|
|
try:
|
|
base_format = load_yaml('custom_format/Not English.yml')
|
|
|
|
# Create "Not [Language]" format
|
|
not_format = base_format.copy()
|
|
lang_display = language_code.capitalize()
|
|
not_format['name'] = f"Not {lang_display}"
|
|
|
|
# Update conditions for the specific language
|
|
for condition in not_format.get('conditions', []):
|
|
if condition.get('type') == 'language':
|
|
condition['language'] = language_code
|
|
if 'name' in condition:
|
|
condition['name'] = condition['name'].replace('English', lang_display)
|
|
# Note: exceptLanguage field is preserved from the base format
|
|
|
|
formats.append(not_format)
|
|
|
|
# For 'only' behavior, add additional formats
|
|
if behavior == 'only':
|
|
additional_format_names = [
|
|
"Not Only English",
|
|
"Not Only English (Missing)"
|
|
]
|
|
|
|
for format_name in additional_format_names:
|
|
try:
|
|
additional = load_yaml(f'custom_format/{format_name}.yml')
|
|
additional['name'] = additional['name'].replace('English', lang_display)
|
|
|
|
for condition in additional.get('conditions', []):
|
|
if condition.get('type') == 'language':
|
|
condition['language'] = language_code
|
|
if 'name' in condition:
|
|
condition['name'] = condition['name'].replace('English', lang_display)
|
|
# Note: exceptLanguage field is preserved from the base format
|
|
|
|
formats.append(additional)
|
|
except Exception as e:
|
|
# Silent fail - format doesn't exist
|
|
pass
|
|
|
|
except Exception as e:
|
|
# Silent fail - will be caught at higher level
|
|
pass
|
|
|
|
return formats
|
|
|
|
|
|
def load_regex_patterns() -> Dict[str, str]:
|
|
"""
|
|
Load all regex patterns from the regex directory.
|
|
|
|
Returns:
|
|
Dictionary mapping pattern names to regex patterns
|
|
"""
|
|
from ..data.utils import REGEX_DIR
|
|
|
|
patterns = {}
|
|
pattern_dir = Path(REGEX_DIR)
|
|
|
|
if not pattern_dir.exists():
|
|
return patterns
|
|
|
|
for pattern_file in pattern_dir.glob('*.yml'):
|
|
try:
|
|
with open(pattern_file, 'r', encoding='utf-8') as f:
|
|
data = yaml.safe_load(f)
|
|
if data and 'name' in data and 'pattern' in data:
|
|
patterns[data['name']] = data['pattern']
|
|
except Exception as e:
|
|
# Silent fail for individual pattern files
|
|
pass
|
|
|
|
return patterns |