Test Failed
Push — integration-test ( abbdf8...fd2301 )
by Konstantinos
02:34
created

DialogCommander.logo()   A

Complexity

Conditions 1

Size

Total Lines 4
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
import os
2
import sys
3
import shutil
4
5
from PyInquirer import prompt, Validator, ValidationError
6
7
# __all__ = ['store_album_dialog', 'interactive_metadata_dialogs']
8
9
10
class InputFactory:
11
    __instance = None
12
13
    def __new__(cls, *args, **kwargs):
14
        if not cls.__instance:
15
            cls.__instance = super().__new__(cls)
16
            if sys.version_info.major == 2:
17
                cls.__instance._input = raw_input  # NOQA
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable raw_input does not seem to be defined.
Loading history...
18
            else:
19
                cls.__instance._input = input
20
        return cls.__instance
21
22
    def __call__(self, *args):
23
        return self._input(*args)
24
25
26
ask_input = InputFactory()
27
28
29
class DialogCommander:
30
31
    @classmethod
32
    def logo(cls):
33
        print(
34
            "\
35
╔═╗╦  ╔╗ ╦ ╦╔╦╗  ╔═╗╦═╗╔═╗╔═╗╔╦╗╔═╗╦═╗\n\
36
╠═╣║  ╠╩╗║ ║║║║  ║  ╠╦╝║╣ ╠═╣ ║ ║ ║╠╦╝\n\
37
╩ ╩╩═╝╚═╝╚═╝╩ ╩  ╚═╝╩╚═╚═╝╩ ╩ ╩ ╚═╝╩╚═\
38
            ")
39
40
    @classmethod
41
    def print(cls, string):
42
        print(string)
43
44
    @classmethod
45
    def input_youtube_url_dialog(cls):
46
        """"""
47
        return ask_input('Please input a url corresponding to a music album uploaded as a youtube video.\n   video url: ')
48
49
50
    ## HANDLE Token Error with update youtube-dl and retry download same url dialog
51
    @classmethod
52
    def update_and_retry_dialog(cls):
53
        questions = [
54
            {
55
                'type': 'confirm',
56
                'name': 'update-youtube-dl',
57
                'message': "Update 'youtube-dl' backend?)",
58
                'default': True,
59
            }
60
        ]
61
        answer = prompt(questions)
62
        return answer
63
64
65
    ##### MULTILINE INPUT TRACK NAMES AND TIMESTAMPS (hh:mm:ss)
66
    @classmethod
67
    def track_information_type_dialog(cls, prediction=''):
68
        """Returns a parser of track hh:mm:ss multiline string"""
69
        if prediction == 'timestamps':
70
            choices = ['Timestamps (predicted)', 'Durations']
71
        elif prediction == 'durations':
72
            choices = ['Durations (predicted)', 'Timestamps']
73
        else:
74
            choices = ['Timestamps', 'Durations']
75
        questions = [
76
            {
77
                'type': 'list',  # navigate with arrows through choices
78
                'name': 'how-to-input-tracks',
79
                # type of is the format you prefer to input for providing the necessary information to segment an album
80
                'message': 'What does the expected "hh:mm:ss" input represent?',
81
                'choices': choices,
82
            }
83
        ]
84
        answers = prompt(questions)
85
        return answers['how-to-input-tracks']
86
87
    @classmethod
88
    def interactive_track_info_input_dialog(cls):
89
        print("Enter/Paste your 'track_name - hh:mm:ss' pairs. Each line should represent a single track with format 'trackname - hh:mm:ss'. "
90
              "The assumption is that each track is defined either in terms of a timestamp corrspoding to the starting point within the full album or its actuall playtime length. Then navigate one line below your last track and press Ctrl-D (or Ctrl-Z in $#*!% windows) to save it.\n")
91
92
        def input_lines(prompt_=None):
93
            """Yields input lines from user until EOFError is raised."""
94
            while True:
95
                try:
96
                    yield ask_input() if prompt_ is None else ask_input(prompt_)
97
                except EOFError:
98
                    break
99
                else:
100
                    prompt_ = None  # Only display prompt while reading first line.
101
102
        def multiline_input(prompt_=None):
103
            """Reads a multi-line input from the user."""
104
            return os.linesep.join(input_lines(prompt_=prompt_))
105
        return multiline_input()  # '\n' separable string
106
107
108
    ####################################################################
109
110
    @classmethod
111
    def album_directory_path_dialog(cls, music_lib, artist='', album='', year=''):
112
        if year:
113
            album = '{} ({})'.format(album, year)
114
        else:
115
            album = album
116
        return prompt([{'type': 'input',
117
                        'name': 'create-album-dir',
118
                        'message': 'Please give album directory path',
119
                        'default': os.path.join(music_lib, artist, album)}])['create-album-dir']
120
121
    @classmethod
122
    def confirm_copy_tracks_dialog(cls, destination_directory):
123
        return prompt([{'type': 'confirm',
124
                        'name': 'copy-in-existant-dir',
125
                        'message': "Directory '{}' exists. Copy the tracks there?".format(destination_directory),
126
                        'default': True}])['copy-in-existant-dir']
127
128
    @classmethod
129
    def interactive_metadata_dialogs(cls, artist='', album='', year=''):
130
        questions = [
131
            {
132
                'type': 'confirm',
133
                'name': 'add-metadata',
134
                'message': 'Do you want to add metadata, such as artist, track names, to the audio files?',
135
                'default': True,
136
            },
137
            {
138
                'type': 'checkbox',
139
                'name': 'automatic-metadata',
140
                'message': 'Infer from audio files',
141
                'when': lambda answers: bool(answers['add-metadata']),
142
                'choices': [
143
                    {
144
                        'name': 'track numbers',
145
                        'checked': True
146
                    },
147
                    {
148
                        'name': 'track names',
149
                        'checked': True
150
                    }
151
                ]
152
            },
153
            {
154
                'type': 'input',
155
                'name': 'artist',
156
                'default': artist,
157
                'message': "'artist' tag",
158
            },
159
            {
160
                'type': 'input',
161
                'name': 'album-artist',
162
                'message': "'album artist' tag",
163
                'default': lambda x: x['artist']
164
            },
165
            {
166
                'type': 'input',
167
                'name': 'album',
168
                'default': album,
169
                'message': "'album' tag",
170
            },
171
            {
172
                'type': 'input',
173
                'name': 'year',
174
                'message': "'year' tag",
175
                'default': year,  # trick to allow empty value
176
                'validate': NumberValidator,
177
                # 'filter': lambda val: int(val)
178
            },
179
        ]
180
        return prompt(questions)
181
182
183
class NumberValidator(Validator):
184
    def validate(self, document):
185
        if document.text != '':  # trick to allow empty value
186
            try:
187
                int(document.text)
188
            except ValueError:
189
                raise ValidationError(
190
                    message='Please enter a number',
191
                    cursor_position=len(document.text))  # Move cursor to end
192