mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-04-06 00:32:05 +02:00
Fixed many profile issues and cleaned up some messes. (#10686)
This commit is contained in:
@@ -214,7 +214,7 @@ def check_machine_default_materials(profiles_dir, vendor_name):
|
||||
|
||||
return error_count, 0
|
||||
|
||||
def check_filament_name_consistency(profiles_dir, vendor_name):
|
||||
def check_name_consistency(profiles_dir, vendor_name):
|
||||
"""
|
||||
Make sure filament profile names match in both vendor json and subpath files.
|
||||
Filament profiles work only if the name in <vendor>.json matches the name in sub_path file,
|
||||
@@ -243,39 +243,40 @@ def check_filament_name_consistency(profiles_dir, vendor_name):
|
||||
print_error(f"Error loading vendor profile {vendor_file}: {e}")
|
||||
return 1, 0
|
||||
|
||||
if 'filament_list' not in data:
|
||||
return 0, 0
|
||||
|
||||
for child in data['filament_list']:
|
||||
name_in_vendor = child['name']
|
||||
sub_path = child['sub_path']
|
||||
sub_file = vendor_dir / sub_path
|
||||
|
||||
if not sub_file.exists():
|
||||
print_error(f"Missing sub profile: '{sub_path}' declared in {vendor_file.relative_to(profiles_dir)}")
|
||||
error_count += 1
|
||||
for section in ['filament_list', 'machine_model_list', 'machine_list', 'process_list']:
|
||||
if section not in data:
|
||||
continue
|
||||
|
||||
for child in data[section]:
|
||||
name_in_vendor = child['name']
|
||||
sub_path = child['sub_path']
|
||||
sub_file = vendor_dir / sub_path
|
||||
|
||||
try:
|
||||
with open(sub_file, 'r', encoding='UTF-8') as fp:
|
||||
sub_data = json.load(fp)
|
||||
except Exception as e:
|
||||
print_error(f"Error loading profile {sub_file}: {e}")
|
||||
error_count += 1
|
||||
continue
|
||||
|
||||
name_in_sub = sub_data['name']
|
||||
|
||||
if name_in_sub == name_in_vendor:
|
||||
continue
|
||||
|
||||
if 'renamed_from' in sub_data:
|
||||
renamed_from = [n.strip() for n in sub_data['renamed_from'].split(';')]
|
||||
if name_in_vendor in renamed_from:
|
||||
if not sub_file.exists():
|
||||
print_error(f"Missing sub profile: '{sub_path}' declared in {vendor_file.relative_to(profiles_dir)}")
|
||||
error_count += 1
|
||||
continue
|
||||
|
||||
print_error(f"Filament name mismatch: required '{name_in_vendor}' in {vendor_file.relative_to(profiles_dir)} but found '{name_in_sub}' in {sub_file.relative_to(profiles_dir)}, and none of its `renamed_from` matches the required name either")
|
||||
error_count += 1
|
||||
try:
|
||||
with open(sub_file, 'r', encoding='UTF-8') as fp:
|
||||
sub_data = json.load(fp)
|
||||
except Exception as e:
|
||||
print_error(f"Error loading profile {sub_file}: {e}")
|
||||
error_count += 1
|
||||
continue
|
||||
|
||||
name_in_sub = sub_data['name']
|
||||
|
||||
if name_in_sub == name_in_vendor:
|
||||
continue
|
||||
|
||||
# if 'renamed_from' in sub_data:
|
||||
# renamed_from = [n.strip() for n in sub_data['renamed_from'].split(';')]
|
||||
# if name_in_vendor in renamed_from:
|
||||
# continue
|
||||
|
||||
print_error(f"{section} name mismatch: required '{name_in_vendor}' in {vendor_file.relative_to(profiles_dir)} but found '{name_in_sub}' in {sub_file.relative_to(profiles_dir)}")
|
||||
error_count += 1
|
||||
|
||||
return error_count, 0
|
||||
|
||||
@@ -385,7 +386,7 @@ def main():
|
||||
if args.check_obsolete_keys:
|
||||
warnings_found += check_obsolete_keys(profiles_dir, vendor_name)
|
||||
|
||||
new_errors, new_warnings = check_filament_name_consistency(profiles_dir, vendor_name)
|
||||
new_errors, new_warnings = check_name_consistency(profiles_dir, vendor_name)
|
||||
errors_found += new_errors
|
||||
warnings_found += new_warnings
|
||||
|
||||
|
||||
@@ -3,6 +3,22 @@ import json
|
||||
import argparse
|
||||
from collections import defaultdict
|
||||
|
||||
def create_ordered_profile(profile_dict, priority_fields=['name', 'type']):
|
||||
"""Create a new dictionary with priority fields first"""
|
||||
ordered_profile = {}
|
||||
|
||||
# Add priority fields first
|
||||
for field in priority_fields:
|
||||
if field in profile_dict:
|
||||
ordered_profile[field] = profile_dict[field]
|
||||
|
||||
# Add remaining fields
|
||||
for key, value in profile_dict.items():
|
||||
if key not in priority_fields:
|
||||
ordered_profile[key] = value
|
||||
|
||||
return ordered_profile
|
||||
|
||||
def topological_sort(filaments):
|
||||
# Build a graph of dependencies
|
||||
graph = defaultdict(list)
|
||||
@@ -49,67 +65,141 @@ def topological_sort(filaments):
|
||||
|
||||
return result
|
||||
|
||||
def update_profile_library(vendor="OrcaFilamentLibrary",profile_type="filament"):
|
||||
def update_profile_library(vendor="",profile_type="filament"):
|
||||
# change current working directory to the relative path(..\resources\profiles) compare to script location
|
||||
os.chdir(os.path.join(os.path.dirname(__file__), '..', 'resources', 'profiles'))
|
||||
|
||||
# Collect current profile entries
|
||||
current_profiles = []
|
||||
base_dir = vendor
|
||||
profile_dir = os.path.join(base_dir, profile_type)
|
||||
|
||||
for root, dirs, files in os.walk(profile_dir):
|
||||
for file in files:
|
||||
if file.lower().endswith('.json'):
|
||||
full_path = os.path.join(root, file)
|
||||
if vendor:
|
||||
vendors = [vendor]
|
||||
else:
|
||||
profiles_dir = os.path.join(os.path.dirname(__file__), '..', 'resources', 'profiles')
|
||||
vendors = [f[:-5] for f in os.listdir(profiles_dir) if f.lower().endswith('.json')]
|
||||
for vendor in vendors:
|
||||
current_profiles = []
|
||||
base_dir = vendor
|
||||
# Orca expects machine_model to be in the machine folder
|
||||
if profile_type == 'machine_model':
|
||||
profile_dir = os.path.join(base_dir, 'machine')
|
||||
else:
|
||||
profile_dir = os.path.join(base_dir, profile_type)
|
||||
|
||||
for root, dirs, files in os.walk(profile_dir):
|
||||
for file in files:
|
||||
if file.lower().endswith('.json'):
|
||||
full_path = os.path.join(root, file)
|
||||
|
||||
# Get relative path from base directory
|
||||
sub_path = os.path.relpath(full_path, base_dir).replace('\\', '/')
|
||||
|
||||
try:
|
||||
with open(full_path, 'r', encoding='utf-8') as f:
|
||||
_profile = json.load(f)
|
||||
if _profile.get('type') != profile_type:
|
||||
continue
|
||||
name = _profile.get('name')
|
||||
inherits = _profile.get('inherits')
|
||||
|
||||
if name:
|
||||
entry = {
|
||||
"name": name,
|
||||
"sub_path": sub_path
|
||||
}
|
||||
if inherits:
|
||||
entry['inherits'] = inherits
|
||||
current_profiles.append(entry)
|
||||
else:
|
||||
print(f"Warning: Missing 'name' in {full_path}")
|
||||
except Exception as e:
|
||||
print(f"Error reading {full_path}: {str(e)}")
|
||||
continue
|
||||
|
||||
# Sort profiles based on inheritance
|
||||
sorted_profiles = topological_sort(current_profiles)
|
||||
|
||||
# Remove the inherits field as it's not needed in the final JSON
|
||||
for p in sorted_profiles:
|
||||
p.pop('inherits', None)
|
||||
|
||||
# Update library file
|
||||
lib_path = f'{vendor}.json'
|
||||
|
||||
profile_section = profile_type+'_list'
|
||||
|
||||
try:
|
||||
with open(lib_path, 'r+', encoding='utf-8') as f:
|
||||
library = json.load(f)
|
||||
library[profile_section] = sorted_profiles
|
||||
f.seek(0)
|
||||
json.dump(library, f, indent=4, ensure_ascii=False)
|
||||
f.truncate()
|
||||
|
||||
# Get relative path from base directory
|
||||
sub_path = os.path.relpath(full_path, base_dir).replace('\\', '/')
|
||||
|
||||
try:
|
||||
with open(full_path, 'r', encoding='utf-8') as f:
|
||||
filament_data = json.load(f)
|
||||
name = filament_data.get('name')
|
||||
inherits = filament_data.get('inherits')
|
||||
|
||||
if name:
|
||||
entry = {
|
||||
"name": name,
|
||||
"sub_path": sub_path
|
||||
}
|
||||
if inherits:
|
||||
entry['inherits'] = inherits
|
||||
current_profiles.append(entry)
|
||||
else:
|
||||
print(f"Warning: Missing 'name' in {full_path}")
|
||||
except Exception as e:
|
||||
print(f"Error reading {full_path}: {str(e)}")
|
||||
continue
|
||||
print(f"Profile library for {vendor} updated successfully!")
|
||||
except Exception as e:
|
||||
print(f"Error updating library file: {str(e)}")
|
||||
|
||||
# Sort profiles based on inheritance
|
||||
sorted_profiles = topological_sort(current_profiles)
|
||||
|
||||
# Remove the inherits field as it's not needed in the final JSON
|
||||
for p in sorted_profiles:
|
||||
p.pop('inherits', None)
|
||||
def clean_up_profile(vendor="", profile_type="", force=False):
|
||||
# change current working directory to the relative path(..\resources\profiles) compare to script location
|
||||
os.chdir(os.path.join(os.path.dirname(__file__), '..', 'resources', 'profiles'))
|
||||
|
||||
# Update library file
|
||||
lib_path = f'{vendor}.json'
|
||||
# Collect current profile entries
|
||||
if vendor:
|
||||
vendors = [vendor]
|
||||
else:
|
||||
profiles_dir = os.path.join(os.path.dirname(__file__), '..', 'resources', 'profiles')
|
||||
vendors = [f[:-5] for f in os.listdir(profiles_dir) if f.lower().endswith('.json')]
|
||||
for vendor in vendors:
|
||||
current_profiles = []
|
||||
base_dir = vendor
|
||||
# Orca expects machine_model to be in the machine folder
|
||||
if profile_type == 'machine_model':
|
||||
profile_dir = os.path.join(base_dir, 'machine')
|
||||
else:
|
||||
profile_dir = os.path.join(base_dir, profile_type)
|
||||
|
||||
for root, dirs, files in os.walk(profile_dir):
|
||||
for file in files:
|
||||
if file.lower().endswith('.json'):
|
||||
full_path = os.path.join(root, file)
|
||||
|
||||
# Get relative path from base directory
|
||||
sub_path = os.path.relpath(full_path, base_dir).replace('\\', '/')
|
||||
|
||||
try:
|
||||
with open(full_path, 'r+', encoding='utf-8') as f:
|
||||
_profile = json.load(f)
|
||||
need_update = False
|
||||
if not _profile.get('type') or _profile.get('type') == "":
|
||||
need_update = True
|
||||
name = _profile.get('name')
|
||||
inherits = _profile.get('inherits')
|
||||
if profile_type == "machine_model" or profile_type == "machine":
|
||||
if "nozzle" in name or "Nozzle" in name:
|
||||
_profile['type'] = "machine"
|
||||
else:
|
||||
_profile['type'] = "machine_model"
|
||||
else:
|
||||
_profile['type'] = profile_type
|
||||
print(f"Added type: {_profile['type']} to {file}")
|
||||
|
||||
profile_section = profile_type+'_list'
|
||||
|
||||
try:
|
||||
with open(lib_path, 'r+', encoding='utf-8') as f:
|
||||
library = json.load(f)
|
||||
library[profile_section] = sorted_profiles
|
||||
f.seek(0)
|
||||
json.dump(library, f, indent=4, ensure_ascii=False)
|
||||
f.truncate()
|
||||
|
||||
print(f"Profile library for {vendor} updated successfully!")
|
||||
except Exception as e:
|
||||
print(f"Error updating library file: {str(e)}")
|
||||
fields_to_remove = ['version', 'is_custom_defined']
|
||||
for field in fields_to_remove:
|
||||
if _profile.get(field):
|
||||
# remove version field
|
||||
del _profile[field]
|
||||
print(f"Removed {field} field from {file}")
|
||||
need_update = True
|
||||
|
||||
if need_update or force:
|
||||
# write back to file
|
||||
f.seek(0)
|
||||
ordered_profile = create_ordered_profile(_profile, ['type', 'name', 'renamed_from', 'inherits', 'from', 'setting_id', 'filament_id', 'instantiation'])
|
||||
json.dump(ordered_profile, f, indent=4, ensure_ascii=False)
|
||||
f.truncate()
|
||||
print(f"Updated profile: {full_path}")
|
||||
except Exception as e:
|
||||
print(f"Error reading {full_path}: {str(e)}")
|
||||
continue
|
||||
|
||||
# For each JSON file, it will:
|
||||
# - Replace "BBL X1C" with "System" in the name field
|
||||
@@ -156,14 +246,27 @@ def rename_filament_system(vendor="OrcaFilamentLibrary"):
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='Update filament library for specified vendor')
|
||||
parser.add_argument('-v', '--vendor', type=str, default="OrcaFilamentLibrary",
|
||||
help='Vendor name (default: OrcaFilamentLibrary)')
|
||||
parser.add_argument('-m', '--mode', type=str, choices=['update', 'rename'],
|
||||
default='update', help='Operation mode (default: update)')
|
||||
parser.add_argument('-v', '--vendor', type=str, default="",
|
||||
help='Vendor name (default: "" which means all vendors)')
|
||||
parser.add_argument('-u', '--update', action='store_true', help='update vendor.json')
|
||||
parser.add_argument('-p', '--profile_type', type=str, choices=['machine_model', 'process', 'filament', 'machine'], help='profile type (default: "" which means all types)')
|
||||
parser.add_argument('-f', '--fix', action='store_true', help='Fix errors like missing type field, and clean up the profile')
|
||||
parser.add_argument('--force', action='store_true', help='Force update the profile files, for --fix option')
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.mode == 'update':
|
||||
update_profile_library(args.vendor, 'filament')
|
||||
if args.fix:
|
||||
if(args.profile_type):
|
||||
clean_up_profile(args.vendor, args.profile_type, args.force)
|
||||
else:
|
||||
clean_up_profile(args.vendor, 'machine_model', args.force)
|
||||
clean_up_profile(args.vendor, 'process', args.force)
|
||||
clean_up_profile(args.vendor, 'filament', args.force)
|
||||
clean_up_profile(args.vendor, 'machine', args.force)
|
||||
|
||||
if args.update:
|
||||
update_profile_library(args.vendor, 'machine_model')
|
||||
update_profile_library(args.vendor, 'process')
|
||||
update_profile_library(args.vendor, 'filament')
|
||||
update_profile_library(args.vendor, 'machine')
|
||||
else:
|
||||
rename_filament_system(args.vendor)
|
||||
Reference in New Issue
Block a user