def grab_single(raw_song, number=None): """ Logic behind downloading a song. """ if internals.is_youtube(raw_song): log.debug('Input song is a YouTube URL') content = go_pafy(raw_song, meta_tags=None) raw_song = slugify(content.title).replace('-', ' ') meta_tags = generate_metadata(raw_song) else: meta_tags = generate_metadata(raw_song) content = go_pafy(raw_song, meta_tags) if content is None: log.debug('Found no matching video') return # "[number]. [artist] - [song]" if downloading from list # otherwise "[artist] - [song]" youtube_title = get_youtube_title(content, number) log.info('{} ({})'.format(youtube_title, content.watchv_url)) # generate file name of the song to download songname = content.title if meta_tags is not None: refined_songname = generate_songname(meta_tags) log.debug('Refining songname from "{0}" to "{1}"'.format( songname, refined_songname)) if not refined_songname == ' - ': songname = refined_songname if args.dry_run: return file_name = internals.sanitize_title(songname) if not check_exists(file_name, raw_song, meta_tags): if download_song(file_name, content): input_song = file_name + args.input_ext output_song = file_name + args.output_ext print('') try: convert.song(input_song, output_song, args.folder, avconv=args.avconv) except FileNotFoundError: encoder = 'avconv' if args.avconv else 'ffmpeg' log.warning( 'Could not find {0}, skipping conversion'.format(encoder)) args.output_ext = args.input_ext output_song = file_name + args.output_ext if not args.input_ext == args.output_ext: os.remove(os.path.join(args.folder, input_song)) if not args.no_metadata: metadata.embed(os.path.join(args.folder, output_song), meta_tags) else: log.error('No audio streams available')
def test_check_exists(): expect_check = False # prerequisites for determining filename global file_name file_name = internals.sanitize_title(title) check = spotdl.check_exists(file_name, raw_song, meta_tags=None) assert check == expect_check
def test_check_exists(tmpdir): expect_check = False const.args.folder = str(tmpdir) # prerequisites for determining filename global file_name file_name = internals.sanitize_title(title) check = spotdl.check_exists(file_name, raw_song, metadata) assert check == expect_check
def test_check_exists(): expect_check = False # prerequisites for determining filename songname = internals.generate_songname(const.args.file_format, meta_tags) global file_name file_name = internals.sanitize_title(songname) check = spotdl.check_exists(file_name, raw_song, meta_tags) assert check == expect_check
def test_check_track_exists_before_download(tmpdir): expect_check = False const.args.folder = str(tmpdir) # prerequisites for determining filename songname = internals.generate_songname(const.args.file_format, meta_tags) global file_name file_name = internals.sanitize_title(songname) check = spotdl.check_exists(file_name, raw_song, meta_tags) assert check == expect_check
def grab_single(raw_song, number=None): """ Logic behind downloading a song. """ if number: islist = True else: islist = False if internals.is_youtube(raw_song): log.debug('Input song is a YouTube URL') content = go_pafy(raw_song, meta_tags=None) raw_song = slugify(content.title).replace('-', ' ') meta_tags = generate_metadata(raw_song) else: meta_tags = generate_metadata(raw_song) content = go_pafy(raw_song, meta_tags) if content is None: log.debug('Found no matching video') return # log '[number]. [artist] - [song]' if downloading from list # otherwise log '[artist] - [song]' log.info(get_youtube_title(content, number)) # generate file name of the song to download songname = content.title if meta_tags is not None: refined_songname = generate_songname(meta_tags) log.debug('Refining songname from "{0}" to "{1}"'.format( songname, refined_songname)) if not refined_songname == ' - ': songname = refined_songname file_name = internals.sanitize_title(songname) if not check_exists(file_name, raw_song, meta_tags, islist=islist): if download_song(file_name, content): input_song = file_name + args.input_ext output_song = file_name + args.output_ext print('') convert.song(input_song, output_song, args.folder, avconv=args.avconv) if not args.input_ext == args.output_ext: os.remove(os.path.join(args.folder, input_song)) if not args.no_metadata: metadata.embed(os.path.join(args.folder, output_song), meta_tags) else: log.error('No audio streams available')
def download_single(raw_song, number=None, folder=None) -> bool: """ Logic behind downloading a song. """ meta_tags = spotify_tools.generate_metadata(raw_song) if const.args.download_only_metadata and meta_tags is None: log.info('Found no metadata. Skipping the download') return False # generate file name of the song to download songname = 'foo' if meta_tags is not None: refined_songname = internals.format_string(const.args.file_format, meta_tags, slugification=True) log.debug('Refining songname from "{0}" to "{1}"'.format( songname, refined_songname)) if not refined_songname == ' - ': songname = refined_songname else: log.warning('Could not find metadata') songname = internals.sanitize_title(songname) if not check_exists(songname, raw_song, meta_tags, folder): # deal with file formats containing slashes to non-existent directories if folder: folder_path = folder else: folder_path = const.args.folder songpath = os.path.join(folder_path, os.path.dirname(songname)) os.makedirs(songpath, exist_ok=True) file_name = os.path.join(folder_path, songname + const.args.output_ext) play_time = player.play_and_record(meta_tags['uri'], file_name, songname) if not record.verify_length(file_name, meta_tags['duration'], play_time): log.error('Duration mismatch! Deleting: {}'.format(songname)) if duration_debug: fail_path = os.path.join(folder_path, 'mismatch') if not os.path.exists(fail_path): os.mkdir(fail_path) _, file_only = os.path.split(file_name) copyfile(file_name, os.path.join(fail_path, file_only)) os.remove(file_name) return False if not const.args.no_metadata and meta_tags is not None: metadata.embed(file_name, meta_tags) return True return True
def check_exists(music_file, raw_song, meta_tags): """ Check if the input song already exists in the given folder. """ log.debug('Cleaning any temp files and checking ' 'if "{}" already exists'.format(music_file)) songs = os.listdir(args.folder) for song in songs: if song.endswith('.temp'): os.remove(os.path.join(args.folder, song)) continue # check if any song with similar name is already present in the given folder file_name = internals.sanitize_title(music_file) if song.startswith(file_name): log.debug('Found an already existing song: "{}"'.format(song)) if internals.is_spotify(raw_song): # check if the already downloaded song has correct metadata # if not, remove it and download again without prompt already_tagged = metadata.compare( os.path.join(args.folder, song), meta_tags) log.debug('Checking if it is already tagged correctly? {}', already_tagged) if not already_tagged: os.remove(os.path.join(args.folder, song)) return False log.warning('"{}" already exists'.format(song)) if args.overwrite == 'prompt': log.info('"{}" has already been downloaded. ' 'Re-download? (y/N): '.format(song)) prompt = input('> ') if prompt.lower() == 'y': os.remove(os.path.join(args.folder, song)) return False else: return True elif args.overwrite == 'force': os.remove(os.path.join(args.folder, song)) log.info('Overwriting "{}"'.format(song)) return False elif args.overwrite == 'skip': log.info('Skipping "{}"'.format(song)) return True return False
def download_single(raw_song, number=None): """ Logic behind downloading a song. """ if internals.is_youtube(raw_song): log.debug('Input song is a YouTube URL') content = youtube_tools.go_pafy(raw_song, meta_tags=None) raw_song = slugify(content.title).replace('-', ' ') meta_tags = spotify_tools.generate_metadata(raw_song) else: meta_tags = spotify_tools.generate_metadata(raw_song) content = youtube_tools.go_pafy(raw_song, meta_tags) if content is None: log.debug('Found no matching video') return if const.args.download_only_metadata and meta_tags is None: log.info('Found no metadata. Skipping the download') return # "[number]. [artist] - [song]" if downloading from list # otherwise "[artist] - [song]" youtube_title = youtube_tools.get_youtube_title(content, number) log.info('{} ({})'.format(youtube_title, content.watchv_url)) # generate file name of the song to download songname = content.title if meta_tags is not None: refined_songname = internals.format_string(const.args.file_format, meta_tags, slugification=True) log.debug('Refining songname from "{0}" to "{1}"'.format( songname, refined_songname)) if not refined_songname == ' - ': songname = refined_songname else: log.warning('Could not find metadata') songname = internals.sanitize_title(songname) if const.args.dry_run: return if not check_exists(songname, raw_song, meta_tags): # deal with file formats containing slashes to non-existent directories songpath = os.path.join(const.args.folder, os.path.dirname(songname)) os.makedirs(songpath, exist_ok=True) input_song = songname + const.args.input_ext output_song = songname + const.args.output_ext if youtube_tools.download_song(input_song, content): print('') try: convert.song(input_song, output_song, const.args.folder, avconv=const.args.avconv, trim_silence=const.args.trim_silence) except FileNotFoundError: encoder = 'avconv' if const.args.avconv else 'ffmpeg' log.warning( 'Could not find {0}, skipping conversion'.format(encoder)) const.args.output_ext = const.args.input_ext output_song = songname + const.args.output_ext if not const.args.input_ext == const.args.output_ext: os.remove(os.path.join(const.args.folder, input_song)) if not const.args.no_metadata and meta_tags is not None: metadata.embed(os.path.join(const.args.folder, output_song), meta_tags) return True
def convert(self, uri, convert_count, logged_in): self.playlist_uri = uri self.convert_count = convert_count self.logged_in = logged_in self.progress = 0 self.done = 1 self.out_of = 0 self.time_left = "" self.current_song = "" self.error = "" self.finished = False tracks = [] if 'playlist' in self.playlist_uri: # playlist try: playlist = spotify_tools.fetch_playlist(self.playlist_uri) except spotipy.client.SpotifyException as e: log.error(e) log.debug('Token expired, generating new one and authorizing') new_token = spotify_tools.generate_token() spotify_tools.spotify = spotipy.Spotify(auth=new_token) playlist = spotify_tools.fetch_playlist(self.playlist_uri) if playlist is None: self.error = "Could not find playlist. Please check the playlist URL and try again." return tracks = get_tracks(playlist['tracks']) else: # song try: meta_tags = spotify_tools.generate_metadata(self.playlist_uri) except spotipy.client.SpotifyException as e: log.error(e) self.error = "Could not find song. Please check the song URL and try again." return track_name = meta_tags['name'] track_artist = meta_tags['artists'][0]['name'] track_url = self.playlist_uri tracks.append((track_name, track_artist, track_url)) self.progress = 10 length = len(tracks) time_per_song = 9 self.out_of = length seconds_left = length * time_per_song self.time_left = get_time_left(seconds_left) self.update_state(state="STARTED", meta={'status': '200', 'error': self.error, 'finished': self.finished, 'progress': self.progress, 'current_song': self.current_song, 'done': self.done, 'out_of': self.out_of, 'time_left': self.time_left}) log.info(u'Preparing to convert {} songs'.format(length)) percentPerSong = 90 / length converted_songs = [] for number, track in enumerate(tracks, 1): embed_metadata = self.logged_in high_quality = self.logged_in if self.logged_in or self.convert_count <= max_converts: track_name = track[0] track_artist = track[1] track_url = track[2] start_time = time.time() self.current_song = internals.sanitize_title('{} - {}'.format(track_name, track_artist)) # either not yet converted or not fully converted try: auxport.convert_single(track_url, folder, number, embed_metadata, high_quality) time_per_song = (time.time() - start_time) self.convert_count += 1 # token expires after 1 hour except spotipy.client.SpotifyException as e: # refresh token when it expires log.error(e) log.debug('Token expired, generating new one and authorizing') new_token = spotify_tools.generate_token() spotify_tools.spotify = spotipy.Spotify(auth=new_token) auxport.convert_single(track_url, folder, number, embed_metadata, high_quality) time_per_song = (time.time() - start_time) self.convert_count += 1 # detect network problems except (urllib.request.URLError, TypeError, IOError) as e: log.error(e) log.debug('Network error when converting {} by {}'.format(track_name, track_artist)) continue except Exception as e: log.error(e) continue else: self.convert_count += 1 seconds_left = (length - self.done) * time_per_song if self.done < self.out_of: self.done += 1 self.progress += percentPerSong self.time_left = get_time_left(seconds_left) self.update_state(state="PROGRESS", meta={'status': '200', 'error': self.error, 'finished': self.finished, 'progress': self.progress, 'current_song': self.current_song, 'done': self.done, 'out_of': self.out_of, 'time_left': self.time_left}) log.debug('Percent:' + str(self.progress) + "%") else: # limit reached break