Completed
Push — dev ( 232b11...6092be )
by Konstantinos
04:15 queued 01:32
created

DialogCommander.print()   A

Complexity

Conditions 1

Size

Total Lines 3
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1.125

Importance

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