Test Failed
Push — dev ( e53738...7ec219 )
by Andreas
01:18
created

CMS.polish_filenames()   A

Complexity

Conditions 5

Size

Total Lines 21
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
cc 5
eloc 17
nop 0
dl 0
loc 21
ccs 0
cts 16
cp 0
crap 30
rs 9.0833
c 0
b 0
f 0
1
"""Car Music Sorter."""
2 1
import yaml
3 1
import gettext
4 1
import os
5 1
import re
6 1
import shutil
7 1
import w_settings
8
9
from sys import exit
10
from tkinter import Tk, PhotoImage, Menu, LabelFrame
11
from tkinter import Text, Toplevel, messagebox
12
from tkinter.ttk import Button, Label, Progressbar
13
from pathlib import Path
14
15
import tkinter.filedialog as fd
16
input_dir = ''
17
output_dir = ''
18
19
source_file = []
20
21
22
# BEGIN FUNCTIONS #
23
# FIXME: Вынести по возможности в отдельные файлы
24
# Определение исходной и целевой директорий
25
def workdirs(param):
26
    """Открывает диалог выбора директории."""
27
    if param == 'indir':
28
        global input_dir
29
        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...
30
        if input_dir != '':
31
            source_label.config(text = f'...{path_short(input_dir, 2)}')
32
            printlog(_('Input DIR set to: ') + input_dir)
33
        else:
34
            input_dir = ''
35
    elif param == 'outdir':
36
        global output_dir
37
        output_dir = fd.askdirectory(title = _('Set destination directory'))
38
        if output_dir != '':
39
            dest_label.config(text = f'...{path_short(output_dir, 2)}')
40
            printlog(_('Output DIR set to: ') + output_dir)
41
        else:
42
            output_dir = ''
43
    elif param == 'clear':
44
        source_label.config(text = _('Input DIR not defined'))
45
        dest_label.config(text = _('Output DIR not defined'))
46
        printlog(_('Paths cleared'))
47
        main_progressbar['value'] = 0
48
        input_dir = output_dir = ''
49
50
51
def printlog(text):
52
    """Пишет лог операции в TextBox."""
53
    progress_log.config(state = 'normal')
54
    progress_log.insert('end', f'{text}\n')
55
    progress_log.config(state = 'disabled')
56
    progress_log.see('end')
57
58
59
def path_short(path_string, len):
60
    """Сокращает путь для корректного отображения в лейбле."""
61
    return Path(*Path(path_string).parts[-len:])
62
63
64
# Вызов "О программе"
65
def popup_about(vers):
66
    """Открывает окно 'О программе'."""
67
# Центровка окна
68
    main_width = 400
69
    main_height = 150
70
    center_x_pos = int(window.winfo_screenwidth() / 2) - main_width
71
    center_y_pos = int(window.winfo_screenheight() / 2) - main_height
72
73
    popup = Toplevel()
74
    popup.geometry(f'{main_width}x{main_height}+{center_x_pos}+{center_y_pos}')
75
    popup.title(_('About'))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable _ does not seem to be defined.
Loading history...
76
    imagepath = 'data/imgs/main.png'
77
    img = PhotoImage(file = imagepath)
78
    poplabel1 = Label(popup, image = img)
79
    poplabel1.grid(sticky = 'W', column = 0, row = 0, rowspan = 2)
80
81
    name_vers_str = 'Car Music Sorter\n\n' + _('Version: ') + vers
82
    author_github = 'https://github.com/intervisionlord'
83
    prog_author = _('\nAuthor: ') + 'Intervision\nGithub: ' + author_github
84
    poplabel_maindesc = Label(popup,
85
                              text = name_vers_str + prog_author,
86
                              justify = 'left')
87
    poplabel_maindesc.grid(sticky = 'W', column = 1, row = 0)
88
# Автор иконок
89
    icons_author = _('Icons: ') + 'icon king1 ' + _('on') + ' freeicons.io'
90
    poplabel_icons = Label(popup, text = icons_author, justify = 'left')
91
    poplabel_icons.grid(sticky = 'W', column = 1, row = 1)
92
93
    popup.grab_set()
94
    popup.focus_set()
95
    popup.wait_window()
96
97
98
# Основные операции
99
def check_paths():
100
    """Проверяет, что все пути заданы корректно и запускает копирование."""
101
    if input_dir == '' or output_dir == '':
