Files
profilarr/backend/app/importer/strategies/format.py
Samuel Chau d7d6b13e46 feat(profiles): radarr/sonarr split functionality (#215)
- added option to set radarr/sonarr specific scores that profilarr's compiler will handle on import
- revise design for arr settings container - now styled as a table
- completely rewrote import module. Now uses connection pooling to reuse connections.
- fixed import progress bug where 1 failed format causes all other formats to be labelled as failed (even if they succeeded)
- fixed bug where on pull sync wasn't working
- improve styling for link / unlink database modals
- fixed issue where 0 score formats were removed in selective mode
2025-08-11 01:51:51 +09:30

132 lines
4.6 KiB
Python

"""Format import strategy."""
import logging
from typing import Dict, List, Any
from .base import ImportStrategy
from ..utils import load_yaml
from ..compiler import compile_format_to_api_structure
from ..logger import get_import_logger
logger = logging.getLogger(__name__)
class FormatStrategy(ImportStrategy):
"""Strategy for importing custom formats."""
def compile(self, filenames: List[str]) -> Dict[str, Any]:
"""
Compile format files to API-ready format.
Args:
filenames: List of format filenames (without .yml)
Returns:
Dictionary with 'formats' key containing compiled formats
"""
formats = []
failed = []
import_logger = get_import_logger()
# Don't try to predict - we'll count as we go
import_logger.start(0, 0) # Will update counts as we compile
for filename in filenames:
try:
# Load YAML
format_yaml = load_yaml(f"custom_format/{filename}.yml")
# Compile to API structure
compiled = compile_format_to_api_structure(format_yaml, self.arr_type)
# Add unique suffix if needed
if self.import_as_unique:
compiled['name'] = self.add_unique_suffix(compiled['name'])
formats.append(compiled)
import_logger.update_compilation(filename)
except Exception as e:
import_logger.error(f"{e}", filename, 'compilation')
failed.append(filename)
# Don't count failed compilations
# Set final compilation count
import_logger.total_compilation = len(formats)
import_logger.current_compilation = len(formats)
import_logger.compilation_complete()
return {'formats': formats}
def import_data(self, compiled_data: Dict[str, Any], dry_run: bool = False) -> Dict[str, Any]:
"""
Import compiled formats to Arr instance.
Args:
compiled_data: Dictionary with 'formats' key
dry_run: If True, simulate import without making changes
Returns:
Import results
"""
# Get existing formats
existing = self.arr.get_all_formats()
existing_map = {f['name']: f['id'] for f in existing}
results = {
'added': 0,
'updated': 0,
'failed': 0,
'details': []
}
import_logger = get_import_logger()
# Set import count
import_logger.total_import = len(compiled_data['formats'])
import_logger._import_shown = False # Reset import shown flag
for format_data in compiled_data['formats']:
format_name = format_data['name']
try:
if format_name in existing_map:
# Update existing
if not dry_run:
format_data['id'] = existing_map[format_name]
self.arr.put(
f"/api/v3/customformat/{existing_map[format_name]}",
format_data
)
import_logger.update_import(format_name, "updated")
results['updated'] += 1
results['details'].append({
'name': format_name,
'action': 'updated'
})
else:
# Add new
if not dry_run:
self.arr.post("/api/v3/customformat", format_data)
import_logger.update_import(format_name, "added")
results['added'] += 1
results['details'].append({
'name': format_name,
'action': 'added'
})
except Exception as e:
import_logger.update_import(format_name, "failed")
import_logger.error(f"Failed to import format {format_name}: {e}", format_name)
results['failed'] += 1
results['details'].append({
'name': format_name,
'action': 'failed',
'error': str(e)
})
# Show import summary
import_logger.import_complete()
import_logger._import_shown = True
return results