From 3e6b2d7702e0e464c0f9b8c08d68db203be95af1 Mon Sep 17 00:00:00 2001 From: Ritiek Malhotra Date: Fri, 26 Jan 2018 20:44:37 +0530 Subject: [PATCH] Increase coverage (#218) * Monkeypatch fetch user and use pytest.tempdir * Cover spotify_tools.grab_album() * Cover avconv conversion * Cover grab_single() * Reduce code repetition * Move grab_playlist() to spotify_tools.py * Move Spotify specific functions to spotify_tools.py * Refactoring * Return track list from write_tracks() * Fix tests * Cover more cases in generate_youtube_url() * Test for unavailable audio streams * Test for filename without spaces * handle.py 100% coverage * Improve config tests * Speed up tests * Install avconv and libfdk-aac * Some cleaning * FFmpeg with libfdk-aac, libopus * Some refactoring * Convert tmpdir to string * Cover YouTube title when downloading from list * Explicitly cover some internals.py functions --- .gitignore | 1 + .travis.yml | 6 +- core/convert.py | 18 ++--- core/internals.py | 11 +++ core/metadata.py | 3 +- core/spotify_tools.py | 100 +++++++++++++++---------- core/youtube_tools.py | 10 ++- spotdl.py | 57 +++++---------- test/loader.py | 2 + test/test_dry_run.py | 18 +++++ test/test_handle.py | 34 +++++++++ test/test_internals.py | 38 ++++++++++ test/test_list.py | 50 +++++++++++++ test/test_simple.py | 77 -------------------- test/test_spotify.py | 84 --------------------- test/test_username.py | 55 -------------- test/test_with_metadata.py | 133 ++++++++++++++++++++++++++++++++++ test/test_without_metadata.py | 87 ++++++++++++++++++++++ 18 files changed, 474 insertions(+), 310 deletions(-) create mode 100644 test/test_dry_run.py create mode 100644 test/test_handle.py create mode 100644 test/test_internals.py create mode 100644 test/test_list.py delete mode 100644 test/test_simple.py delete mode 100644 test/test_spotify.py delete mode 100644 test/test_username.py create mode 100644 test/test_with_metadata.py create mode 100644 test/test_without_metadata.py diff --git a/.gitignore b/.gitignore index 40db01a..39259af 100755 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ config.yml Music/ *.txt +.coverage *.pyc __pycache__/ diff --git a/.travis.yml b/.travis.yml index 4092b7c..e78439d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ python: - "3.5" - "3.6" before_install: - - sudo apt-get -qq update - pip install tinydownload - pip install codecov - pip install pytest-cov @@ -25,15 +24,18 @@ addons: - libxcb1-dev - libxcb-shm0-dev - libxcb-xfixes0-dev + - libfdk-aac-dev + - libopus-dev - pkg-config - texinfo - zlib1g-dev - yasm - nasm - libmp3lame-dev + - libav-tools install: - pip install -r requirements.txt - - tinydownload 05861434675432854607 -o ~/bin/ffmpeg + - tinydownload 22684734659253158385 -o ~/bin/ffmpeg - chmod 755 ~/bin/ffmpeg script: python -m pytest test --cov=. after_success: codecov diff --git a/core/convert.py b/core/convert.py index d036a52..af7cffd 100644 --- a/core/convert.py +++ b/core/convert.py @@ -42,7 +42,7 @@ class Converter: command = ['avconv', '-loglevel', level, '-i', self.input_file, '-ab', '192k', - self.output_file] + self.output_file, '-y'] log.debug(command) return subprocess.call(command) @@ -53,19 +53,19 @@ class Converter: if not log.level == 10: ffmpeg_pre += '-hide_banner -nostats -v panic ' - input_ext = self.input_file.split('.')[-1] - output_ext = self.output_file.split('.')[-1] + _, input_ext = os.path.splitext(self.input_file) + _, output_ext = os.path.splitext(self.output_file) - if input_ext == 'm4a': - if output_ext == 'mp3': + if input_ext == '.m4a': + if output_ext == '.mp3': ffmpeg_params = '-codec:v copy -codec:a libmp3lame -q:a 2 ' - elif output_ext == 'webm': + elif output_ext == '.webm': ffmpeg_params = '-c:a libopus -vbr on -b:a 192k -vn ' - elif input_ext == 'webm': - if output_ext == 'mp3': + elif input_ext == '.webm': + if output_ext == '.mp3': ffmpeg_params = ' -ab 192k -ar 44100 -vn ' - elif output_ext == 'm4a': + elif output_ext == '.m4a': ffmpeg_params = '-cutoff 20000 -c:a libfdk_aac -b:a 192k -vn ' ffmpeg_pre += ' -i' diff --git a/core/internals.py b/core/internals.py index fa615ae..3c3e1f3 100755 --- a/core/internals.py +++ b/core/internals.py @@ -48,6 +48,7 @@ def trim_song(text_file): data = file_in.read().splitlines(True) with open(text_file, 'w') as file_out: file_out.writelines(data[1:]) + return data[0] def is_spotify(raw_song): @@ -117,3 +118,13 @@ def videotime_from_seconds(time): return '{0}:{1:02}'.format(time//60, time % 60) return '{0}:{1:02}:{2:02}'.format((time//60)//60, (time//60) % 60, time % 60) + + +def get_splits(url): + if '/' in url: + if url.endswith('/'): + url = url[:-1] + splits = url.split('/') + else: + splits = url.split(':') + return splits \ No newline at end of file diff --git a/core/metadata.py b/core/metadata.py index 743e30a..75a748d 100755 --- a/core/metadata.py +++ b/core/metadata.py @@ -8,6 +8,7 @@ import urllib.request def compare(music_file, metadata): """Check if the input music file title matches the expected title.""" + already_tagged = False try: if music_file.endswith('.mp3'): audiofile = EasyID3(music_file) @@ -16,7 +17,7 @@ def compare(music_file, metadata): audiofile = MP4(music_file) already_tagged = audiofile['\xa9nam'][0] == metadata['name'] except (KeyError, TypeError): - already_tagged = False + pass return already_tagged diff --git a/core/spotify_tools.py b/core/spotify_tools.py index 910f369..bc78625 100644 --- a/core/spotify_tools.py +++ b/core/spotify_tools.py @@ -77,7 +77,13 @@ def generate_metadata(raw_song): return meta_tags -def feed_playlist(username): +def write_user_playlist(username, text_file=None): + links = get_playlists(username=username) + playlist = internals.input_link(links) + return write_playlist(playlist, text_file) + + +def get_playlists(username): """ Fetch user playlists when using the -u option. """ playlists = spotify.user_playlists(username) links = [] @@ -91,19 +97,65 @@ def feed_playlist(username): log.info(u'{0:>5}. {1:<30} ({2} tracks)'.format( check, playlist['name'], playlist['tracks']['total'])) - log.debug(playlist['external_urls']['spotify']) - links.append(playlist) + playlist_url = playlist['external_urls']['spotify'] + log.debug(playlist_url) + links.append(playlist_url) check += 1 if playlists['next']: playlists = spotify.next(playlists) else: break - playlist = internals.input_link(links) - write_playlist(playlist['owner']['id'], playlist['id']) + return links -def write_tracks(text_file, tracks): +def fetch_playlist(playlist): + splits = internals.get_splits(playlist) + try: + username = splits[-3] + except IndexError: + # Wrong format, in either case + log.error('The provided playlist URL is not in a recognized format!') + sys.exit(10) + playlist_id = splits[-1] + try: + results = spotify.user_playlist(username, playlist_id, + fields='tracks,next,name') + except spotipy.client.SpotifyException: + log.error('Unable to find playlist') + log.info('Make sure the playlist is set to publicly visible and then try again') + sys.exit(11) + + return results + + +def write_playlist(playlist_url, text_file=None): + playlist = fetch_playlist(playlist_url) + tracks = playlist['tracks'] + if not text_file: + text_file = u'{0}.txt'.format(slugify(playlist['name'], ok='-_()[]{}')) + return write_tracks(tracks, text_file) + + +def fetch_album(album): + splits = internals.get_splits(album) + album_id = splits[-1] + album = spotify.album(album_id) + return album + + +def write_album(album_url, text_file=None): + album = fetch_album(album_url) + tracks = spotify.album_tracks(album['id']) + if not text_file: + text_file = u'{0}.txt'.format(slugify(album['name'], ok='-_()[]{}')) + return write_tracks(tracks, text_file) + + +def write_tracks(tracks, text_file): + log.info(u'Writing {0} tracks to {1}'.format( + tracks['total'], text_file)) + track_urls = [] with open(text_file, 'a') as file_out: while True: for item in tracks['items']: @@ -113,8 +165,9 @@ def write_tracks(text_file, tracks): track = item try: track_url = track['external_urls']['spotify'] - file_out.write(track_url + '\n') log.debug(track_url) + file_out.write(track_url + '\n') + track_urls.append(track_url) except KeyError: log.warning(u'Skipping track {0} by {1} (local only?)'.format( track['name'], track['artists'][0]['name'])) @@ -124,34 +177,5 @@ def write_tracks(text_file, tracks): tracks = spotify.next(tracks) else: break - -def write_playlist(username, playlist_id): - results = spotify.user_playlist(username, playlist_id, - fields='tracks,next,name') - text_file = u'{0}.txt'.format(slugify(results['name'], ok='-_()[]{}')) - log.info(u'Writing {0} tracks to {1}'.format( - results['tracks']['total'], text_file)) - tracks = results['tracks'] - write_tracks(text_file, tracks) - - -def write_album(album): - tracks = spotify.album_tracks(album['id']) - text_file = u'{0}.txt'.format(slugify(album['name'], ok='-_()[]{}')) - log.info(u'writing {0} tracks to {1}'.format( - tracks['total'], text_file)) - write_tracks(text_file, tracks) - - -def grab_album(album): - if '/' in album: - if album.endswith('/'): - playlist = playlist[:-1] - splits = album.split('/') - else: - splits = album.split(':') - - album_id = splits[-1] - album = spotify.album(album_id) - - write_album(album) + log.info(track_urls) + return track_urls diff --git a/core/youtube_tools.py b/core/youtube_tools.py index fcfb454..4a237e1 100644 --- a/core/youtube_tools.py +++ b/core/youtube_tools.py @@ -35,19 +35,21 @@ def get_youtube_title(content, number=None): def download_song(file_name, content): """ Download the audio file from YouTube. """ - if const.args.input_ext in (".webm", ".m4a"): - link = content.getbestaudio(preftype=const.args.input_ext[1:]) + _, extension = os.path.splitext(file_name) + if extension in ('.webm', '.m4a'): + link = content.getbestaudio(preftype=extension[1:]) else: + log.debug('No audio streams available for {} type'.format(extension)) return False if link: log.debug('Downloading from URL: ' + link.url) - filepath = '{0}{1}'.format(os.path.join(const.args.folder, file_name), - const.args.input_ext) + filepath = os.path.join(const.args.folder, file_name) log.debug('Saving to: ' + filepath) link.download(filepath=filepath) return True else: + log.debug('No audio streams available') return False diff --git a/spotdl.py b/spotdl.py index 092bbd6..f175680 100755 --- a/spotdl.py +++ b/spotdl.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 # -*- coding: UTF-8 -*- - from core import const from core import handle from core import metadata @@ -61,7 +60,7 @@ def check_exists(music_file, raw_song, meta_tags): return False -def grab_list(text_file): +def download_list(text_file): """ Download all songs from the list. """ with open(text_file, 'r') as listed: lines = (listed.read()).splitlines() @@ -70,19 +69,21 @@ def grab_list(text_file): lines.remove('') except ValueError: pass + log.info(u'Preparing to download {} songs'.format(len(lines))) + downloaded_songs = [] for number, raw_song in enumerate(lines, 1): print('') try: - grab_single(raw_song, number=number) + download_single(raw_song, number=number) # token expires after 1 hour except spotipy.client.SpotifyException: # refresh token when it expires log.debug('Token expired, generating new one and authorizing') new_token = spotify_tools.generate_token() spotify_tools.spotify = spotipy.Spotify(auth=new_token) - grab_single(raw_song, number=number) + download_single(raw_song, number=number) # detect network problems except (urllib.request.URLError, TypeError, IOError): lines.append(raw_song) @@ -96,34 +97,14 @@ def grab_list(text_file): time.sleep(0.5) continue + downloaded_songs.append(raw_song) log.debug('Removing downloaded song from text file') internals.trim_song(text_file) - -def grab_playlist(playlist): - if '/' in playlist: - if playlist.endswith('/'): - playlist = playlist[:-1] - splits = playlist.split('/') - else: - splits = playlist.split(':') - - try: - username = splits[-3] - except IndexError: - # Wrong format, in either case - log.error('The provided playlist URL is not in a recognized format!') - sys.exit(10) - playlist_id = splits[-1] - try: - spotify_tools.write_playlist(username, playlist_id) - except spotipy.client.SpotifyException: - log.error('Unable to find playlist') - log.info('Make sure the playlist is set to publicly visible and then try again') - sys.exit(11) + return downloaded_songs -def grab_single(raw_song, number=None): +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') @@ -166,11 +147,10 @@ def grab_single(raw_song, number=None): # 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) - if youtube_tools.download_song(songname, content): - input_song = songname + const.args.input_ext - output_song = songname + const.args.output_ext + 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) @@ -182,12 +162,9 @@ def grab_single(raw_song, number=None): 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) - - else: - log.error('No audio streams available') + return True if __name__ == '__main__': @@ -203,15 +180,15 @@ if __name__ == '__main__': try: if const.args.song: - grab_single(raw_song=const.args.song) + download_single(raw_song=const.args.song) elif const.args.list: - grab_list(text_file=const.args.list) + download_list(text_file=const.args.list) elif const.args.playlist: - grab_playlist(playlist=const.args.playlist) + spotify_tools.write_playlist(playlist_url=const.args.playlist) elif const.args.album: - spotify_tools.grab_album(album=const.args.album) + spotify_tools.write_album(album_url=const.args.album) elif const.args.username: - spotify_tools.feed_playlist(username=const.args.username) + spotify_tools.write_user_playlist(username=const.args.username) # actually we don't necessarily need this, but yeah... # explicit is better than implicit! diff --git a/test/loader.py b/test/loader.py index c24536f..2c8d1fe 100644 --- a/test/loader.py +++ b/test/loader.py @@ -1,11 +1,13 @@ from core import const from core import handle import spotdl +import pytest def load_defaults(): const.args = handle.get_arguments(raw_args='', to_group=False, to_merge=False) const.args.overwrite = 'skip' + const.args.log_level = 10 spotdl.args = const.args spotdl.log = const.logzero.setup_logger(formatter=const.formatter, diff --git a/test/test_dry_run.py b/test/test_dry_run.py new file mode 100644 index 0000000..7e61141 --- /dev/null +++ b/test/test_dry_run.py @@ -0,0 +1,18 @@ +from core import const + +import spotdl +import loader +import os + +loader.load_defaults() + + +def test_dry_download_list(tmpdir): + song = 'http://open.spotify.com/track/0JlS7BXXD07hRmevDnbPDU' + const.args.folder = str(tmpdir) + const.args.dry_run = True + file_path = os.path.join(const.args.folder, 'test_list.txt') + with open(file_path, 'w') as tin: + tin.write(song) + downloaded_song, *_ = spotdl.download_list(file_path) + assert downloaded_song == song diff --git a/test/test_handle.py b/test/test_handle.py new file mode 100644 index 0000000..2fcffea --- /dev/null +++ b/test/test_handle.py @@ -0,0 +1,34 @@ +from core import handle + +import pytest +import os +import sys + + +def test_log_str_to_int(): + expect_levels = [20, 30, 40, 10] + levels = [handle.log_leveller(level) + for level in handle._LOG_LEVELS_STR] + assert levels == expect_levels + + +class TestConfig: + def test_default_config(self, tmpdir): + expect_config = handle.default_conf['spotify-downloader'] + global config_path + config_path = os.path.join(str(tmpdir), 'config.yml') + config = handle.get_config(config_path) + assert config == expect_config + + def test_modified_config(self): + default_config = handle.default_conf['spotify-downloader'] + modified_config = dict(default_config) + modified_config['file-format'] = 'just_a_test' + config = handle.merge(default_config, modified_config) + assert config['file-format'] == modified_config['file-format'] + + +def test_grouped_arguments(tmpdir): + sys.path[0] = str(tmpdir) + with pytest.raises(SystemExit): + handle.get_arguments(to_group=True, to_merge=True) diff --git a/test/test_internals.py b/test/test_internals.py new file mode 100644 index 0000000..8d7594a --- /dev/null +++ b/test/test_internals.py @@ -0,0 +1,38 @@ +from core import internals + +import os + + +class TestPathFilterer: + def test_create_directory(self, tmpdir): + expect_path = True + global folder_path + folder_path = os.path.join(str(tmpdir), 'filter_this_folder') + internals.filter_path(folder_path) + is_path = os.path.isdir(folder_path) + assert is_path == expect_path + + def test_remove_temp_files(self, tmpdir): + expect_file = False + file_path = os.path.join(folder_path, 'pesky_file.temp') + open(file_path, 'a') + internals.filter_path(folder_path) + is_file = os.path.isfile(file_path) + assert is_file == expect_file + + +class TestVideoTime: + def test_from_seconds(self): + expect_duration = '35' + duration = internals.videotime_from_seconds(35) + assert duration == expect_duration + + def test_from_minutes(self): + expect_duration = '2:38' + duration = internals.videotime_from_seconds(158) + assert duration == expect_duration + + def test_from_hours(self): + expect_duration = '1:16:02' + duration = internals.videotime_from_seconds(4562) + assert duration == expect_duration diff --git a/test/test_list.py b/test/test_list.py new file mode 100644 index 0000000..fc6bc8b --- /dev/null +++ b/test/test_list.py @@ -0,0 +1,50 @@ +from core import spotify_tools +from core import const + +import spotdl + +import builtins +import os + + +def test_user_playlists(tmpdir, monkeypatch): + expect_tracks = 14 + text_file = os.path.join(str(tmpdir), 'test_us.txt') + monkeypatch.setattr('builtins.input', lambda x: 1) + spotify_tools.write_user_playlist('alex', text_file) + with open(text_file, 'r') as tin: + tracks = len(tin.readlines()) + assert tracks == expect_tracks + + +def test_playlist(tmpdir): + expect_tracks = 14 + text_file = os.path.join(str(tmpdir), 'test_pl.txt') + spotify_tools.write_playlist('https://open.spotify.com/user/alex/playlist/0iWOVoumWlkXIrrBTSJmN8', text_file) + with open(text_file, 'r') as tin: + tracks = len(tin.readlines()) + assert tracks == expect_tracks + + +def test_album(tmpdir): + expect_tracks = 15 + global text_file + text_file = os.path.join(str(tmpdir), 'test_al.txt') + spotify_tools.write_album('https://open.spotify.com/album/499J8bIsEnU7DSrosFDJJg', text_file) + with open(text_file, 'r') as tin: + tracks = len(tin.readlines()) + assert tracks == expect_tracks + + +def test_trim(): + with open(text_file, 'r') as track_file: + tracks = track_file.readlines() + + expect_number = len(tracks) - 1 + expect_track = tracks[0] + track = spotdl.internals.trim_song(text_file) + + with open(text_file, 'r') as track_file: + number = len(track_file.readlines()) + + assert (expect_number == number and expect_track == track) diff --git a/test/test_simple.py b/test/test_simple.py deleted file mode 100644 index 933aed4..0000000 --- a/test/test_simple.py +++ /dev/null @@ -1,77 +0,0 @@ -from core import const -from core import handle -from core import internals -from core import spotify_tools -from core import youtube_tools -from core import convert -from core import metadata - -import spotdl -import loader - -import os - -loader.load_defaults() -internals.filter_path(const.args.folder) -raw_song = "Tony's Videos VERY SHORT VIDEO 28.10.2016" - - -def test_youtube_url(): - expect_url = 'http://youtube.com/watch?v=qOOcy2-tmbk' - url = youtube_tools.generate_youtube_url(raw_song, meta_tags=None) - assert url == expect_url - - -def test_youtube_title(): - global content - global title - expect_title = "Tony's Videos VERY SHORT VIDEO 28.10.2016" - content = youtube_tools.go_pafy(raw_song, meta_tags=None) - title = youtube_tools.get_youtube_title(content) - assert title == expect_title - - -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_download(): - expect_download = True - download = youtube_tools.download_song(file_name, content) - assert download == expect_download - - -def test_convert(): - # exit code 0 = success - expect_converted = 0 - global input_song - global output_song - input_song = file_name + const.args.input_ext - output_song = file_name + const.args.output_ext - converted = convert.song(input_song, output_song, const.args.folder) - assert converted == expect_converted - - -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 test_check_exists2(): - expect_check = True - os.remove(os.path.join(const.args.folder, input_song)) - check = spotdl.check_exists(file_name, raw_song, meta_tags=None) - os.remove(os.path.join(const.args.folder, output_song)) - assert check == expect_check diff --git a/test/test_spotify.py b/test/test_spotify.py deleted file mode 100644 index 8ee9515..0000000 --- a/test/test_spotify.py +++ /dev/null @@ -1,84 +0,0 @@ - -from core import const -from core import handle -from core import internals -from core import spotify_tools -from core import youtube_tools -from core import convert -from core import metadata - -import spotdl - -import loader -import os - -loader.load_defaults() -internals.filter_path(const.args.folder) -raw_song = 'http://open.spotify.com/track/0JlS7BXXD07hRmevDnbPDU' - -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 - - -def test_youtube_url(): - expect_url = 'http://youtube.com/watch?v=rg1wfcty0BA' - url = youtube_tools.generate_youtube_url(raw_song, meta_tags) - assert url == expect_url - - -def test_youtube_title(): - expect_title = 'Intro - David André Østby' - content = youtube_tools.go_pafy(raw_song, meta_tags) - title = youtube_tools.get_youtube_title(content) - assert title == expect_title - - -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_download(): - expect_download = True - # prerequisites for determining filename - content = youtube_tools.go_pafy(raw_song, meta_tags) - download = youtube_tools.download_song(file_name, content) - assert download == expect_download - - -def test_convert(): - # exit code 0 = success - expect_converted = 0 - # prerequisites for determining filename - global input_song - global output_song - input_song = file_name + const.args.input_ext - output_song = file_name + const.args.output_ext - converted = convert.song(input_song, output_song, const.args.folder) - assert converted == expect_converted - - -def test_metadata(): - expect_metadata = True - # prerequisites for determining filename - 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) - assert metadata_output == (metadata_input == expect_metadata) - - -def test_check_exists2(): - expect_check = True - # prerequisites for determining filename - os.remove(os.path.join(const.args.folder, input_song)) - check = spotdl.check_exists(file_name, raw_song, meta_tags) - os.remove(os.path.join(const.args.folder, output_song)) - assert check == expect_check diff --git a/test/test_username.py b/test/test_username.py deleted file mode 100644 index 45552a7..0000000 --- a/test/test_username.py +++ /dev/null @@ -1,55 +0,0 @@ -import spotdl - -spotify = spotdl.spotify_tools.spotify -username = 'alex' - - -def test_user(): - expect_playlists = 7 - playlists = spotify.user_playlists(username) - playlists = len(playlists['items']) - assert playlists == expect_playlists - - -def test_playlist(): - expect_tracks = 14 - playlist = spotify.user_playlists(username)['items'][0] - tracks = playlist['tracks']['total'] - assert tracks == expect_tracks - - -def test_tracks(): - playlist = spotify.user_playlists(username)['items'][0] - expect_lines = playlist['tracks']['total'] - result = spotify.user_playlist( - playlist['owner']['id'], playlist['id'], fields='tracks,next') - tracks = result['tracks'] - - with open('list.txt', 'w') as fout: - while True: - for item in tracks['items']: - track = item['track'] - try: - fout.write(track['external_urls']['spotify'] + '\n') - except KeyError: - pass - # 1 page = 50 results - # check if there are more pages - if tracks['next']: - tracks = spotify.next(tracks) - else: - break - - with open('list.txt', 'r') as listed: - expect_song = (listed.read()).splitlines()[0] - - spotdl.internals.trim_song('list.txt') - with open('list.txt', 'a') as myfile: - myfile.write(expect_song) - - with open('list.txt', 'r') as listed: - songs = (listed.read()).splitlines() - - lines = len(songs) - song = songs[-1] - assert (expect_lines == lines and expect_song == song) diff --git a/test/test_with_metadata.py b/test/test_with_metadata.py new file mode 100644 index 0000000..83a41e4 --- /dev/null +++ b/test/test_with_metadata.py @@ -0,0 +1,133 @@ + +from core import const +from core import internals +from core import spotify_tools +from core import youtube_tools +from core import convert +from core import metadata + +import spotdl + +import loader +import os + +loader.load_defaults() +raw_song = 'http://open.spotify.com/track/0JlS7BXXD07hRmevDnbPDU' + + +def test_metadata(): + expect_number = 22 + global meta_tags + meta_tags = spotify_tools.generate_metadata(raw_song) + assert len(meta_tags) == expect_number + + +class TestFileFormat: + def test_with_spaces(self): + expect_title = 'David André Østby - Intro' + title = internals.generate_songname(const.args.file_format, meta_tags) + assert title == expect_title + + def test_without_spaces(self): + expect_title = 'David_André_Østby_-_Intro' + const.args.no_spaces = True + title = internals.generate_songname(const.args.file_format, meta_tags) + assert title == expect_title + + +def test_youtube_url(): + expect_url = 'http://youtube.com/watch?v=rg1wfcty0BA' + url = youtube_tools.generate_youtube_url(raw_song, meta_tags) + assert url == expect_url + + +def test_youtube_title(): + expect_title = 'Intro - David André Østby' + global content + content = youtube_tools.go_pafy(raw_song, meta_tags) + title = youtube_tools.get_youtube_title(content) + assert title == expect_title + + +def test_check_exists(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 + + +class TestDownload: + def test_m4a(self): + expect_download = True + download = youtube_tools.download_song(file_name + '.m4a', content) + assert download == expect_download + + def test_webm(self): + expect_download = True + download = youtube_tools.download_song(file_name + '.webm', content) + assert download == expect_download + + +class TestFFmpeg(): + def test_convert_from_webm_to_mp3(self): + expect_return_code = 0 + return_code = convert.song(file_name + '.webm', + file_name + '.mp3', + const.args.folder) + assert return_code == expect_return_code + + def test_convert_from_webm_to_m4a(self): + expect_return_code = 0 + return_code = convert.song(file_name + '.webm', + file_name + '.m4a', + const.args.folder) + assert return_code == expect_return_code + + + def test_convert_from_m4a_to_mp3(self): + expect_return_code = 0 + return_code = convert.song(file_name + '.m4a', + file_name + '.mp3', + const.args.folder) + assert return_code == expect_return_code + + def test_convert_from_m4a_to_webm(self): + expect_return_code = 0 + return_code = convert.song(file_name + '.m4a', + file_name + '.webm', + const.args.folder) + os.remove(os.path.join(const.args.folder, file_name + '.webm')) + assert return_code == expect_return_code + + +class TestAvconv: + def test_convert_from_m4a_to_mp3(self): + expect_return_code = 0 + return_code = convert.song(file_name + '.m4a', + file_name + '.mp3', + const.args.folder, + avconv=True) + assert return_code == expect_return_code + + +def test_embed_metadata(): + expect_metadata = True + # prerequisites for determining filename + metadata_input = metadata.embed(os.path.join(const.args.folder, + file_name + '.m4a'), meta_tags) + metadata_output = metadata.embed(os.path.join(const.args.folder, + file_name + '.mp3'), meta_tags) + assert metadata_output == (metadata_input == expect_metadata) + + +def test_check_exists2(): + expect_check = True + # prerequisites for determining filename + os.remove(os.path.join(const.args.folder, file_name + '.m4a')) + check = spotdl.check_exists(file_name, raw_song, meta_tags) + os.remove(os.path.join(const.args.folder, file_name + '.mp3')) + assert check == expect_check diff --git a/test/test_without_metadata.py b/test/test_without_metadata.py new file mode 100644 index 0000000..8027ea1 --- /dev/null +++ b/test/test_without_metadata.py @@ -0,0 +1,87 @@ +from core import const +from core import internals +from core import spotify_tools +from core import youtube_tools + +import spotdl +import loader + +import os +import builtins + +loader.load_defaults() +raw_song = "Tony's Videos VERY SHORT VIDEO 28.10.2016" + + +def test_metadata(): + expect_metadata = None + global metadata + metadata = spotify_tools.generate_metadata(raw_song) + assert metadata == expect_metadata + + +class TestYouTubeURL: + def test_only_music_category(self): + expect_url = 'http://youtube.com/watch?v=P11ou3CXKZo' + const.args.music_videos_only = True + url = youtube_tools.generate_youtube_url(raw_song, metadata) + assert url == expect_url + + def test_all_categories(self): + expect_url = 'http://youtube.com/watch?v=qOOcy2-tmbk' + const.args.music_videos_only = False + url = youtube_tools.generate_youtube_url(raw_song, metadata) + assert url == expect_url + + def test_args_manual(self, monkeypatch): + expect_url = 'http://youtube.com/watch?v=qOOcy2-tmbk' + const.args.manual = True + monkeypatch.setattr('builtins.input', lambda x: '1') + url = youtube_tools.generate_youtube_url(raw_song, metadata) + assert url == expect_url + + def test_args_manual_none(self, monkeypatch): + expect_url = None + monkeypatch.setattr('builtins.input', lambda x: '0') + url = youtube_tools.generate_youtube_url(raw_song, metadata) + const.args.manual = False + assert url == expect_url + + +class TestYouTubeTitle: + def test_single_download(self): + global content + global title + expect_title = "Tony's Videos VERY SHORT VIDEO 28.10.2016" + content = youtube_tools.go_pafy(raw_song, metadata) + title = youtube_tools.get_youtube_title(content) + assert title == expect_title + + def test_download_from_list(self): + expect_title = "1. Tony's Videos VERY SHORT VIDEO 28.10.2016" + content = youtube_tools.go_pafy(raw_song, metadata) + title = youtube_tools.get_youtube_title(content, 1) + assert title == expect_title + + +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 + + +class TestDownload: + def test_webm(self): + # content does not have any .webm audiostream + expect_download = False + download = youtube_tools.download_song(file_name + '.webm', content) + assert download == expect_download + + def test_other(self): + expect_download = False + download = youtube_tools.download_song(file_name + '.fake_extension', content) + assert download == expect_download