def test_metadata(self): raw_song = 'https://open.spotify.com/track/0JlS7BXXD07hRmevDnbPDU' expect_number = 23 global meta_tags meta_tags = spotify_tools.generate_metadata(raw_song) assert len(meta_tags) == expect_number
def get_playlist(playlist_uri): tracks = [] if 'playlist' in playlist_uri: # playlist try: playlist = spotify_tools.fetch_playlist(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(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(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 = playlist_uri return tracks
def fetch_yt_url(url): meta_tags = spotify_tools.generate_metadata(url) content = youtube_tools.go_pafy(url, meta_tags) if content: return content.watchv_url return
def test_metadata(): expect_metadata = None meta_tags = spotify_tools.generate_metadata(raw_song) if meta_tags: metadata_output = metadata.embed( os.path.join(const.args.folder, output_song), meta_tags) metadata_input = metadata.embed( os.path.join(const.args.folder, input_song), meta_tags) else: metadata_input = None metadata_output = None assert (metadata_output == expect_metadata) and (metadata_input == expect_metadata)
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 test_metadata(): expect_number = 22 global meta_tags meta_tags = spotify_tools.generate_metadata(raw_song) assert len(meta_tags) == expect_number
def test_metadata(): expect_metadata = None global metadata metadata = spotify_tools.generate_metadata(raw_song) assert metadata == expect_metadata
from core import config, const, internals, spotdl, spotify_tools, youtube_tools config.init_config() raw_song = "Tony's Videos VERY SHORT VIDEO 28.10.2016" raw_song_spotify = 'https://open.spotify.com/track/33IOhptvC2Qoy2UhjiHXLV' meta_tags = spotify_tools.generate_metadata(raw_song_spotify) file_format = '{artist} - {track_name}' class TestArgsManualResultCount: # Regresson test for issue #264 def test_scrape(self): const.config.manual = True url = youtube_tools.GenerateYouTubeURL("she is still sleeping SAO", meta_tags=None) video_ids = url.scrape(bestmatch=False) # Web scraping gives us all videos on the 1st page assert len(video_ids) == 20 def test_api(self): url = youtube_tools.GenerateYouTubeURL("she is still sleeping SAO", meta_tags=None) video_ids = url.api(bestmatch=False) const.config.manual = False # API gives us 50 videos (or as requested) assert len(video_ids) == 50 class TestYouTubeURL: def test_only_music_category(self):
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 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 = 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.generate_songname(meta_tags) 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') if const.args.dry_run: return file_name = internals.sanitize_title(songname) if not check_exists(file_name, raw_song, meta_tags): if youtube_tools.download_song(file_name, content): input_song = file_name + const.args.input_ext output_song = file_name + const.args.output_ext print('') try: convert.song(input_song, output_song, const.args.folder, avconv=const.args.avconv) 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 = file_name + 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) if const.args.preserve_spaces and "_" in output_song: song_path = os.path.join(const.args.folder, output_song.replace('_', ' ')) os.rename(os.path.join(const.args.folder, output_song), song_path) else: log.error('No audio streams available')
def MP3Tagger(self): Caminho = self.lineEdit.text() if Caminho == "": QMessageBox.about(self, "ERRO", "Nenhum caminho especificado.") else: File = glob.glob(Caminho + "/*.mp3") for i in File: # Caminho completo do arquivo com extensão self.label_10.setText(_translate("MainWindow", "")) QtWidgets.QApplication.processEvents() Path = os.path.dirname(i) # Caninho completo da pasta do arquivo Name1 = os.path.basename(i) # Nome do arquivo completo com extensão Name2 = os.path.splitext(Name1) # Nome do arquivo dividido na extensão Name3 = Name2[0].split(" - ") # Nome do arquivo divido no artista e musica Name4 = ''.join(i for i in Name3[0] if not i.isdigit()) # Nome da música sem os números print("Caminho: " + i) print("Name1: " + str(Name1)) print("Name2: " + str(Name2)) print("Name3: " + str(Name3)) print("Name4: " + str(Name4)) self.label_10.setText(_translate("MainWindow", "Renomeando arquivo...")) QtWidgets.QApplication.processEvents() os.rename(i, Path + "\\" + Name3[1] + " -" + Name4 + ".mp3") # Renomeia o arquivo self.label_10.setText(_translate("MainWindow", "Buscando metadados no banco de dados do Spotify...")) QtWidgets.QApplication.processEvents() meta_tags = spotify_tools.generate_metadata(Name3[1] + " -" + Name4) # Gera as tags do mp3 if meta_tags == None: continue else: self.label_6.setText(_translate("MainWindow", str(meta_tags['artists'][0]['name']))) self.label_7.setText(_translate("MainWindow", str(meta_tags['name']))) self.label_8.setText(_translate("MainWindow", str(meta_tags['album']['name']))) self.label_10.setText(_translate("MainWindow", "Aplicando tags...")) ScriptFolder = os.path.dirname(os.path.realpath(sys.argv[0])) IMG = open(ScriptFolder + "\\" + 'cover2.jpg', 'wb') IMG.write(urllib.request.urlopen(meta_tags['album']['images'][0]['url']).read()) IMG.close() time.sleep(1) self.GenericCover3 = QPixmap('cover2.jpg') self.GenericCover4 = self.GenericCover3.scaled(141, 141) self.graphicsView.setPixmap(self.GenericCover4) QtWidgets.QApplication.processEvents() audiofile = MP3(Path + "\\" + Name3[1] + " -" + Name4 + ".mp3") audiofile.tags = None # Exclui qualquer tag antes de aplicar as novas (previne erro) audiofile.add_tags(ID3=EasyID3) audiofile['artist'] = meta_tags['artists'][0]['name'] audiofile['albumartist'] = meta_tags['artists'][0]['name'] audiofile['album'] = meta_tags['album']['name'] audiofile['title'] = meta_tags['name'] audiofile['tracknumber'] = [meta_tags['track_number'], meta_tags['total_tracks']] audiofile['discnumber'] = [meta_tags['disc_number'], 0] audiofile['date'] = meta_tags['release_date'] audiofile['originaldate'] = meta_tags['release_date'] audiofile['media'] = meta_tags['type'] audiofile['author'] = meta_tags['artists'][0]['name'] audiofile['lyricist'] = meta_tags['artists'][0]['name'] audiofile['arranger'] = meta_tags['artists'][0]['name'] audiofile['performer'] = meta_tags['artists'][0]['name'] audiofile['website'] = meta_tags['external_urls']['spotify'] audiofile['length'] = str(meta_tags['duration_ms'] / 1000.0) if meta_tags['publisher']: audiofile['encodedby'] = meta_tags['publisher'] if meta_tags['genre']: audiofile['genre'] = meta_tags['genre'] if meta_tags['copyright']: audiofile['copyright'] = meta_tags['copyright'] if meta_tags['external_ids']['isrc']: audiofile['isrc'] = meta_tags['external_ids']['isrc'] audiofile.save(v2_version=3) # For supported id3 tags: # https://github.com/quodlibet/mutagen/blob/master/mutagen/id3/_frames.py # Each class represents an id3 tag audiofile = ID3(Path + "\\" + Name3[1] + " -" + Name4 + ".mp3") year, *_ = meta_tags['release_date'].split('-') audiofile['TORY'] = TORY(encoding=3, text=year) audiofile['TYER'] = TYER(encoding=3, text=year) audiofile['TPUB'] = TPUB(encoding=3, text=meta_tags['publisher']) audiofile['COMM'] = COMM(encoding=3, text=meta_tags['external_urls']['spotify']) if meta_tags['lyrics']: audiofile['USLT'] = USLT(encoding=3, desc=u'Lyrics', text=meta_tags['lyrics']) try: albumart = urllib.request.urlopen(meta_tags['album']['images'][0]['url']) audiofile['APIC'] = APIC(encoding=3, mime='image/jpeg', type=3, desc=u'Cover', data=albumart.read()) albumart.close() except IndexError: pass audiofile.save(v2_version=3) self.label_10.setText(_translate("MainWindow", "Concluído.")) QtWidgets.QApplication.processEvents() time.sleep(2) # pausa dramática # Some com os textos: self.label_10.setText(_translate("MainWindow", "")) QtWidgets.QApplication.processEvents() QMessageBox.about(self, "Concluído", "Operação concluída.")
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
def test_spotify_title(): expect_title = 'David André Østby - Intro' global meta_tags meta_tags = spotify_tools.generate_metadata(raw_song) title = internals.generate_songname(const.args.file_format, meta_tags) assert title == expect_title