Fix naming
This commit is contained in:
parent
91821f4c51
commit
ae132ff1c4
237 changed files with 1808 additions and 1070 deletions
|
|
@ -7,13 +7,12 @@
|
|||
# ///
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import yaml
|
||||
|
||||
from utils.custom_formats import collect_custom_formats
|
||||
from utils.regex_patterns import collect_regex_patterns
|
||||
from utils.profiles import collect_profiles
|
||||
|
||||
|
||||
def clear_output_dir(output_dir):
|
||||
if not os.path.exists(output_dir):
|
||||
print(f"Output directory does not exist, skipping clearing")
|
||||
|
|
@ -23,6 +22,7 @@ def clear_output_dir(output_dir):
|
|||
os.remove(file_path)
|
||||
print(f"Cleared output directory: {output_dir}")
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 3:
|
||||
print("Usage: python generate.py <input_dir> <output_dir>")
|
||||
|
|
@ -30,33 +30,38 @@ def main():
|
|||
input_dir = sys.argv[1]
|
||||
output_dir = sys.argv[2]
|
||||
|
||||
regex_patterns_dir = os.path.join(output_dir, 'regex_patterns')
|
||||
regex_patterns_dir = os.path.join(output_dir, "regex_patterns")
|
||||
os.makedirs(regex_patterns_dir, exist_ok=True)
|
||||
clear_output_dir(regex_patterns_dir)
|
||||
|
||||
custom_formats_dir = os.path.join(output_dir, 'custom_formats')
|
||||
custom_formats_dir = os.path.join(output_dir, "custom_formats")
|
||||
os.makedirs(custom_formats_dir, exist_ok=True)
|
||||
clear_output_dir(custom_formats_dir)
|
||||
|
||||
profiles_dir = os.path.join(output_dir, 'profiles')
|
||||
profiles_dir = os.path.join(output_dir, "profiles")
|
||||
os.makedirs(profiles_dir, exist_ok=True)
|
||||
clear_output_dir(profiles_dir)
|
||||
|
||||
# TODO: Support Sonarr
|
||||
for service in ['radarr']:
|
||||
for service in ["radarr"]:
|
||||
trash_custom_formats_dir = os.path.join(input_dir, f"{service}/cf")
|
||||
if not os.path.exists(trash_custom_formats_dir):
|
||||
print(f"Custom format directory {trash_custom_formats_dir} does not exist, skipping.")
|
||||
print(
|
||||
f"Custom format directory {trash_custom_formats_dir} does not exist, skipping."
|
||||
)
|
||||
continue
|
||||
|
||||
trash_profiles_dir = os.path.join(input_dir, f"{service}/quality-profiles")
|
||||
if not os.path.exists(trash_profiles_dir):
|
||||
print(f"Custom format directory {trash_profiles_dir} does not exist, skipping.")
|
||||
print(
|
||||
f"Custom format directory {trash_profiles_dir} does not exist, skipping."
|
||||
)
|
||||
continue
|
||||
|
||||
collect_regex_patterns(service, trash_custom_formats_dir, regex_patterns_dir)
|
||||
collect_custom_formats(service, trash_custom_formats_dir, custom_formats_dir)
|
||||
collect_profiles(service, trash_profiles_dir, profiles_dir)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -5,88 +5,92 @@ import yaml
|
|||
from markdownify import markdownify
|
||||
|
||||
IMPLEMENTATION_TO_TAG_MAPPING = {
|
||||
'ReleaseTitleSpecification': ['Release Title'],
|
||||
'ResolutionSpecification': ['Resolution'],
|
||||
'SourceSpecification': ['Source'],
|
||||
'LanguageSpecification': ['Language'],
|
||||
'ReleaseGroupSpecification': ['Release Group'],
|
||||
'IndexerFlagSpecification': ['Indexer Flag'],
|
||||
'QualityModifierSpecification': ['Quality Modifier'],
|
||||
'ReleaseTypeSpecification': ['Release Type'],
|
||||
"ReleaseTitleSpecification": ["Release Title"],
|
||||
"ResolutionSpecification": ["Resolution"],
|
||||
"SourceSpecification": ["Source"],
|
||||
"LanguageSpecification": ["Language"],
|
||||
"ReleaseGroupSpecification": ["Release Group"],
|
||||
"IndexerFlagSpecification": ["Indexer Flag"],
|
||||
"QualityModifierSpecification": ["Quality Modifier"],
|
||||
"ReleaseTypeSpecification": ["Release Type"],
|
||||
}
|
||||
|
||||
IMPLEMENTATION_TO_TYPE_MAPPING = {
|
||||
'ReleaseTitleSpecification': 'release_title',
|
||||
'ResolutionSpecification': 'resolution',
|
||||
'SourceSpecification': 'source',
|
||||
'LanguageSpecification': 'language',
|
||||
'ReleaseGroupSpecification': 'release_group',
|
||||
'IndexerFlagSpecification': 'indexer_flag',
|
||||
'QualityModifierSpecification': 'quality_modifier',
|
||||
'ReleaseTypeSpecification': 'release_type',
|
||||
"ReleaseTitleSpecification": "release_title",
|
||||
"ResolutionSpecification": "resolution",
|
||||
"SourceSpecification": "source",
|
||||
"LanguageSpecification": "language",
|
||||
"ReleaseGroupSpecification": "release_group",
|
||||
"IndexerFlagSpecification": "indexer_flag",
|
||||
"QualityModifierSpecification": "quality_modifier",
|
||||
"ReleaseTypeSpecification": "release_type",
|
||||
}
|
||||
|
||||
|
||||
def collect_custom_format(service, file_name, input_json, output_dir):
|
||||
conditions = []
|
||||
for spec in input_json.get('specifications', []):
|
||||
for spec in input_json.get("specifications", []):
|
||||
condition = {
|
||||
'name': spec.get('name', ''),
|
||||
'negate': spec.get('negate', False),
|
||||
'required': spec.get('required', False),
|
||||
'type': IMPLEMENTATION_TO_TYPE_MAPPING.get(spec.get('implementation'), 'unknown'),
|
||||
"name": spec.get("name", ""),
|
||||
"negate": spec.get("negate", False),
|
||||
"required": spec.get("required", False),
|
||||
"type": IMPLEMENTATION_TO_TYPE_MAPPING.get(
|
||||
spec.get("implementation"), "unknown"
|
||||
),
|
||||
}
|
||||
|
||||
implementation = spec.get('implementation')
|
||||
if implementation in ['ReleaseTitleSpecification', 'ReleaseGroupSpecification']:
|
||||
condition['pattern'] = spec.get('name', '')
|
||||
elif implementation in ['ResolutionSpecification']:
|
||||
condition['resolution'] = f"{spec.get('fields', {}).get('value')}p"
|
||||
elif implementation in ['SourceSpecification']:
|
||||
condition['source'] = spec.get('fields', {}).get('value')
|
||||
elif implementation in ['LanguageSpecification']:
|
||||
# TODO: exceptLanguage
|
||||
condition['language'] = spec.get('fields', {}).get('value')
|
||||
elif implementation in ['IndexerFlagSpecification']:
|
||||
condition['flag'] = spec.get('fields', {}).get('value')
|
||||
elif implementation in ['QualityModifierSpecification']:
|
||||
condition['qualityModifier'] = spec.get('fields', {}).get('value')
|
||||
elif implementation in ['ReleaseTypeSpecification']:
|
||||
condition['releaseType'] = spec.get('fields', {}).get('value')
|
||||
implementation = spec.get("implementation")
|
||||
if implementation in ["ReleaseTitleSpecification", "ReleaseGroupSpecification"]:
|
||||
condition["pattern"] = spec.get("name", "")
|
||||
elif implementation in ["ResolutionSpecification"]:
|
||||
condition["resolution"] = f"{spec.get('fields', {}).get('value')}p"
|
||||
elif implementation in ["SourceSpecification"]:
|
||||
condition["source"] = spec.get("fields", {}).get("value")
|
||||
elif implementation in ["LanguageSpecification"]:
|
||||
# TODO: exceptLanguage
|
||||
condition["language"] = spec.get("fields", {}).get("value")
|
||||
elif implementation in ["IndexerFlagSpecification"]:
|
||||
condition["flag"] = spec.get("fields", {}).get("value")
|
||||
elif implementation in ["QualityModifierSpecification"]:
|
||||
condition["qualityModifier"] = spec.get("fields", {}).get("value")
|
||||
elif implementation in ["ReleaseTypeSpecification"]:
|
||||
condition["releaseType"] = spec.get("fields", {}).get("value")
|
||||
|
||||
conditions.append(condition)
|
||||
|
||||
# Compose YAML structure
|
||||
name = input_json.get('name', '')
|
||||
trash_id = input_json.get('trash_id', '')
|
||||
name = input_json.get("name", "")
|
||||
trash_id = input_json.get("trash_id", "")
|
||||
yml_data = {
|
||||
'name': name,
|
||||
'trash_id': trash_id,
|
||||
'trash_scores': input_json.get('trash_scores', {}),
|
||||
'description': f"""[Custom format from TRaSH-Guides.](https://trash-guides.info/{service.capitalize()}/{service.capitalize()}-collection-of-custom-formats/#{file_name})
|
||||
"name": name,
|
||||
"trash_id": trash_id,
|
||||
"trash_scores": input_json.get("trash_scores", {}),
|
||||
"description": f"""[Custom format from TRaSH-Guides.](https://trash-guides.info/{service.capitalize()}/{service.capitalize()}-collection-of-custom-formats/#{file_name})
|
||||
|
||||
{markdownify(input_json.get('description', ''))}""".strip(),
|
||||
'metadata': {
|
||||
'includeInRename': input_json.get('includeCustomFormatWhenRenaming', False),
|
||||
"metadata": {
|
||||
"includeInRename": input_json.get("includeCustomFormatWhenRenaming", False),
|
||||
},
|
||||
'tags': IMPLEMENTATION_TO_TAG_MAPPING[implementation],
|
||||
'conditions': conditions,
|
||||
'tests': []
|
||||
"tags": IMPLEMENTATION_TO_TAG_MAPPING[implementation],
|
||||
"conditions": conditions,
|
||||
"tests": [],
|
||||
}
|
||||
|
||||
# Output path
|
||||
output_path = os.path.join(output_dir, f"{file_name}-{trash_id}.yml")
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
output_path = os.path.join(output_dir, f"{file_name}.yml")
|
||||
with open(output_path, "w", encoding="utf-8") as f:
|
||||
yaml.dump(yml_data, f, sort_keys=False, allow_unicode=True)
|
||||
print(f"Generated: {output_path}")
|
||||
|
||||
|
||||
def collect_custom_formats(service, input_dir, output_dir):
|
||||
for root, _, files in os.walk(input_dir):
|
||||
for filename in files:
|
||||
if not filename.endswith('.json'):
|
||||
if not filename.endswith(".json"):
|
||||
continue
|
||||
|
||||
file_path = os.path.join(root, filename)
|
||||
file_stem = os.path.splitext(filename)[0] # Filename without extension
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
collect_custom_format(service, file_stem, data, output_dir)
|
||||
|
|
|
|||
|
|
@ -4,117 +4,123 @@ import yaml
|
|||
|
||||
from markdownify import markdownify
|
||||
|
||||
|
||||
def get_file_name(profile_name):
|
||||
return profile_name.replace('[', '(').replace(']', ')')
|
||||
return profile_name.replace("[", "(").replace("]", ")")
|
||||
|
||||
def find_score_for_custom_format(trash_score_set, custom_format_name, trash_id, output_dir):
|
||||
custom_formats_dir = os.path.join(output_dir, '..', 'custom_formats')
|
||||
target_file = None
|
||||
for fname in os.listdir(custom_formats_dir):
|
||||
if fname.endswith('.yml') and trash_id in fname:
|
||||
target_file = os.path.join(custom_formats_dir, fname)
|
||||
break
|
||||
|
||||
if not target_file or not os.path.exists(target_file):
|
||||
print(f"Custom format with trash_id {trash_id} not found in {custom_formats_dir}")
|
||||
return 0
|
||||
def find_score_for_custom_format(
|
||||
trash_score_set, custom_format_name, trash_id, output_dir
|
||||
):
|
||||
custom_formats_dir = os.path.join(output_dir, "..", "custom_formats")
|
||||
target_file = None
|
||||
for fname in os.listdir(custom_formats_dir):
|
||||
if fname.endswith(".yml"):
|
||||
target_file = os.path.join(custom_formats_dir, fname)
|
||||
break
|
||||
|
||||
with open(target_file, 'r', encoding='utf-8') as f:
|
||||
data = yaml.safe_load(f)
|
||||
if not target_file or not os.path.exists(target_file):
|
||||
print(
|
||||
f"Custom format with trash_id {trash_id} not found in {custom_formats_dir}"
|
||||
)
|
||||
return 0
|
||||
|
||||
if not data or 'trash_id' not in data:
|
||||
print(f"Invalid custom format data for {custom_format_name}")
|
||||
return 0
|
||||
with open(target_file, "r", encoding="utf-8") as f:
|
||||
data = yaml.safe_load(f)
|
||||
|
||||
if data['trash_id'] != trash_id:
|
||||
# TODO: Better log
|
||||
print(f"Trash ID {trash_id} not found in trash_score_set for custom format {custom_format_name}")
|
||||
return 0
|
||||
if not data or "trash_id" not in data:
|
||||
print(f"Invalid custom format data for {custom_format_name}")
|
||||
return 0
|
||||
|
||||
trash_scores = data.get('trash_scores', {})
|
||||
if not trash_scores:
|
||||
print(f"No trash scores found in {custom_format_name}")
|
||||
return 0
|
||||
if data["trash_id"] != trash_id:
|
||||
continue
|
||||
|
||||
return trash_scores.get(trash_score_set, trash_scores.get('default', 0))
|
||||
trash_scores = data.get("trash_scores", {})
|
||||
if not trash_scores:
|
||||
print(f"No trash scores found in {custom_format_name}")
|
||||
return 0
|
||||
|
||||
return trash_scores.get(trash_score_set, trash_scores.get("default", 0))
|
||||
|
||||
|
||||
def collect_profile_formats(trash_score_set, format_items, output_dir):
|
||||
profile_format = []
|
||||
for name, trash_id in format_items.items():
|
||||
score = find_score_for_custom_format(trash_score_set, name, trash_id, output_dir)
|
||||
if score == 0:
|
||||
continue
|
||||
score = find_score_for_custom_format(
|
||||
trash_score_set, name, trash_id, output_dir
|
||||
)
|
||||
if score == 0:
|
||||
continue
|
||||
|
||||
profile_format.append({
|
||||
'name': name,
|
||||
'score': score
|
||||
})
|
||||
profile_format.append({"name": name, "score": score})
|
||||
return profile_format
|
||||
|
||||
|
||||
def collect_qualities(items):
|
||||
qualities = []
|
||||
quality_id = 1
|
||||
quality_collection_id = -1
|
||||
for item in items:
|
||||
if item.get('allowed', False) is False:
|
||||
continue
|
||||
qualities = []
|
||||
quality_id = 1
|
||||
quality_collection_id = -1
|
||||
for item in items:
|
||||
if item.get("allowed", False) is False:
|
||||
continue
|
||||
|
||||
quality = {
|
||||
'name': item.get('name', ''),
|
||||
}
|
||||
if item.get('items') is not None:
|
||||
quality['id'] = quality_collection_id
|
||||
quality_collection_id -= 1
|
||||
quality['description'] = ''
|
||||
quality['qualities'] = []
|
||||
for sub_item in item['items']:
|
||||
quality['qualities'].append({
|
||||
'id': quality_id,
|
||||
'name': sub_item
|
||||
})
|
||||
quality_id += 1
|
||||
else:
|
||||
quality['id'] = quality_id
|
||||
quality_id += 1
|
||||
qualities.append(quality)
|
||||
quality = {
|
||||
"name": item.get("name", ""),
|
||||
}
|
||||
if item.get("items") is not None:
|
||||
quality["id"] = quality_collection_id
|
||||
quality_collection_id -= 1
|
||||
quality["description"] = ""
|
||||
quality["qualities"] = []
|
||||
for sub_item in item["items"]:
|
||||
quality["qualities"].append({"id": quality_id, "name": sub_item})
|
||||
quality_id += 1
|
||||
else:
|
||||
quality["id"] = quality_id
|
||||
quality_id += 1
|
||||
qualities.append(quality)
|
||||
|
||||
return qualities
|
||||
|
||||
return qualities
|
||||
|
||||
def collect_profile(service, input_json, output_dir):
|
||||
# Compose YAML structure
|
||||
name = input_json.get('name', '')
|
||||
trash_id = input_json.get('trash_id', '')
|
||||
name = input_json.get("name", "")
|
||||
trash_id = input_json.get("trash_id", "")
|
||||
yml_data = {
|
||||
'name': name,
|
||||
'description': f"""[Profile from TRaSH-Guides.](https://trash-guides.info/{service.capitalize()}/{service}-setup-quality-profiles)
|
||||
"name": name,
|
||||
"description": f"""[Profile from TRaSH-Guides.](https://trash-guides.info/{service.capitalize()}/{service}-setup-quality-profiles)
|
||||
|
||||
{markdownify(input_json.get('trash_description', ''))}""".strip(),
|
||||
'trash_id': trash_id,
|
||||
'tags': [],
|
||||
'upgradesAllowed': input_json.get('upgradeAllowed', True),
|
||||
'minCustomFormatScore': input_json.get('minFormatScore', 0),
|
||||
'upgradeUntilScore': input_json.get('cutoffFormatScore', 0),
|
||||
'minScoreIncrement': input_json.get('minUpgradeFormatScore', 0),
|
||||
'qualities': collect_qualities(input_json.get('items', [])),
|
||||
'custom_formats': collect_profile_formats(input_json.get('trash_score_set'), input_json.get('formatItems', {}), output_dir),
|
||||
'language': input_json.get('language', 'any').lower(),
|
||||
"trash_id": trash_id,
|
||||
"tags": [],
|
||||
"upgradesAllowed": input_json.get("upgradeAllowed", True),
|
||||
"minCustomFormatScore": input_json.get("minFormatScore", 0),
|
||||
"upgradeUntilScore": input_json.get("cutoffFormatScore", 0),
|
||||
"minScoreIncrement": input_json.get("minUpgradeFormatScore", 0),
|
||||
"qualities": collect_qualities(input_json.get("items", [])),
|
||||
"custom_formats": collect_profile_formats(
|
||||
input_json.get("trash_score_set"),
|
||||
input_json.get("formatItems", {}),
|
||||
output_dir,
|
||||
),
|
||||
"language": input_json.get("language", "any").lower(),
|
||||
}
|
||||
|
||||
# Output path
|
||||
output_path = os.path.join(output_dir, f"{get_file_name(name)}.yml")
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
with open(output_path, "w", encoding="utf-8") as f:
|
||||
yaml.dump(yml_data, f, sort_keys=False, allow_unicode=True)
|
||||
print(f"Generated: {output_path}")
|
||||
|
||||
|
||||
def collect_profiles(service, input_dir, output_dir):
|
||||
for root, _, files in os.walk(input_dir):
|
||||
for filename in files:
|
||||
if not filename.endswith('.json'):
|
||||
if not filename.endswith(".json"):
|
||||
continue
|
||||
|
||||
file_path = os.path.join(root, filename)
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
collect_profile(service, data, output_dir)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ import os
|
|||
import json
|
||||
import yaml
|
||||
|
||||
# TODO: prevent duplicates by only writing unique regex patterns to files
|
||||
# In some cases negations will result in a new regex pattern as of now
|
||||
|
||||
|
||||
def collect_regex_pattern(service, file_name, input_json, output_dir):
|
||||
# Find the first pattern in specifications
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue