Skip to content

Commit 9747d57

Browse files
committed
improve config system
1 parent 829c340 commit 9747d57

File tree

8 files changed

+102
-149
lines changed

8 files changed

+102
-149
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# personal
22
test_data*/
33
tests/
4+
config.json
45

56
# Byte-compiled / optimized / DLL files
67
__pycache__/

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ The Python scripts are made to run on windows devices only, but may work on othe
3636
If you have not installed **ffmpeg** then do so, because it is required. Also don't forget to add it to your PATH environment variables.
3737

3838
## Setup
39+
Copy the `config-sample.json` and rename it to `config.json`
40+
3941
### First Steps
4042
1. run `install_requirements.bat` to install required python packages
4143
2. run `make_spec.bat` to create a spec file with pyinstaller

make_spec.bat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ pyi-makespec --onefile --icon=build_assets/favicon.ico --name %SPEC_FILE_NAME% s
1010
rem Add Python statement to copy config.ini to build folder
1111
ECHO.>>"%SPEC_FILE_NAME%.spec"
1212
ECHO import shutil>>"%SPEC_FILE_NAME%.spec"
13-
ECHO shutil.copyfile('src/config.ini', '{0}/config.ini'.format(DISTPATH))>>"%SPEC_FILE_NAME%.spec"
13+
ECHO shutil.copyfile('src/config.json', '{0}/config.json'.format(DISTPATH))>>"%SPEC_FILE_NAME%.spec"

src/config-sample.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"FileFilter": "flac|m4a",
3+
"ExportFormat": "aiff",
4+
"ExportQuality": "normal",
5+
"ConvertedFilesDirName": "converted",
6+
"RemoveConvertedFiles": false,
7+
"MirrorFileStructure": true,
8+
"RecreateFileNameFromMetadata": true,
9+
"RecreateFileNameTemplate": "$ARTIST - $TITLE",
10+
"VerboseFFMPEGOutputs": true
11+
}

src/config.ini

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/modules/audio_converter.py

