mirror of
https://github.com/Dictionarry-Hub/profilarr.git
synced 2026-01-26 12:52:00 +01:00
feat: add support for unique import names in format and profile import processes
This commit is contained in:
@@ -382,6 +382,7 @@ def run_import_for_config(config_row):
|
||||
arr_type = config_row['type']
|
||||
arr_server = config_row['arrServer']
|
||||
api_key = config_row['apiKey']
|
||||
import_as_unique = config_row.get('import_as_unique', False)
|
||||
|
||||
logger.info(
|
||||
f"[Pull Import] Running import for ARR config #{arr_id} ({arr_name})")
|
||||
@@ -396,6 +397,13 @@ def run_import_for_config(config_row):
|
||||
total_attempted = 0
|
||||
total_successful = 0
|
||||
|
||||
# Log import_as_unique setting
|
||||
if import_as_unique:
|
||||
logger.info(f"Unique imports for {arr_name} are on, adjusting names")
|
||||
else:
|
||||
logger.info(
|
||||
f"Unique imports for {arr_name} are off, using original names")
|
||||
|
||||
# 1) Import user-selected custom formats
|
||||
if selected_formats:
|
||||
total_attempted += len(selected_formats)
|
||||
@@ -404,8 +412,20 @@ def run_import_for_config(config_row):
|
||||
)
|
||||
try:
|
||||
from ..importarr.format import import_formats_to_arr
|
||||
format_names = selected_formats
|
||||
original_names = format_names.copy()
|
||||
|
||||
# Modify format names if import_as_unique is true
|
||||
if import_as_unique:
|
||||
format_names = [
|
||||
f"{name} [Dictionarry]" for name in format_names
|
||||
]
|
||||
logger.info(
|
||||
f"Modified format names for unique import: {format_names}")
|
||||
|
||||
format_result = import_formats_to_arr(
|
||||
format_names=selected_formats,
|
||||
format_names=format_names,
|
||||
original_names=original_names,
|
||||
base_url=arr_server,
|
||||
api_key=api_key,
|
||||
arr_type=arr_type)
|
||||
@@ -453,11 +473,22 @@ def run_import_for_config(config_row):
|
||||
total_attempted += len(referenced_cf_names)
|
||||
try:
|
||||
from ..importarr.format import import_formats_to_arr
|
||||
cf_result = import_formats_to_arr(
|
||||
format_names=list(referenced_cf_names),
|
||||
base_url=arr_server,
|
||||
api_key=api_key,
|
||||
arr_type=arr_type)
|
||||
format_names = list(referenced_cf_names)
|
||||
original_names = format_names.copy()
|
||||
|
||||
# Modify format names if import_as_unique is true
|
||||
if import_as_unique:
|
||||
format_names = [
|
||||
f"{name} [Dictionarry]" for name in format_names
|
||||
]
|
||||
logger.info(
|
||||
f"Modified format names for unique import: {format_names}")
|
||||
|
||||
cf_result = import_formats_to_arr(format_names=format_names,
|
||||
original_names=original_names,
|
||||
base_url=arr_server,
|
||||
api_key=api_key,
|
||||
arr_type=arr_type)
|
||||
|
||||
if cf_result.get('success'):
|
||||
total_successful += (cf_result.get('added', 0) +
|
||||
@@ -475,12 +506,26 @@ def run_import_for_config(config_row):
|
||||
total_attempted += len(selected_profiles)
|
||||
try:
|
||||
from ..importarr.profile import import_profiles_to_arr
|
||||
profile_names = selected_profiles
|
||||
original_names = profile_names.copy()
|
||||
|
||||
# Modify profile names if import_as_unique is true
|
||||
if import_as_unique:
|
||||
profile_names = [
|
||||
f"{name} [Dictionarry]" for name in profile_names
|
||||
]
|
||||
logger.info(
|
||||
f"Modified profile names for unique import: {profile_names}"
|
||||
)
|
||||
|
||||
profile_result = import_profiles_to_arr(
|
||||
profile_names=selected_profiles,
|
||||
profile_names=profile_names,
|
||||
original_names=original_names,
|
||||
base_url=arr_server,
|
||||
api_key=api_key,
|
||||
arr_type=arr_type,
|
||||
arr_id=arr_id)
|
||||
arr_id=arr_id,
|
||||
import_as_unique=import_as_unique)
|
||||
|
||||
if profile_result.get('success'):
|
||||
total_successful += (profile_result.get('added', 0) +
|
||||
|
||||
@@ -34,11 +34,13 @@ class ProfileConverter:
|
||||
target_app: TargetApp,
|
||||
base_url: str = None,
|
||||
api_key: str = None,
|
||||
format_importer: Callable = None):
|
||||
format_importer: Callable = None,
|
||||
import_as_unique: bool = False):
|
||||
self.target_app = target_app
|
||||
self.base_url = base_url
|
||||
self.api_key = api_key
|
||||
self.format_importer = format_importer
|
||||
self.import_as_unique = import_as_unique
|
||||
self.quality_mappings = ValueResolver.get_qualities(target_app)
|
||||
|
||||
def _convert_group_id(self, group_id: int) -> int:
|
||||
@@ -60,8 +62,11 @@ class ProfileConverter:
|
||||
})
|
||||
return qualities
|
||||
|
||||
def _process_language_formats(self, behaviour: str,
|
||||
language: str) -> List[Dict]:
|
||||
def _process_language_formats(
|
||||
self,
|
||||
behaviour: str,
|
||||
language: str,
|
||||
import_as_unique: bool = False) -> List[Dict]:
|
||||
if not self.base_url or not self.api_key or not self.format_importer:
|
||||
logger.error("Missing required credentials or format importer")
|
||||
raise ValueError(
|
||||
@@ -80,7 +85,8 @@ class ProfileConverter:
|
||||
for_profile=False)
|
||||
|
||||
modified_format = base_format.copy()
|
||||
modified_format['name'] = f"Not {language_data['name']}"
|
||||
base_name = f"Not {language_data['name']}"
|
||||
modified_format['name'] = base_name
|
||||
|
||||
for condition in modified_format['conditions']:
|
||||
if condition.get('type') == 'language':
|
||||
@@ -113,17 +119,24 @@ class ProfileConverter:
|
||||
arr_type = 'radarr' if self.target_app == TargetApp.RADARR else 'sonarr'
|
||||
for format_data in formats_to_import:
|
||||
try:
|
||||
result = import_format_from_memory(format_data,
|
||||
self.base_url,
|
||||
self.api_key, arr_type)
|
||||
result = import_format_from_memory(
|
||||
format_data,
|
||||
self.base_url,
|
||||
self.api_key,
|
||||
arr_type,
|
||||
import_as_unique=self.import_as_unique)
|
||||
if not result.get('success', False):
|
||||
logger.error(
|
||||
f"Format import failed for: {format_data['name']}")
|
||||
raise Exception(
|
||||
f"Failed to import format {format_data['name']}")
|
||||
|
||||
format_name = format_data['name']
|
||||
if import_as_unique:
|
||||
format_name = f"{format_name} [Dictionarry]"
|
||||
|
||||
format_configs.append({
|
||||
'name': format_data['name'],
|
||||
'name': format_name,
|
||||
'score': -9999
|
||||
})
|
||||
|
||||
@@ -305,9 +318,13 @@ def compile_quality_profile(profile_data: Dict,
|
||||
target_app: TargetApp,
|
||||
base_url: str = None,
|
||||
api_key: str = None,
|
||||
format_importer: Callable = None) -> List[Dict]:
|
||||
converter = ProfileConverter(target_app, base_url, api_key,
|
||||
format_importer)
|
||||
format_importer: Callable = None,
|
||||
import_as_unique: bool = False) -> List[Dict]:
|
||||
converter = ProfileConverter(target_app,
|
||||
base_url,
|
||||
api_key,
|
||||
format_importer,
|
||||
import_as_unique=import_as_unique)
|
||||
converted = converter.convert_profile(profile_data)
|
||||
|
||||
output = {
|
||||
|
||||
@@ -81,8 +81,11 @@ def add_format(base_url: str, api_key: str, format_data: Dict) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def import_format_from_memory(format_data: Dict, base_url: str, api_key: str,
|
||||
arr_type: str) -> Dict:
|
||||
def import_format_from_memory(format_data: Dict,
|
||||
base_url: str,
|
||||
api_key: str,
|
||||
arr_type: str,
|
||||
import_as_unique: bool = False) -> Dict:
|
||||
"""
|
||||
Import a format directly from memory without requiring file loading.
|
||||
|
||||
@@ -91,6 +94,7 @@ def import_format_from_memory(format_data: Dict, base_url: str, api_key: str,
|
||||
base_url: Arr instance base URL
|
||||
api_key: API key for arr instance
|
||||
arr_type: Type of arr instance (radarr/sonarr)
|
||||
import_as_unique: Whether to append [Dictionarry] to format names
|
||||
|
||||
Returns:
|
||||
Dict containing import results
|
||||
@@ -104,6 +108,14 @@ def import_format_from_memory(format_data: Dict, base_url: str, api_key: str,
|
||||
}
|
||||
|
||||
try:
|
||||
# Modify format name if import_as_unique is true
|
||||
original_name = format_data['name']
|
||||
if import_as_unique:
|
||||
format_data['name'] = f"{original_name} [Dictionarry]"
|
||||
logger.info(
|
||||
f"Modified format name for unique import: {format_data['name']}"
|
||||
)
|
||||
|
||||
# Log the received memory-based format data
|
||||
logger.info("Received memory-based format:\n" +
|
||||
json.dumps(format_data, indent=2))
|
||||
|
||||
@@ -81,7 +81,7 @@ def import_profiles_to_arr(profile_names: List[str], original_names: List[str],
|
||||
f"Processing tweaks and importing formats for profile '{profile_name}'"
|
||||
)
|
||||
profile_data = process_tweaks(profile_data, base_url, api_key,
|
||||
arr_type)
|
||||
arr_type, import_as_unique)
|
||||
|
||||
logger.info("Compiling quality profile...")
|
||||
compiled_profiles = compile_quality_profile(
|
||||
@@ -89,7 +89,8 @@ def import_profiles_to_arr(profile_names: List[str], original_names: List[str],
|
||||
target_app=target_app,
|
||||
base_url=base_url,
|
||||
api_key=api_key,
|
||||
format_importer=import_formats_to_arr)
|
||||
format_importer=import_formats_to_arr,
|
||||
import_as_unique=import_as_unique)
|
||||
|
||||
if not compiled_profiles:
|
||||
raise ValueError("Profile compilation returned no data")
|
||||
@@ -216,8 +217,11 @@ def sync_format_ids(profile_data: Dict, format_id_map: Dict[str, int]) -> Dict:
|
||||
return profile_data
|
||||
|
||||
|
||||
def process_tweaks(profile_data: Dict, base_url: str, api_key: str,
|
||||
arr_type: str) -> Dict:
|
||||
def process_tweaks(profile_data: Dict,
|
||||
base_url: str,
|
||||
api_key: str,
|
||||
arr_type: str,
|
||||
import_as_unique: bool = False) -> Dict:
|
||||
logger.debug(f"Processing tweaks for profile: {profile_data.get('name')}")
|
||||
tweaks = profile_data.get('tweaks', {})
|
||||
|
||||
@@ -233,7 +237,8 @@ def process_tweaks(profile_data: Dict, base_url: str, api_key: str,
|
||||
base_url=base_url,
|
||||
api_key=api_key,
|
||||
arr_type=arr_type,
|
||||
feature_name="freeleech")
|
||||
feature_name="freeleech",
|
||||
import_as_unique=import_as_unique)
|
||||
|
||||
lossless_formats = [
|
||||
"FLAC", "DTS-X", "DTS-HD MA", "TrueHD", "TrueHD (Missing)"
|
||||
@@ -249,7 +254,8 @@ def process_tweaks(profile_data: Dict, base_url: str, api_key: str,
|
||||
base_url=base_url,
|
||||
api_key=api_key,
|
||||
arr_type=arr_type,
|
||||
feature_name="lossless audio")
|
||||
feature_name="lossless audio",
|
||||
import_as_unique=import_as_unique)
|
||||
|
||||
dv_formats = ["Dolby Vision (Without Fallback)"]
|
||||
dv_score = 0 if tweaks.get('allowDVNoFallback', False) else -9999
|
||||
@@ -260,7 +266,8 @@ def process_tweaks(profile_data: Dict, base_url: str, api_key: str,
|
||||
base_url=base_url,
|
||||
api_key=api_key,
|
||||
arr_type=arr_type,
|
||||
feature_name="Dolby Vision no fallback")
|
||||
feature_name="Dolby Vision no fallback",
|
||||
import_as_unique=import_as_unique)
|
||||
|
||||
codec_formats = ["AV1", "VVC"]
|
||||
codec_score = 0 if tweaks.get('allowBleedingEdgeCodecs', False) else -9999
|
||||
@@ -271,23 +278,56 @@ def process_tweaks(profile_data: Dict, base_url: str, api_key: str,
|
||||
base_url=base_url,
|
||||
api_key=api_key,
|
||||
arr_type=arr_type,
|
||||
feature_name="bleeding edge codecs")
|
||||
feature_name="bleeding edge codecs",
|
||||
import_as_unique=import_as_unique)
|
||||
|
||||
return profile_data
|
||||
|
||||
|
||||
def _import_and_score_formats(formats: List[str], scores: List[Dict[str, Any]],
|
||||
profile_data: Dict, base_url: str, api_key: str,
|
||||
arr_type: str, feature_name: str) -> None:
|
||||
def _import_and_score_formats(formats: List[str],
|
||||
scores: List[Dict[str, Any]],
|
||||
profile_data: Dict,
|
||||
base_url: str,
|
||||
api_key: str,
|
||||
arr_type: str,
|
||||
feature_name: str,
|
||||
import_as_unique: bool = False) -> None:
|
||||
logger.info(
|
||||
f"Processing {feature_name} formats for profile '{profile_data.get('name')}'"
|
||||
)
|
||||
try:
|
||||
result = import_formats_to_arr(formats, base_url, api_key, arr_type)
|
||||
# Create modified format names if import_as_unique is true
|
||||
format_names = [
|
||||
f"{name} [Dictionarry]" if import_as_unique else name
|
||||
for name in formats
|
||||
]
|
||||
|
||||
result = import_formats_to_arr(
|
||||
format_names=format_names, # Use modified names for import
|
||||
original_names=formats, # Original names for file lookup
|
||||
base_url=base_url,
|
||||
api_key=api_key,
|
||||
arr_type=arr_type)
|
||||
|
||||
if not result.get('success', False):
|
||||
logger.warning(
|
||||
f"Failed to import {feature_name} formats for '{profile_data.get('name')}'"
|
||||
)
|
||||
return
|
||||
|
||||
if 'custom_formats' not in profile_data:
|
||||
profile_data['custom_formats'] = []
|
||||
|
||||
# Use the modified format names in the profile's format list
|
||||
modified_scores = []
|
||||
for i, score in enumerate(scores):
|
||||
score_copy = score.copy()
|
||||
# Use the same modified name that was used for import
|
||||
score_copy['name'] = format_names[i]
|
||||
modified_scores.append(score_copy)
|
||||
|
||||
profile_data['custom_formats'].extend(modified_scores)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error importing {feature_name} formats: {str(e)}")
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user