102
        printlog(_('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...
103
    elif input_dir == output_dir:
104
        printlog(_('Input DIR and Output DIR must be different!'))
105
        return
106
    else:
107
        for path, subdirs, files in os.walk(input_dir):
108
            for file in files:
109
                # Перегоняем все MP3 в целевую директорию,
110
                # потом разберемся что с ними делать
111
                # Хотя, лучше искать только нужные (отбрасывать лайвы
112
                # и ремиксы и перегонять уже без них)
113
                filtered = re.search('.*mp3', file)
114
                if filtered is not None:
115
                    source_file.append(f'{path}/{filtered.group(0)}')
116
    main_progressbar['maximum'] = len(source_file)
117
    for files in source_file:
118
        maincopy(files, output_dir)
119
    source_file.clear()
120
121
122
def processing():
123
    """Удаляет ремиксы и лайвы."""
124
    check_paths()
125
# Удаление ремиксов и лайвов
126
    liveregexp = r'.*\(.*[Rr]emix.*\).*|.*\(.*[Ll]ive.*\).*'
127
    for files in os.walk(output_dir):
128
        for file in files[2]:
129
            try:
130
                source_file.append(re.search(liveregexp, file).group(0))
131
            except Exception:
132
                pass
133
    for file in source_file:
134
        printlog('Removing Remix: ' + file)
135
        os.remove(f'{output_dir}/{file}')
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
    source_file.clear()  # Очищаем список
139
    polish_filenames()
140
141
142
def polish_filenames():
143
    """Удаляет из имен треков мусор."""
144
# Готовим список свежепринесенных файлов с вычищенными ремиксами и лайвами
145
    for files in os.walk(output_dir):
146
        for file in files[2]:
147
            try:
148
                source_file.append(file)
149
            except Exception:
150
                pass
151
152
# Убираем из имен файлов мусор (номера треков в различном формате)
153
    main_progressbar['maximum'] = (main_progressbar['maximum'] +
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable main_progressbar does not seem to be defined.
Loading history...
154
                                   len(source_file))
155
    trashregexp = r'^[\d{1,2}\s\-\.]*'
156
    for file in source_file:
157
        new_file = re.sub(trashregexp, '', file)
158
        shutil.move(f'{output_dir}/{file}', f'{output_dir}/{new_file}')
159
        main_progressbar['value'] = main_progressbar['value'] + 1
160
        window.update_idletasks()
161
    source_file.clear()
162
    printlog(_('Completed!'))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable _ does not seem to be defined.
Loading history...
163
164
165
# Копируем файлы
166
def maincopy(files, output_dir):
167
    """Копирует файлы."""
168
    printlog(f'{files}')
169
    filename = str.split(files, '/')
170
    printlog(filename[-1])
171
    shutil.copyfile(f'{files}', f'{output_dir}/{filename[-1]}')
172
    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...
173
    window.update_idletasks()
174
# TODO: Вывести запись логов в файл, убрать бокс с логом из окна.
175
# END FUNCTIONS #
176
177
178
# Проверяем конфиг
179
def getconfig():
180
    """Определяет наличие конфига и загружает его."""
181
    try:
182
        conffile = open('conf/main.yml', 'r')
183
    except IOError:  # FIXME: Убрать exit() в результате эксепшена
184
        exit(messagebox.showerror('ERROR', 'Config file not found'))
185
186
    config = yaml.full_load(conffile)
187
    conffile.close()
188
    return config
189
190
191
# Вводим основные переменные
192
vers = getconfig()['core']['version']
193
langcode = getconfig()['settings']['locale']
194
# Локализация
195
gettext.translation('CarMusicSorter', localedir='l10n',
196
                    languages=[langcode]).install()
197
# Рисуем окно
198
window = Tk()
199
200
window.iconphoto(True, PhotoImage(file = 'data/imgs/main.png'))
201
window.geometry('650x260')
202
window.eval('tk::PlaceWindow . center')
203
window.title('Car Music Sorter')
204
205
# Пути к оформлению
206
sourceicon = PhotoImage(file = 'data/imgs/20source.png')
207
desticon = PhotoImage(file = 'data/imgs/20dest.png')
208
launchicon = PhotoImage(file = 'data/imgs/20ok.png')
209
clearicon = PhotoImage(file = 'data/imgs/20clear.png')
210
211
# Основное меню
212
menu = Menu(window)
213
menu_about = Menu(menu, tearoff = 0)
214
menu_file = Menu(menu, tearoff = 0)
215
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...
216
menu.add_cascade(label = _('Info'), menu = menu_about)
217
# Элементы меню
218
menu_about.add_command(label = _('About'),
219
                       command = lambda: popup_about(vers),
220
                       accelerator = 'F1')
221
222
menu_file.add_command(label = _('Input Dir'),
223
                      command = lambda: workdirs('indir'),
224
                      accelerator = 'CTRL+O')
225
menu_file.add_command(label = _('Output Dir'),
226
                      command = lambda: workdirs('outdirs'),
227
                      accelerator = 'CTRL+D')
228
menu_file.add_command(label = _('Clear'),
229
                      command = lambda: workdirs('clear'),
230
                      accelerator = 'CTRL+R')
231
menu_file.add_separator()
232
menu_file.add_command(label = _('Settings'),
233
                      command = w_settings.popup_settings)
234
menu_file.add_separator()
235
menu_file.add_command(label = _('Exit'),
236
                      command = exit,
237
                      accelerator = 'CTRL+E')
238
239
menu_file.bind_all('<Command-o>', lambda event: workdirs('indir'))
240
menu_file.bind_all('<Command-d>', lambda event: workdirs('outdir'))
241
menu_file.bind_all('<Command-r>', lambda event: workdirs('clear'))
242
menu_file.bind_all('<Command-e>', exit)
243
244
menu_about.bind_all('<F1>', lambda event: popup_about(vers))
245
246
window.config(menu = menu)
247
# Строим элеметны основного окна и группы
248
first_group = LabelFrame(window, text = _('IO Directories'))
249
250
first_group.grid(sticky = 'WE', column = 0, row = 0, padx = 5, pady = 10,
251
                 ipadx = 2, ipady = 4)
252
253
operation_group = LabelFrame(window, text = _('Operations'))
254
operation_group.grid(sticky = 'WE', column = 0, row = 1, padx = 5, pady = 10,
255
                     ipadx = 2, ipady = 4)
256
257
progress_group = LabelFrame(window, text = _('Progress'))
258
progress_group.grid(sticky = 'WSEN', column = 1, row = 0, padx = 5, pady = 10,
259
                    ipadx = 0, ipady = 2, rowspan = 2)
260
261
# Прогрессбар
262
main_progressbar = Progressbar(progress_group, length = 255, value = 0,
263
                               orient = 'horizontal', mode = 'determinate')
264
main_progressbar.grid(pady = 4, column = 0, row = 1)
265
266
# Поясняющие лейблы
267
source_label_text = _('Input DIR not defined')
268
dest_label_text = _('Output DIR not defined')
269
270
source_label = Label(first_group, text = source_label_text, justify = 'left')
271
source_label.grid(column = 1, row = 0)
272
dest_label = Label(first_group, text = dest_label_text, justify = 'left')
273
dest_label.grid(column = 1, row = 1)
274
275
# Кнопки
276
source_button = Button(first_group, text = _('Input Dir'),
277
                       command = lambda: workdirs('indir'), image = sourceicon,
278
                       width = 20, compound = 'left')
279
source_button.grid(row = 0, ipadx = 2, ipady = 2, padx = 4)
280
281
dest_button = Button(first_group, text = _('Output Dir'),
282
                     command = lambda: workdirs('outdir'), image = desticon,
283
                     width = 20, compound = 'left')
284
dest_button.grid(row = 1, ipadx = 2, ipady = 2, padx = 4)
285
286
launch_button = Button(operation_group, text = _('Process'),
287
                       command = processing, image = launchicon,
288
                       width = 20, compound = 'left')
289
launch_button.grid(column = 0, row = 2, ipadx = 2, ipady = 2, padx = 4)
290
291
clear_button = Button(operation_group, text = _('Clear'),
292
                      command = lambda: workdirs('clear'), image = clearicon,
293
                      width = 20, compound = 'left')
294
295
clear_button.grid(column = 1, row = 2, ipadx = 2, ipady = 2, padx = 4)
296
297
# Лог и прогресс
298
progress_log = Text(progress_group, state = 'disabled', relief = 'flat',
299
                    width = 31, height = 10)
300
progress_log.grid(ipadx = 2, ipady = 2, padx = 4, column = 0, row = 0)
301
302
if __name__ == '__main__':
303
    window.mainloop()
304