-
Notifications
You must be signed in to change notification settings - Fork 0
/
audio_process.py
executable file
·142 lines (111 loc) · 3.8 KB
/
audio_process.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#!/usr/bin/env python3
# move all non audio files to a + directory at the same level in the hierarchy
# complete extensions
# run replaygain
# TODO
# check that the track numbers are consecutive and unique
import fnmatch
import os
import re
import shutil
import multiprocessing
from pathlib import Path
import subprocess
# case should be ok by now
IGNORE = ('folder.jpg', '+')
EXT = ('flac', 'opus', 'ogg', 'mp3')
DEL_EXT = ('m3u', 'db', 'DS_Store')
def move_file_anyway(f):
if re.search(r'00-.*pregap\.', str(f)):
return True
else:
return False
def child_containing_matching_f(root, ext=EXT):
"""
Yields folders containing files of specified extension.
"""
seen = set()
for x in ext:
# no yield from rglob, as it might create an exception for rmed files
for c in list(root.rglob('*.' + x)):
if not c.exists():
continue
if (not move_file_anyway(c.name) and
'+' not in (d.name for d in c.absolute().parents)
and c.parent.exists()):
if c.parent not in seen:
yield c.parent
seen.add(c.parent)
def clean_files():
"""
Moves irrelevant files to a '+' folder.
"""
root = Path('.')
for d in child_containing_matching_f(root):
assert d.is_dir(), d
dst = d / '+'
dst.mkdir(exist_ok=True)
for f in d.glob('*'):
if f.name in IGNORE:
continue
ext = str(f.suffix)[1:]
if ext in DEL_EXT:
f.unlink()
elif ext not in EXT or move_file_anyway(f):
print(f'moving {f}')
try:
shutil.move(str(f), str(dst))
except shutil.Error:
f.unlink()
def rename_cue_files():
root = Path('.')
for d in child_containing_matching_f(root):
# XXX: should be case insensitive...
for f in d.rglob('*.cue'):
new_path = f.parent.absolute() / (f.name + '.ignore')
f.rename(new_path)
def get_artist_name_from_folder_name(s):
pattern = re.compile(
r"(?P<artist>.*) - (.*) \((?P<year>\d{4})\)")
match = pattern.match(s)
if match:
return match.group("artist")
def test_get_artist_name_from_folder_name():
s = 'Archive - Londinium (1996) (CD) (524 285 - 2; ARKCD 1001)'
assert get_artist_name_from_folder_name(s) == 'Archive'
s = 'Run-D.M.C. - Tougher than Leather (1988) (Vinyl) (ve)'
assert get_artist_name_from_folder_name(s) == 'Run-D.M.C.'
s = 'CYNE - Pretty Dark Things (2008) (CD)'
assert get_artist_name_from_folder_name(s) == 'CYNE'
def move_to_artist_folder():
root = Path('.')
for d in child_containing_matching_f(root):
assert d.is_dir(), d
artist = get_artist_name_from_folder_name(d.name)
if artist is None:
print(f'Could not find artist name for {d.name}')
continue
elif d.parent.name != artist:
artist_folder = d.parent / artist
artist_folder.mkdir(exist_ok=True)
shutil.move(str(d), str(artist_folder))
def run_cmd_on_files(d, cmd, x):
print('Running on ' + str(d) + ', ' + x + ' files.')
subprocess.run(cmd + [str(p) for p in
d.glob('*.' + x)])
def compute_replay_gain():
root = Path('.')
ext = 'flac'
cmd_to_run_in_pool = []
for d in child_containing_matching_f(root, (ext,)):
assert d.is_dir(), d
cmd_to_run_in_pool.append(
(d, ['metaflac', '--add-replay-gain'], ext))
with multiprocessing.Pool() as p:
p.starmap(run_cmd_on_files, cmd_to_run_in_pool)
if __name__ == '__main__':
os.nice(40)
move_to_artist_folder()
clean_files()
rename_cue_files()
compute_replay_gain()