Passed
Push — dev ( 2ef46d...fac993 )
by Andreas
01:42
created

CMS.polish_filenames()   A

Complexity

Conditions 5

Size

Total Lines 22
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
eloc 18
dl 0
loc 22
rs 9.0333
c 0
b 0
f 0
ccs 0
cts 13
cp 0
cc 5
nop 0
crap 30
1
"""Car Music Sorter."""
2 1
import gettext
3 1
import os
4 1
import re
5 1
import shutil
6 1
import w_settings
7 1
8
from threading import Thread
9
from typing import Union
10
from sys import exit
11
from tkinter import Tk, PhotoImage, Menu, LabelFrame, messagebox
12
from tkinter.ttk import Button, Label, Progressbar
13
from pathlib import Path
14
from f_getconfig import getconfig
15
from f_logging import writelog
16
from w_about import popup_about
17
18
import tkinter.filedialog as fd
19
input_dir: str = ''
20
output_dir: str = ''
21
source_file = []
22
23
24
# BEGIN FUNCTIONS #
25
# FIXME: Вынести по возможности в отдельные файлы
26
# Определение исходной и целевой директорий
27
def workdirs(param: str) -> None:
28
    """Открывает диалог выбора директории."""
29
    if param == 'indir':
30
        global input_dir
31
        input_dir = fd.askdirectory(title = _('Open source directory'))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable _ does not seem to be defined.
Loading history...
32
        if input_dir != '':
33
            source_label.config(text = f'...{path_short(input_dir, 2)}')
34
            writelog(_('Input DIR set to: ') + input_dir)
35
        else:
36
            input_dir = ''
37
    elif param == 'outdir':
38
        global output_dir
39
        output_dir = fd.askdirectory(title = _('Set destination directory'))
40
        if output_dir != '':
41
            dest_label.config(text = f'...{path_short(output_dir, 2)}')
42
            writelog(_('Output DIR set to: ') + output_dir)
43
        else:
44
            output_dir = ''
45
    elif param == 'clear':
46
        source_label.config(text = _('Input DIR not defined'))
47
        dest_label.config(text = _('Output DIR not defined'))
48
        main_progressbar['value'] = 0
49
        input_dir = output_dir = ''
50
51
52
def path_short(path_string: str, len: int) -> Union[str, Path]:
53
    """Сокращает путь для корректного отображения в лейбле."""
54
    return Path(*Path(path_string).parts[-len:])
55
56
57
# Основные операции
58
def check_paths() -> None:
59
    """Проверяет, что все пути заданы корректно и запускает копирование."""
60
    if input_dir == '' or output_dir == '':
61
        writelog(_('Input DIR or Output DIR are not defined!'))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable _ does not seem to be defined.
Loading history...
62
    elif input_dir == output_dir:
63
        writelog(_('Input DIR and Output DIR must be different!'))
64
        return
65
    else:
66
        for path, subdirs, files in os.walk(input_dir):
67
            for file in files:
68
                # Перегоняем MP3 без лайвов и ремиксов в целевую директорию.
69
                filtered = re.search(r'^(?!(.*[Rr]emix.*|.*[Ll]ive.*)).*mp3', file)
70
                if filtered is not None:
71
                    source_file.append(f'{path}/{filtered.group(0)}')
72
    main_progressbar['maximum'] = len(source_file)
73
    for files in source_file:
74
        maincopy(files, Path(output_dir))
75
    source_file.clear()
76
77
78
def proc_thread():
79
    """Запускает процесс в отдельном потоке."""
80
    forked_thread = Thread(target = processing)
81
    forked_thread.start()
82
83
84
def processing() -> None:
85
    """Удаляет ремиксы и лайвы."""
86
    check_paths()
87
# Удаление ремиксов и лайвов
88
# TODO: Depricated
89
    liveregexp = r'.*\(.*[Rr]emix.*\).*|.*\(.*[Ll]ive.*\).*'
90
    for files in os.walk(output_dir):
91
        for file in files[2]:
92
            try:
93
                source_file.append(re.search(liveregexp, file).group(0))
94
            except Exception:
95
                pass
96
    for file in source_file:
97
        writelog(_('Removing Remix: ') + file)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable _ does not seem to be defined.
Loading history...
98
        os.remove(f'{output_dir}/{file}')
99
        main_progressbar['value'] = main_progressbar['value'] + 1
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable main_progressbar does not seem to be defined.
Loading history...
100
        window.update_idletasks()
101
    source_file.clear()  # Очищаем список
102
    polish_filenames()
103
104
105
def polish_filenames() -> None:
106
    """Удаляет из имен треков мусор."""
107
# Готовим список свежепринесенных файлов с вычищенными ремиксами и лайвами
108
    for files in os.walk(output_dir):
109
        for file in files[2]:
110
            try:
111
                source_file.append(file)
112
            except Exception:
113
                pass
114
115
# Убираем из имен файлов мусор (номера треков в различном формате)
116
    main_progressbar['maximum'] = (main_progressbar['maximum'] + len(source_file))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable main_progressbar does not seem to be defined.
Loading history...
117
    trashregexp = r'^[\d{1,2}\s\-\.]*'
118
    for file in source_file:
119
        new_file = re.sub(trashregexp, '', file)
120
        shutil.move(f'{output_dir}/{file}', f'{output_dir}/{new_file}')
121
        main_progressbar['value'] = main_progressbar['value'] + 1
122
        window.update_idletasks()
123
    source_file.clear()
124
    writelog(_('Completed!'))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable _ does not seem to be defined.
Loading history...
125
    messagebox.showinfo(_('Information'),
126
                        _('Completed!'))
127
128
129
# Копируем файлы
130
def maincopy(files: list[str], output_dir: Path) -> None:
131
    """Копирует файлы."""
