1717from xml .etree import ElementTree
1818from xml .etree .ElementTree import Element
1919
20+ import mobase
21+ import yaml
2022from PyQt6 import QtCore
2123from PyQt6 .QtCore import (
2224 QCoreApplication ,
3638 QProgressDialog ,
3739)
3840
39- import mobase
40-
4141from ..basic_features import (
4242 BasicGameSaveGameInfo ,
4343 BasicLocalSavegames ,
@@ -208,6 +208,11 @@ def settings(self):
208208 "Force reparsing mod metadata immediately." ,
209209 False ,
210210 ),
211+ mobase .PluginSetting (
212+ "convert_jsons_to_yaml" ,
213+ "Convert all jsons in active mods to yaml immediately." ,
214+ False ,
215+ ),
211216 mobase .PluginSetting (
212217 "check_for_lslib_updates" ,
213218 "Check to see if there has been a new release of LSLib and create download dialog if so." ,
@@ -218,6 +223,11 @@ def settings(self):
218223 "Extract the full pak when parsing metadata, instead of just meta.lsx." ,
219224 False ,
220225 ),
226+ mobase .PluginSetting (
227+ "convert_yamls_to_json" ,
228+ "Convert YAMLs to JSONs when executable runs. Allows one to configure ScriptExtender and related mods with YAML files." ,
229+ False ,
230+ ),
221231 ]
222232 for setting in custom_settings :
223233 setting .description = self .__tr (setting .description )
@@ -293,15 +303,41 @@ def map_files(
293303 dest_func : Callable [[Path ], str ] = (
294304 (lambda f : os .path .relpath (f , path )) if rel else lambda f : f .name
295305 )
296- for file in list (path .rglob (pattern )):
297- mappings .append (
298- mobase .Mapping (
299- source = str (file ),
300- destination = str (dest / dest_func (file )),
301- is_directory = file .is_dir (),
302- create_target = True ,
303- )
306+ found_jsons : set [Path ] = set ()
307+ add_mapping : Callable [[Path ], None ] = lambda file : mappings .append (
308+ mobase .Mapping (
309+ source = str (file ),
310+ destination = str (dest / dest_func (file )),
311+ is_directory = file .is_dir (),
312+ create_target = True ,
304313 )
314+ )
315+ for file in list (path .rglob (pattern )):
316+ if self ._convert_yamls_to_json and (
317+ file .name .endswith (".yaml" ) or file .name .endswith (".yml" )
318+ ):
319+ converted_path = file .parent / file .name .replace (
320+ ".yaml" , ".json"
321+ ).replace (".yml" , ".json" )
322+ try :
323+ if not converted_path .exists () or os .path .getmtime (
324+ file
325+ ) > os .path .getmtime (converted_path ):
326+ with open (file , "r" ) as yaml_file :
327+ with open (converted_path , "w" ) as json_file :
328+ json .dump (
329+ yaml .safe_load (yaml_file ), json_file , indent = 2
330+ )
331+ qDebug (f"Converted { file } to JSON" )
332+ found_jsons .add (converted_path )
333+ except OSError as e :
334+ qWarning (f"Error accessing file { converted_path } : { e } " )
335+ elif file .name .endswith (".json" ):
336+ found_jsons .add (file )
337+ else :
338+ add_mapping (file )
339+ for file in found_jsons :
340+ add_mapping (file )
305341
306342 progress = self ._create_progress_window (
307343 "Mapping files to documents folder" , len (active_mods ) + 1
@@ -323,6 +359,39 @@ def map_files(
323359 progress .close ()
324360 return mappings
325361
362+ def _convert_jsons_to_yaml (self ):
363+ qInfo ("converting all json files to yaml" )
364+ active_mods = self ._active_mods ()
365+
366+ def map_files (path : Path ):
367+ for file in list (path .rglob ("*.json" )):
368+ converted_path = file .parent / file .name .replace (".json" , ".yaml" )
369+ try :
370+ if not converted_path .exists () or os .path .getmtime (
371+ file
372+ ) > os .path .getmtime (converted_path ):
373+ with open (file , "r" ) as json_file :
374+ with open (converted_path , "w" ) as yaml_file :
375+ yaml .dump (json .load (json_file ), yaml_file , indent = 2 )
376+ qInfo (f"Converted { file } to YAML" )
377+ except OSError as e :
378+ qWarning (f"Error accessing file { converted_path } : { e } " )
379+
380+ progress = self ._create_progress_window (
381+ "Converting all json files to yaml" , len (active_mods ) + 1
382+ )
383+ for mod in active_mods :
384+ map_files (Path (mod .absolutePath ()))
385+ progress .setValue (progress .value () + 1 )
386+ QApplication .processEvents ()
387+ if progress .wasCanceled ():
388+ qWarning ("conversion canceled by user" )
389+ return
390+ map_files (self ._overwrite_path )
391+ progress .setValue (len (active_mods ) + 1 )
392+ QApplication .processEvents ()
393+ progress .close ()
394+
326395 @cached_property
327396 def _base_dlls (self ) -> set [str ]:
328397 base_bin = Path (self .gameDirectory ().absoluteFilePath ("bin" ))
@@ -381,6 +450,10 @@ def _force_load_dlls(self):
381450 def _log_diff (self ):
382451 return bool (self ._get_setting ("log_diff" ))
383452
453+ @cached_property
454+ def _convert_yamls_to_json (self ):
455+ return bool (self ._get_setting ("convert_yamls_to_json" ))
456+
384457 @cached_property
385458 def _needed_lslib_files (self ):
386459 return {
@@ -454,12 +527,18 @@ def _on_settings_changed(
454527 )
455528 finally :
456529 self ._set_setting (setting , False )
530+ elif new and setting == "convert_jsons_to_yaml" :
531+ try :
532+ self ._convert_jsons_to_yaml ()
533+ finally :
534+ self ._set_setting (setting , False )
457535 elif setting in {
458536 "extract_full_package" ,
459537 "autobuild_paks" ,
460538 "remove_extracted_metadata" ,
461539 "force_load_dlls" ,
462540 "log_diff" ,
541+ "convert_yamls_to_json" ,
463542 } and hasattr (self , f"_{ setting } " ):
464543 delattr (self , f"_{ setting } " )
465544
0 commit comments