Lines changed: 15 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,6 @@ def __init__(self) -> None:
1414
# outputs
1515
self.allowed_formats = ['aiff', 'wav']
1616
self.allowed_quality = ['normal', 'high', 'copy']
17-
try:
18-
self.settings = {
19-
"file_filter": config['FileFilter'],
20-
"export_format": config['ExportFormat'],
21-
"export_quality": config['ExportQuality'],
22-
"converted_files_dir_name": config['ConvertedFilesDirName'],
23-
"remove_converted_files": config['RemoveConvertedFiles'],
24-
"mirror_file_structure": config['MirrorFileStructure'],
25-
"native_ffmpeg": config['NativeFFMPEG'],
26-
"file_name_modifications": {
27-
"title_separator": config['TitleSeparator'],
28-
"custom_regex_replacement": config['CustomRegexReplacement'],
29-
"recreate_file_name_from_metadata": config['RecreateFileNameFromMetadata']
30-
}
31-
}
32-
except Exception:
33-
print("ERROR: could not read AudioConverter settings from config")
34-
3517
self.ffmpeg_type_arguments = {
3618
"aiff_normal": {
3719
"codec": 'pcm_s16be', # 16 Bit PCM Big Endian
@@ -72,7 +54,9 @@ def __init__(self) -> None:
7254
}
7355

7456
# all ffmpeg arguments: https://gist.github.com/tayvano/6e2d456a9897f55025e25035478a3a50
75-
def generate_ffmpeg_arguments(self, in_audio: Path, out_audio: Path, in_cover: Path or None = None, quality='normal', verbose=False) -> list:
57+
def generate_ffmpeg_arguments(self, in_audio: Path, out_audio: Path, in_cover: Path or None = None) -> list:
58+
verbose = config['VerboseFFMPEGOutputs']
59+
quality = config['ExportQuality']
7660
in_format = in_audio.suffix.replace('.', '')
7761
out_format = out_audio.suffix.replace('.', '')
7862
if out_format not in self.allowed_formats:
@@ -144,7 +128,7 @@ def generate_file_tree(self, paths: list, mirror_file_structure=True, is_files=T
144128
directory = paths[0]
145129
root_path_parent = Path(directory).parent.resolve()
146130
root_target_folder_name = str(Path(directory).resolve())[len(str(root_path_parent))+1:]
147-
converted_files_dir_abs = f"{root_path_parent}/{root_target_folder_name}_{self.settings['converted_files_dir_name']}-{int(datetime.utcnow().timestamp())}"
131+
converted_files_dir_abs = f"{root_path_parent}/{root_target_folder_name}_{config['ConvertedFilesDirName']}-{int(datetime.utcnow().timestamp())}"
148132
Path(converted_files_dir_abs).mkdir(parents=True, exist_ok=True)
149133

150134
summary = {
@@ -167,12 +151,10 @@ def generate_file_tree(self, paths: list, mirror_file_structure=True, is_files=T
167151
summary["total"] += 1
168152
if self.is_file_type_correct(file):
169153
self.save_print(f"\t* {file}")
170-
if (self.settings['native_ffmpeg']):
171-
converted_without_errors = self.convert_file_to_wav_with_ffmpeg(
172-
Path.joinpath(abs_root, file), converted_files_subdir_abs)
173-
else:
174-
converted_without_errors = self.convert_file_to_wav_with_pydub(
175-
Path.joinpath(abs_root, file), converted_files_subdir_abs)
154+
converted_without_errors = self.convert_file_to_wav_with_ffmpeg(
155+
Path.joinpath(abs_root, file),
156+
converted_files_subdir_abs
157+
)
176158

177159
if converted_without_errors:
178160
summary["converted"] += 1
@@ -190,7 +172,7 @@ def generate_file_tree(self, paths: list, mirror_file_structure=True, is_files=T
190172

191173
def is_file_type_correct(self, file) -> bool:
192174
file_str = str(file)
193-
regex = re.findall(f'.*\.({self.settings["file_filter"]})', file_str)
175+
regex = re.findall(f'.*\.({config["FileFilter"]})', file_str)
194176
return (len(regex) == 1) and ('\n' not in file_str)
195177

196178
def fix_windows_file_name(self, file_name: str) -> str:
@@ -201,9 +183,9 @@ def fix_windows_file_name(self, file_name: str) -> str:
201183
_file_name = file_name.replace(c, 'X')
202184
return _file_name
203185

204-
def improve_file_name_from_metadata(self, file_path: Path, template_format='$ARTIST - $TITLE'):
186+
def improve_file_name_from_metadata(self, file_path: Path):
205187
file_info = mediainfo(str(file_path)).get('TAG', {})
206-
file_name = template_format
188+
file_name = config['RecreateFileNameTemplate']
207189

208190
template_key_value_list = [
209191
{
@@ -230,7 +212,7 @@ def improve_file_name_from_metadata(self, file_path: Path, template_format='$ART
230212

231213
def convert_file_to_wav_with_ffmpeg(self, file_path: Path, target_path):
232214
# filename manipulations
233-
if self.settings['file_name_modifications']:
215+
if config['RecreateFileNameFromMetadata']:
234216
modified_file_name = self.improve_file_name_from_metadata(file_path)
235217
new_file_name = modified_file_name or file_path.name.replace(file_path.suffix, '').strip()
236218
else:
@@ -240,7 +222,7 @@ def convert_file_to_wav_with_ffmpeg(self, file_path: Path, target_path):
240222
new_file_name = self.fix_windows_file_name(new_file_name)
241223

242224
# export
243-
export_file_format = self.settings['export_format']
225+
export_file_format = config['ExportFormat']
244226
self.save_print(f"\t\t-> {new_file_name}.{export_file_format}")
245227

246228
output_audio = Path.joinpath(Path(target_path), f"{new_file_name}.{export_file_format}").resolve()
@@ -251,9 +233,7 @@ def convert_file_to_wav_with_ffmpeg(self, file_path: Path, target_path):
251233
command = self.generate_ffmpeg_arguments(
252234
input_audio,
253235
output_audio,
254-
input_cover_image,
255-
quality='normal',
256-
verbose=True
236+
input_cover_image
257237
)
258238
subprocess.call(command, timeout=200)
259239

@@ -262,45 +242,7 @@ def convert_file_to_wav_with_ffmpeg(self, file_path: Path, target_path):
262242
print("ERROR: Conversion failed")
263243
return False
264244

265-
if self.settings['remove_converted_files']:
266-
# remove original file
267-
file_path.unlink()
268-
269-
return True
270-
271-
def convert_file_to_wav_with_pydub(self, file_path: Path, target_path):
272-
flac_tmp_audio_data = AudioSegment.from_file(
273-
file_path, file_path.suffix[1:])
274-
275-
old_file_info = mediainfo(str(file_path)).get('TAG', {})
276-
277-
# filename manipulations
278-
if self.settings['file_name_modifications']:
279-
modified_file_name = self.improve_file_name_from_metadata(file_path)
280-
new_file_name = modified_file_name or file_path.name.replace(file_path.suffix, '').strip()
281-
else:
282-
new_file_name = file_path.name.replace(file_path.suffix, '').strip()
283-
284-
# fix windows file name
285-
new_file_name = self.fix_windows_file_name(new_file_name)
286-
287-
# export
288-
export_file_format = self.settings['export_format']
289-
self.save_print(f"\t\t-> {new_file_name}.{export_file_format}")
290-
291-
try:
292-
complete_file_name = str(
293-
Path.joinpath(Path(target_path), f"{new_file_name}.{export_file_format}").resolve())
294-
flac_tmp_audio_data.export(
295-
complete_file_name,
296-
format=export_file_format,
297-
tags=old_file_info
298-
)
299-
except Exception:
300-
self.save_print(f"ERROR: Error while saving file {new_file_name}")
301-
return False
302-
303-
if self.settings['remove_converted_files']:
245+
if config['RemoveConvertedFiles']:
304246
# remove original file
305247
file_path.unlink()
306248

src/modules/config.py

Lines changed: 28 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,35 @@
1-
import configparser
1+
import json
22
import sys
33
from pathlib import Path
44

5-
config_parser = configparser.ConfigParser()
6-
7-
application_path: Path = (Path(sys.executable) if getattr(sys, 'frozen', False) else Path(__file__).parent).parent.resolve()
8-
config_path = Path.joinpath(application_path, 'config.ini')
5+
application_path: Path = (Path(sys.executable) if getattr(
6+
sys, 'frozen', False) else Path(__file__).parent).parent.resolve()
7+
config_path = Path.joinpath(application_path, 'config.json')
98
print(f'INFO: Looking for config file in directory "{config_path}"')
10-
config_parser.read(config_path)
119

10+
config_defaults = {
11+
"FileFilter": "flac|m4a",
12+
"ExportFormat": "aiff",
13+
"ExportQuality": "normal",
14+
"ConvertedFilesDirName": "converted",
15+
"RemoveConvertedFiles": False,
16+
"MirrorFileStructure": True,
17+
"RecreateFileNameFromMetadata": True,
18+
"VerboseFFMPEGOutputs": True
19+
}
20+
21+
22+
def save_config():
23+
with open(config_path, 'w', encoding='utf8') as f:
24+
json.dump(config, f)
1225

13-
def try_config_get(section, key, fallback):
14-
fallback_type = type(fallback)
26+
27+
def load_config():
1528
try:
16-
if fallback_type is int:
17-
return config_parser.getint(section, key)
18-
elif fallback_type is bool:
19-
return config_parser.getboolean(section, key)
20-
elif fallback_type is float:
21-
return config_parser.getfloat(section, key)
22-
else:
23-
return config_parser.get(section, key)
24-
except Exception:
25-
print(
26-
f"ERROR: could not parse value of {section}/{key}, returning fallback value")
27-
return fallback
28-
29-
30-
def get_config():
31-
return {
32-
"FileFilter": try_config_get('AUDIOPARSER', 'FileFilter', fallback='flac|m4a'),
33-
"ExportFormat": try_config_get('AUDIOPARSER', 'ExportFormat', fallback='wav'),
34-
"ExportQuality": try_config_get('AUDIOPARSER', 'ExportQuality', fallback='normal'),
35-
"ConvertedFilesDirName": try_config_get('AUDIOPARSER', 'ConvertedFilesDirName', fallback='converted'),
36-
"RemoveConvertedFiles": try_config_get('AUDIOPARSER', 'RemoveConvertedFiles', fallback=False),
37-
"MirrorFileStructure": try_config_get('AUDIOPARSER', 'MirrorFileStructure', fallback=True),
38-
"NativeFFMPEG": try_config_get('AUDIOPARSER', 'NativeFFMPEG', fallback=True),
39-
"TitleSeparator": try_config_get('AUDIOPARSER/FILENAMEMODIFICATIONS', 'TitleSeparator', fallback='-'),
40-
"CustomRegexReplacement": try_config_get('AUDIOPARSER/FILENAMEMODIFICATIONS', 'CustomRegexReplacement', fallback=''),
41-
"RecreateFileNameFromMetadata": try_config_get('AUDIOPARSER/FILENAMEMODIFICATIONS', 'RecreateFileNameFromMetadata', fallback=True),
42-
}
43-
44-
45-
config = get_config()
29+
with open(config_path, 'r', encoding='utf8') as f:
30+
return json.load(f)
31+
except:
32+
return config_defaults
33+
34+
35+
config: dict = load_config()

0 commit comments

Comments
 (0)