132
    writelog(f'{files}')
133
    filename = str.split(str(files), '/')
134
    writelog(filename[-1])
135
    shutil.copyfile(f'{files}', f'{output_dir}/{filename[-1]}')
136
    main_progressbar['value'] = main_progressbar['value'] + 1
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable main_progressbar does not seem to be defined.
Loading history...
137
    window.update_idletasks()
138
# END FUNCTIONS #
139
140
141
# Вводим основные переменные
142
vers = getconfig()['core']['version']
143
langcode = getconfig()['settings']['locale']
144
# Локализация
145
gettext.translation('CarMusicSorter', localedir='l10n',
146
                    languages=[langcode]).install()
147
writelog('init')
148
# Рисуем окно
149
window = Tk()
150
window.iconphoto(True, PhotoImage(file = 'data/imgs/main.png'))
151
window.geometry('370x270')
152
window.eval('tk::PlaceWindow . center')
153
window.title('Car Music Sorter')
154
window.resizable(False, False)
155
156
# Пути к оформлению
157
sourceicon = PhotoImage(file = 'data/imgs/20source.png')
158
desticon = PhotoImage(file = 'data/imgs/20dest.png')
159
launchicon = PhotoImage(file = 'data/imgs/20ok.png')
160
clearicon = PhotoImage(file = 'data/imgs/20clear.png')
161
162
# Основное меню
163
menu = Menu(window)
164
menu_about = Menu(menu, tearoff = 0)
165
menu_file = Menu(menu, tearoff = 0)
166
menu.add_cascade(label = _('File'), menu = menu_file)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable _ does not seem to be defined.
Loading history...
167
menu.add_cascade(label = _('Info'), menu = menu_about)
168
169
# Элементы меню
170
menu_about.add_command(label = _('About'),
171
                       command = lambda: popup_about(window, vers),
172
                       accelerator = 'F1')
173
menu_file.add_command(label = _('Input Dir'),
174
                      command = lambda: workdirs('indir'),
175
                      accelerator = 'CTRL+O')
176
menu_file.add_command(label = _('Output Dir'),
177
                      command = lambda: workdirs('outdirs'),
178
                      accelerator = 'CTRL+D')
179
menu_file.add_command(label = _('Clear'),
180
                      command = lambda: workdirs('clear'),
181
                      accelerator = 'CTRL+R')
182
menu_file.add_separator()
183
menu_file.add_command(label = _('Settings'),
184
                      command = w_settings.popup_settings)
185
menu_file.add_separator()
186
menu_file.add_command(label = _('Exit'),
187
                      command = exit,
188
                      accelerator = 'CTRL+E')
189
190
# Биндим хоткеи к функциям
191
menu_file.bind_all('<Command-o>', lambda event: workdirs('indir'))
192
menu_file.bind_all('<Command-d>', lambda event: workdirs('outdir'))
193
menu_file.bind_all('<Command-r>', lambda event: workdirs('clear'))
194
menu_file.bind_all('<Command-e>', exit)
195
196
menu_about.bind_all('<F1>', lambda event: popup_about(window, vers))
197
window.config(menu = menu)
198
199
# Строим элеметны основного окна и группы
200
first_group = LabelFrame(window, text = _('IO Directories'))
201
202
first_group.grid(sticky = 'WE',
203
                 column = 0, row = 0,
204
                 padx = 5, pady = 10,
205
                 ipadx = 2, ipady = 4)
206
207
operation_group = LabelFrame(window, text = _('Operations'))
208
operation_group.grid(sticky = 'WE',
209
                     column = 0, row = 3,
210
                     padx = 5, pady = 5,
211
                     ipadx = 5, ipady = 5)
212
213
progress_group = LabelFrame(window, text = _('Progress'))
214
progress_group.grid(sticky = 'WE',
215
                    column = 0, row = 1,
216
                    padx = 5, pady = 5,
217
                    ipadx = 0, ipady = 2,
218
                    rowspan = 2)
219
220
# Прогрессбар
221
main_progressbar = Progressbar(progress_group, length = 350, value = 0,
222
                               orient = 'horizontal', mode = 'determinate')
223
main_progressbar.grid(pady = 4, column = 0, row = 1)
224
225
# Поясняющие лейблы
226
source_label_text = _('Input DIR not defined')
227
dest_label_text = _('Output DIR not defined')
228
source_label = Label(first_group, text = source_label_text, justify = 'left')
229
source_label.grid(column = 1, row = 0)
230
dest_label = Label(first_group, text = dest_label_text, justify = 'left')
231
dest_label.grid(column = 1, row = 1)
232
233
# Кнопки
234
source_button = Button(first_group, text = _('Input Dir'),
235
                       command = lambda: workdirs('indir'), image = sourceicon,
236
                       width = 20, compound = 'left')
237
source_button.grid(row = 0, ipadx = 2, ipady = 2, padx = 4)
238
239
dest_button = Button(first_group, text = _('Output Dir'),
240
                     command = lambda: workdirs('outdir'), image = desticon,
241
                     width = 20, compound = 'left')
242
dest_button.grid(row = 1, ipadx = 2, ipady = 2, padx = 4)
243
244
launch_button = Button(operation_group, text = _('Process'),
245
                       command = proc_thread, image = launchicon,
246
                       width = 20, compound = 'left')
247
launch_button.grid(column = 0, row = 2, ipadx = 2, ipady = 2, padx = 12)
248
249
clear_button = Button(operation_group, text = _('Clear'),
250
                      command = lambda: workdirs('clear'), image = clearicon,
251
                      width = 20, compound = 'left')
252
253
clear_button.grid(column = 1, row = 2, ipadx = 2, ipady = 2, padx = 0)
254
255
if __name__ == '__main__':
256
    window.mainloop()
257