Passed
Push — dev ( b084e9...585a6c )
by Andreas
54s
created

CMS.path_short()   A

Complexity

Conditions 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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