Conditions | 16 |
Total Lines | 176 |
Code Lines | 125 |
Lines | 0 |
Ratio | 0 % |
Tests | 4 |
CRAP Score | 237.9228 |
Changes | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like music_album_creation.create_album.main() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | #!/usr/bin/env python3 |
||
64 | @click.command() |
||
65 | @click.option( |
||
66 | '--tracks_info', |
||
67 | '-t_i', |
||
68 | type=click.File('r'), |
||
69 | help='File in which there is tracks information necessary to segment a music ablum into tracks.' |
||
70 | 'If not provided, a prompt will allow you to type the input tracks information.', |
||
71 | ) |
||
72 | @click.option( |
||
73 | '--track_name/--no-track_name', |
||
74 | default=True, |
||
75 | show_default=True, |
||
76 | help='Whether to extract the track names from the mp3 files and write them as metadata correspondingly', |
||
77 | ) |
||
78 | @click.option( |
||
79 | '--track_number/--no-track_number', |
||
80 | default=True, |
||
81 | show_default=True, |
||
82 | help='Whether to extract the track numbers from the mp3 files and write them as metadata correspondingly', |
||
83 | ) |
||
84 | @click.option( |
||
85 | '--artist', |
||
86 | '-a', |
||
87 | help="If given, then value shall be used as the PTE1 tag: 'Lead performer(s)/Soloist(s)'. In the music player 'clementine' it corresponds to the 'artist' column (and not the 'Album artist column) ", |
||
88 | ) |
||
89 | @click.option( |
||
90 | '--album_artist', |
||
91 | help="If given, then value shall be used as the TPE2 tag: 'Band/orchestra/accompaniment'. In the music player 'clementine' it corresponds to the 'Album artist' column", |
||
92 | ) |
||
93 | @click.option('--video_url', '-u', help='the youtube video url') |
||
94 | def main(tracks_info, track_name, track_number, artist, album_artist, video_url): |
||
95 | music_dir = music_lib_directory(verbose=True) |
||
96 | print("Music library: {}".format(music_dir)) |
||
97 | logger.error("Music library: {}".format(str(music_dir))) |
||
98 | |||
99 | ## Render Logo |
||
100 | inout.logo() |
||
101 | |||
102 | print('\n') |
||
103 | if not video_url: |
||
104 | video_url = inout.input_youtube_url_dialog() |
||
105 | print('\n') |
||
106 | logger.error(f"URL {video_url}") |
||
107 | ## Init |
||
108 | music_master = MusicMaster(music_dir) |
||
109 | # Segments Audio files into tracks and stores them in the system's temp dir (ie /tmp on Debian) |
||
110 | audio_segmenter = AudioSegmenter() |
||
111 | |||
112 | ## DOWNLOAD |
||
113 | while 1: |
||
114 | try: |
||
115 | album_file = music_master.url2mp3( |
||
116 | video_url, suppress_certificate_validation=False, force_download=False |
||
117 | ) |
||
118 | break |
||
119 | except TokenParameterNotInVideoInfoError as e: |
||
120 | print(e, '\n') |
||
121 | if inout.update_and_retry_dialog()['update-youtube-dl']: |
||
122 | music_master.update_youtube() |
||
123 | else: |
||
124 | print("Exiting ..") |
||
125 | sys.exit(1) |
||
126 | except (InvalidUrlError, UnavailableVideoError) as e: |
||
127 | print(e, '\n') |
||
128 | video_url = inout.input_youtube_url_dialog() |
||
129 | print('\n') |
||
130 | print('\n') |
||
131 | |||
132 | print("Album file: {}".format(album_file)) |
||
133 | |||
134 | ### RECEIVE TRACKS INFORMATION |
||
135 | if tracks_info: |
||
136 | tracks_info = TracksInformation.from_multiline(tracks_info.read().strip()) |
||
137 | else: # Interactive track type input |
||
138 | sleep(0.5) |
||
139 | tracks_info = TracksInformation.from_multiline( |
||
140 | inout.interactive_track_info_input_dialog().strip() |
||
141 | ) |
||
142 | print() |
||
143 | |||
144 | # Ask user if the input represents song timestamps (withing the whole playtime) OR |
||
145 | # if the input represents song durations (that sum up to the total playtime) |
||
146 | answer = inout.track_information_type_dialog() |
||
147 | |||
148 | segmentation_info = SegmentationInformation.from_tracks_information( |
||
149 | tracks_info, hhmmss_type=answer.lower() |
||
150 | ) |
||
151 | |||
152 | # SEGMENTATION |
||
153 | try: |
||
154 | audio_file_paths = audio_segmenter.segment( |
||
155 | album_file, |
||
156 | segmentation_info, |
||
157 | sleep_seconds=0, |
||
158 | ) |
||
159 | except TrackTimestampsSequenceError as e: |
||
160 | 1 | print(e) |
|
161 | sys.exit(1) |
||
162 | 1 | # TODO capture ctrl-D to signal possible change of type from timestamp to durations and vice-versa... |
|
163 | # in order to put the above statement outside of while loop |
||
164 | |||
165 | # TODO re-implement the below using the ffmpeg proxy |
||
166 | durations = [ |
||
167 | 1 | time.strftime( |
|
168 | '%H:%M:%S', |
||
169 | time.gmtime(int(float(ffprobe_client.get_stream_info(f)['format']['duration']))), |
||
170 | ) |
||
171 | for f in audio_file_paths |
||
172 | ] |
||
173 | |||
174 | # durations = [StringParser.hhmmss_format(getattr(mutagen.File(t).info, 'length', 0)) for t in audio_file_paths] |
||
175 | max_row_length = max(len(_[0]) + len(_[1]) for _ in zip(audio_file_paths, durations)) |
||
176 | print("\n\nThese are the tracks created.\n") |
||
177 | print( |
||
178 | '\n'.join( |
||
179 | sorted( |
||
180 | [ |
||
181 | ' {}{} {}'.format(t, (max_row_length - len(t) - len(d)) * ' ', d) |
||
182 | for t, d in zip(audio_file_paths, durations) |
||
183 | 1 | ] |
|
184 | ) |
||
185 | ), |
||
186 | '\n', |
||
187 | ) |
||
188 | # TODO |
||
189 | |||
190 | ### STORE TRACKS IN DIR in MUSIC LIBRARY ROOT |
||
191 | while 1: |
||
192 | print(type(music_dir), type(music_master.guessed_info)) |
||
193 | print(music_dir) |
||
194 | print(music_master.guessed_info) |
||
195 | album_dir = inout.album_directory_path_dialog(music_dir, **music_master.guessed_info) |
||
196 | try: |
||
197 | os.makedirs(album_dir) |
||
198 | except FileExistsError: |
||
199 | if not inout.confirm_copy_tracks_dialog(album_dir): |
||
200 | continue |
||
201 | except FileNotFoundError: |
||
202 | print("The selected destination directory '{}' is not valid.".format(album_dir)) |
||
203 | continue |
||
204 | except PermissionError: |
||
205 | print( |
||
206 | "You don't have permision to create a directory in path '{}'".format(album_dir) |
||
207 | ) |
||
208 | continue |
||
209 | try: |
||
210 | for track in audio_file_paths: |
||
211 | destination_file_path = os.path.join(album_dir, os.path.basename(track)) |
||
212 | if os.path.isfile(destination_file_path): |
||
213 | print( |
||
214 | " File '{}' already exists. in '{}'. Skipping".format( |
||
215 | os.path.basename(track), album_dir |
||
216 | ) |
||
217 | ) |
||
218 | else: |
||
219 | shutil.copyfile(track, destination_file_path) |
||
220 | print("Album tracks reside in '{}'".format(album_dir)) |
||
221 | break |
||
222 | except PermissionError: |
||
223 | print( |
||
224 | "Can't copy tracks to '{}' folder. You don't have write permissions in this directory".format( |
||
225 | album_dir |
||
226 | ) |
||
227 | ) |
||
228 | |||
229 | ### WRITE METADATA |
||
230 | md = MetadataDealer() |
||
231 | answers = inout.interactive_metadata_dialogs(**music_master.guessed_info) |
||
232 | md.set_album_metadata( |
||
233 | album_dir, |
||
234 | track_number=track_number, |
||
235 | track_name=track_name, |
||
236 | artist=answers['artist'], |
||
237 | album_artist=answers['album-artist'], |
||
238 | album=answers['album'], |
||
239 | year=answers['year'], |
||
240 | ) |
||
274 |