mirror of
				https://github.com/KevinMidboe/spotify-downloader.git
				synced 2025-10-29 18:00:15 +00:00 
			
		
		
		
	Merge branch 'master' into feat/keep-trackid-as-songname
This commit is contained in:
		| @@ -1,6 +1,4 @@ | ||||
| dist: xenial | ||||
| language: python | ||||
| sudo: required | ||||
| python: | ||||
|   - "3.4" | ||||
|   - "3.5" | ||||
|   | ||||
| @@ -7,10 +7,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. | ||||
| ## [Unreleased] | ||||
| ### Added | ||||
| - Added `--no-remove-original-file` ([@NightMachinary](https://github.com/NightMachinary)) (#580) | ||||
| - Added leading Zeros in `track_number` for correct sorting ([@Dsujan](https://github.com/Dsujan)) (#592) | ||||
| - Added `track_id` key for `--file-format` parameter ([@kadaliao](https://github.com/kadaliao)) (#568) | ||||
|  | ||||
| ### Fixed | ||||
| - | ||||
| - Generate list error --write-m3u ([@arthurlutz](https://github.com/arthurlutz)) (#559) | ||||
|  | ||||
| ### Changed | ||||
| - Fetch lyrics from Genius and fallback to LyricWikia if not found ([@ritiek](https://github.com/ritiek)) (#585) | ||||
|   | ||||
							
								
								
									
										2
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								setup.py
									
									
									
									
									
								
							| @@ -10,7 +10,7 @@ setup( | ||||
|     name="spotdl", | ||||
|     # Tests are included automatically: | ||||
|     # https://docs.python.org/3.6/distutils/sourcedist.html#specifying-the-files-to-distribute | ||||
|     packages=["spotdl"], | ||||
|     packages=["spotdl", "spotdl.lyrics", "spotdl.lyrics.providers"], | ||||
|     version=spotdl.__version__, | ||||
|     install_requires=[ | ||||
|         "pathlib >= 1.0.1", | ||||
|   | ||||
| @@ -16,7 +16,14 @@ https://trac.ffmpeg.org/wiki/Encode/AAC | ||||
| """ | ||||
|  | ||||
|  | ||||
| def song(input_song, output_song, folder, avconv=False, trim_silence=False, delete_original=True): | ||||
| def song( | ||||
|     input_song, | ||||
|     output_song, | ||||
|     folder, | ||||
|     avconv=False, | ||||
|     trim_silence=False, | ||||
|     delete_original=True, | ||||
| ): | ||||
|     """ Do the audio format conversion. """ | ||||
|     if avconv and trim_silence: | ||||
|         raise ValueError("avconv does not support trim_silence") | ||||
| @@ -28,7 +35,9 @@ def song(input_song, output_song, folder, avconv=False, trim_silence=False, dele | ||||
|     else: | ||||
|         return 0 | ||||
|  | ||||
|     convert = Converter(input_song, output_song, folder, delete_original=delete_original) | ||||
|     convert = Converter( | ||||
|         input_song, output_song, folder, delete_original=delete_original | ||||
|     ) | ||||
|     if avconv: | ||||
|         exit_code, command = convert.with_avconv() | ||||
|     else: | ||||
| @@ -97,7 +106,9 @@ class Converter: | ||||
|         return code, command | ||||
|  | ||||
|     def with_ffmpeg(self, trim_silence=False): | ||||
|         ffmpeg_pre = "ffmpeg -y -nostdin " # -nostdin is necessary for spotdl to be able to run in the backgroung. | ||||
|         ffmpeg_pre = ( | ||||
|             "ffmpeg -y -nostdin " | ||||
|         )  # -nostdin is necessary for spotdl to be able to run in the backgroung. | ||||
|  | ||||
|         if not log.level == 10: | ||||
|             ffmpeg_pre += "-hide_banner -nostats -v panic " | ||||
|   | ||||
| @@ -96,6 +96,7 @@ class Downloader: | ||||
|         self.raw_song = raw_song | ||||
|         self.number = number | ||||
|         self.content, self.meta_tags = youtube_tools.match_video_and_metadata(raw_song) | ||||
|         self.total_songs = int(self.meta_tags["total_tracks"]) | ||||
|  | ||||
|     def download_single(self): | ||||
|         """ Logic behind downloading a song. """ | ||||
| @@ -158,7 +159,10 @@ class Downloader: | ||||
|     def refine_songname(self, songname): | ||||
|         if self.meta_tags is not None: | ||||
|             refined_songname = internals.format_string( | ||||
|                 const.args.file_format, self.meta_tags, slugification=True | ||||
|                 const.args.file_format, | ||||
|                 self.meta_tags, | ||||
|                 slugification=True, | ||||
|                 total_songs=self.total_songs, | ||||
|             ) | ||||
|             log.debug( | ||||
|                 'Refining songname from "{0}" to "{1}"'.format( | ||||
|   | ||||
| @@ -37,7 +37,7 @@ default_conf = { | ||||
|         "write-successful": None, | ||||
|         "log-level": "INFO", | ||||
|         "spotify_client_id": "4fe3fecfe5334023a1472516cc99d805", | ||||
|         "spotify_client_secret": "0f02b7c483c04257984695007a4a8d5c" | ||||
|         "spotify_client_secret": "0f02b7c483c04257984695007a4a8d5c", | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -280,13 +280,13 @@ def get_arguments(raw_args=None, to_group=True, to_merge=True): | ||||
|         "-sci", | ||||
|         "--spotify-client-id", | ||||
|         default=config["spotify_client_id"], | ||||
|         help=argparse.SUPPRESS | ||||
|         help=argparse.SUPPRESS, | ||||
|     ) | ||||
|     parser.add_argument( | ||||
|         "-scs", | ||||
|         "--spotify-client-secret", | ||||
|         default=config["spotify_client_secret"], | ||||
|         help=argparse.SUPPRESS | ||||
|         help=argparse.SUPPRESS, | ||||
|     ) | ||||
|     parser.add_argument( | ||||
|         "-c", "--config", default=None, help="path to custom config.yml file" | ||||
| @@ -320,11 +320,12 @@ def get_arguments(raw_args=None, to_group=True, to_merge=True): | ||||
|     if parsed.avconv and parsed.trim_silence: | ||||
|         parser.error("--trim-silence can only be used with FFmpeg") | ||||
|  | ||||
|     if parsed.write_to and not (parsed.playlist \ | ||||
|             or parsed.album \ | ||||
|             or parsed.all_albums \ | ||||
|             or parsed.username): | ||||
|         parser.error("--write-to can only be used with --playlist, --album, --all-albums, or --username") | ||||
|     if parsed.write_to and not ( | ||||
|         parsed.playlist or parsed.album or parsed.all_albums or parsed.username | ||||
|     ): | ||||
|         parser.error( | ||||
|             "--write-to can only be used with --playlist, --album, --all-albums, or --username" | ||||
|         ) | ||||
|  | ||||
|     parsed.log_level = log_leveller(parsed.log_level) | ||||
|  | ||||
|   | ||||
| @@ -1,8 +1,10 @@ | ||||
| from logzero import logger as log | ||||
| import os | ||||
| import sys | ||||
| import math | ||||
| import urllib.request | ||||
|  | ||||
|  | ||||
| from spotdl import const | ||||
|  | ||||
| try: | ||||
| @@ -74,7 +76,9 @@ def is_youtube(raw_song): | ||||
|     return status | ||||
|  | ||||
|  | ||||
| def format_string(string_format, tags, slugification=False, force_spaces=False): | ||||
| def format_string( | ||||
|     string_format, tags, slugification=False, force_spaces=False, total_songs=0 | ||||
| ): | ||||
|     """ Generate a string of the format '[artist] - [song]' for the given spotify song. """ | ||||
|     format_tags = dict(formats) | ||||
|     format_tags[0] = tags["name"] | ||||
| @@ -95,9 +99,16 @@ def format_string(string_format, tags, slugification=False, force_spaces=False): | ||||
|         k: sanitize_title(str(v), ok="'-_()[]{}") if slugification else str(v) | ||||
|         for k, v in format_tags.items() | ||||
|     } | ||||
|     # calculating total digits presnet in total_songs to prepare a zfill. | ||||
|     total_digits = 0 if total_songs == 0 else int(math.log10(total_songs)) + 1 | ||||
|  | ||||
|     for x in formats: | ||||
|         format_tag = "{" + formats[x] + "}" | ||||
|         # Making consistent track number by prepending zero | ||||
|         # on it according to number of digits in total songs | ||||
|         if format_tag == "{track_number}": | ||||
|             format_tags_sanitized[x] = format_tags_sanitized[x].zfill(total_digits) | ||||
|  | ||||
|         string_format = string_format.replace(format_tag, format_tags_sanitized[x]) | ||||
|  | ||||
|     if const.args.no_spaces and not force_spaces: | ||||
|   | ||||
| @@ -18,7 +18,6 @@ class TestGenius: | ||||
|         assert track.base_url == "https://genius.com" | ||||
|  | ||||
|     def test_get_lyrics(self, track, monkeypatch): | ||||
|  | ||||
|         def mocked_urlopen(url, timeout=None): | ||||
|             class DummyHTTPResponse: | ||||
|                 def read(self): | ||||
| @@ -30,7 +29,6 @@ class TestGenius: | ||||
|         assert track.get_lyrics() == "amazing lyrics!" | ||||
|  | ||||
|     def test_lyrics_not_found_error(self, track, monkeypatch): | ||||
|  | ||||
|         def mocked_urlopen(url, timeout=None): | ||||
|             raise urllib.request.HTTPError("", "", "", "", "") | ||||
|  | ||||
|   | ||||
| @@ -15,17 +15,21 @@ class TestLyricWikia: | ||||
|         # `LyricWikia` class uses the 3rd party method `lyricwikia.get_lyrics` | ||||
|         # internally and there is no need to test a 3rd party library as they | ||||
|         # have their own implementation of tests. | ||||
|         monkeypatch.setattr("lyricwikia.get_lyrics", lambda a, b, c, d: "awesome lyrics!") | ||||
|         monkeypatch.setattr( | ||||
|             "lyricwikia.get_lyrics", lambda a, b, c, d: "awesome lyrics!" | ||||
|         ) | ||||
|         track = LyricWikia("Lyricwikia", "Lyricwikia") | ||||
|         assert track.get_lyrics() == "awesome lyrics!" | ||||
|  | ||||
|     def test_lyrics_not_found_error(self, monkeypatch): | ||||
|  | ||||
|         def lyricwikia_lyrics_not_found(msg): | ||||
|             raise lyricwikia.LyricsNotFound(msg) | ||||
|  | ||||
|         # Wrap `lyricwikia.LyricsNotFound` with `exceptions.LyricsNotFound` error. | ||||
|         monkeypatch.setattr("lyricwikia.get_lyrics", lambda a, b, c, d: lyricwikia_lyrics_not_found("Nope, no lyrics.")) | ||||
|         monkeypatch.setattr( | ||||
|             "lyricwikia.get_lyrics", | ||||
|             lambda a, b, c, d: lyricwikia_lyrics_not_found("Nope, no lyrics."), | ||||
|         ) | ||||
|         track = LyricWikia("Lyricwikia", "Lyricwikia") | ||||
|         with pytest.raises(exceptions.LyricsNotFound): | ||||
|             track.get_lyrics() | ||||
|   | ||||
| @@ -80,7 +80,9 @@ class EmbedMetadata: | ||||
|         audiofile["TYER"] = TYER(encoding=3, text=meta_tags["year"]) | ||||
|         if meta_tags["publisher"]: | ||||
|             audiofile["TPUB"] = TPUB(encoding=3, text=meta_tags["publisher"]) | ||||
|         audiofile["COMM"] = COMM(encoding=3, text=meta_tags["external_urls"][self.provider]) | ||||
|         audiofile["COMM"] = COMM( | ||||
|             encoding=3, text=meta_tags["external_urls"][self.provider] | ||||
|         ) | ||||
|         if meta_tags["lyrics"]: | ||||
|             audiofile["USLT"] = USLT( | ||||
|                 encoding=3, desc=u"Lyrics", text=meta_tags["lyrics"] | ||||
|   | ||||
| @@ -11,24 +11,30 @@ def _getbestthumb(self): | ||||
|  | ||||
|     part_url = "https://i.ytimg.com/vi/%s/" % self.videoid | ||||
|     # Thumbnail resolution sorted in descending order | ||||
|     thumbs = ("maxresdefault.jpg", | ||||
|               "sddefault.jpg", | ||||
|               "hqdefault.jpg", | ||||
|               "mqdefault.jpg", | ||||
|               "default.jpg") | ||||
|     thumbs = ( | ||||
|         "maxresdefault.jpg", | ||||
|         "sddefault.jpg", | ||||
|         "hqdefault.jpg", | ||||
|         "mqdefault.jpg", | ||||
|         "default.jpg", | ||||
|     ) | ||||
|     for thumb in thumbs: | ||||
|         url = part_url + thumb | ||||
|         if self._content_available(url): | ||||
|             return url | ||||
|  | ||||
|  | ||||
| def _process_streams(self): | ||||
|     for format_index in range(len(self._ydl_info['formats'])): | ||||
|     for format_index in range(len(self._ydl_info["formats"])): | ||||
|         try: | ||||
|             self._ydl_info['formats'][format_index]['url'] = self._ydl_info['formats'][format_index]['fragment_base_url'] | ||||
|             self._ydl_info["formats"][format_index]["url"] = self._ydl_info["formats"][ | ||||
|                 format_index | ||||
|             ]["fragment_base_url"] | ||||
|         except KeyError: | ||||
|             pass | ||||
|     return backend_youtube_dl.YtdlPafy._old_process_streams(self) | ||||
|  | ||||
|  | ||||
| @classmethod | ||||
| def _content_available(cls, url): | ||||
|     return internals.content_available(url) | ||||
| @@ -39,6 +45,7 @@ class PatchPafy: | ||||
|     These patches have not been released by pafy on PyPI yet but | ||||
|     are useful to us. | ||||
|     """ | ||||
|  | ||||
|     def patch_getbestthumb(self): | ||||
|         # https://github.com/mps-youtube/pafy/pull/211 | ||||
|         pafy.backend_shared.BasePafy._bestthumb = None | ||||
| @@ -47,7 +54,9 @@ class PatchPafy: | ||||
|  | ||||
|     def patch_process_streams(self): | ||||
|         # https://github.com/mps-youtube/pafy/pull/230 | ||||
|         backend_youtube_dl.YtdlPafy._old_process_streams = backend_youtube_dl.YtdlPafy._process_streams | ||||
|         backend_youtube_dl.YtdlPafy._old_process_streams = ( | ||||
|             backend_youtube_dl.YtdlPafy._process_streams | ||||
|         ) | ||||
|         backend_youtube_dl.YtdlPafy._process_streams = _process_streams | ||||
|  | ||||
|     def patch_insecure_streams(self): | ||||
|   | ||||
| @@ -28,8 +28,9 @@ def match_args(): | ||||
|             track_dl.download_single() | ||||
|     elif const.args.list: | ||||
|         if const.args.write_m3u: | ||||
|             youtube_tools.generate_m3u(track_file=const.args.list, | ||||
|                                        text_file=const.args.write_to) | ||||
|             youtube_tools.generate_m3u( | ||||
|                 track_file=const.args.list | ||||
|             ) | ||||
|         else: | ||||
|             list_dl = downloader.ListDownloader( | ||||
|                 tracks_file=const.args.list, | ||||
| @@ -38,17 +39,21 @@ def match_args(): | ||||
|             ) | ||||
|             list_dl.download_list() | ||||
|     elif const.args.playlist: | ||||
|         spotify_tools.write_playlist(playlist_url=const.args.playlist, | ||||
|                                      text_file=const.args.write_to) | ||||
|         spotify_tools.write_playlist( | ||||
|             playlist_url=const.args.playlist, text_file=const.args.write_to | ||||
|         ) | ||||
|     elif const.args.album: | ||||
|         spotify_tools.write_album(album_url=const.args.album, | ||||
|                                   text_file=const.args.write_to) | ||||
|         spotify_tools.write_album( | ||||
|             album_url=const.args.album, text_file=const.args.write_to | ||||
|         ) | ||||
|     elif const.args.all_albums: | ||||
|         spotify_tools.write_all_albums_from_artist(artist_url=const.args.all_albums, | ||||
|                                                    text_file=const.args.write_to) | ||||
|         spotify_tools.write_all_albums_from_artist( | ||||
|             artist_url=const.args.all_albums, text_file=const.args.write_to | ||||
|         ) | ||||
|     elif const.args.username: | ||||
|         spotify_tools.write_user_playlist(username=const.args.username, | ||||
|                                           text_file=const.args.write_to) | ||||
|         spotify_tools.write_user_playlist( | ||||
|             username=const.args.username, text_file=const.args.write_to | ||||
|         ) | ||||
|  | ||||
|  | ||||
| def main(): | ||||
|   | ||||
| @@ -17,8 +17,6 @@ from spotdl.lyrics.exceptions import LyricsNotFound | ||||
| spotify = None | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| def generate_token(): | ||||
|     """ Generate the token. """ | ||||
|     credentials = oauth2.SpotifyClientCredentials( | ||||
| @@ -39,6 +37,7 @@ def must_be_authorized(func, spotify=spotify): | ||||
|             token = generate_token() | ||||
|             spotify = spotipy.Spotify(auth=token) | ||||
|             return func(*args, **kwargs) | ||||
|  | ||||
|     return wrapper | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -18,6 +18,7 @@ pafy.g.opener.addheaders.append(("Range", "bytes=0-")) | ||||
| # More info: https://github.com/mps-youtube/pafy/pull/211 | ||||
| if pafy.__version__ <= "0.5.4": | ||||
|     from spotdl import patcher | ||||
|  | ||||
|     pafy_patcher = patcher.PatchPafy() | ||||
|     pafy_patcher.patch_getbestthumb() | ||||
|     pafy_patcher.patch_process_streams() | ||||
| @@ -52,10 +53,13 @@ def match_video_and_metadata(track): | ||||
|     """ Get and match track data from YouTube and Spotify. """ | ||||
|     meta_tags = None | ||||
|  | ||||
|  | ||||
|     def fallback_metadata(meta_tags): | ||||
|         fallback_metadata_info = "Track not found on Spotify, falling back on YouTube metadata" | ||||
|         skip_fallback_metadata_warning = "Fallback condition not met, shall not embed metadata" | ||||
|         fallback_metadata_info = ( | ||||
|             "Track not found on Spotify, falling back on YouTube metadata" | ||||
|         ) | ||||
|         skip_fallback_metadata_warning = ( | ||||
|             "Fallback condition not met, shall not embed metadata" | ||||
|         ) | ||||
|         if meta_tags is None: | ||||
|             if const.args.no_fallback_metadata: | ||||
|                 log.warning(skip_fallback_metadata_warning) | ||||
| @@ -64,7 +68,6 @@ def match_video_and_metadata(track): | ||||
|                 meta_tags = generate_metadata(content) | ||||
|         return meta_tags | ||||
|  | ||||
|  | ||||
|     if internals.is_youtube(track): | ||||
|         log.debug("Input song is a YouTube URL") | ||||
|         content = go_pafy(track, meta_tags=None) | ||||
| @@ -95,25 +98,29 @@ def match_video_and_metadata(track): | ||||
|  | ||||
| def generate_metadata(content): | ||||
|     """ Fetch a song's metadata from YouTube. """ | ||||
|     meta_tags = {"spotify_metadata": False, | ||||
|                  "name": content.title, | ||||
|                  "artists": [{"name": content.author}], | ||||
|                  "duration": content.length, | ||||
|                  "external_urls": {"youtube": content.watchv_url}, | ||||
|                  "album": {"images" : [{"url": content.getbestthumb()}], | ||||
|                            "artists": [{"name": None}],"name": None}, | ||||
|                  "year": content.published.split("-")[0], | ||||
|                  "release_date": content.published.split(" ")[0], | ||||
|                  "type": "track", | ||||
|                  "disc_number": 1, | ||||
|                  "track_number": 1, | ||||
|                  "total_tracks": 1, | ||||
|                  "publisher": None, | ||||
|                  "external_ids": {"isrc": None}, | ||||
|                  "lyrics": None, | ||||
|                  "copyright": None, | ||||
|                  "genre": None, | ||||
|                  } | ||||
|     meta_tags = { | ||||
|         "spotify_metadata": False, | ||||
|         "name": content.title, | ||||
|         "artists": [{"name": content.author}], | ||||
|         "duration": content.length, | ||||
|         "external_urls": {"youtube": content.watchv_url}, | ||||
|         "album": { | ||||
|             "images": [{"url": content.getbestthumb()}], | ||||
|             "artists": [{"name": None}], | ||||
|             "name": None, | ||||
|         }, | ||||
|         "year": content.published.split("-")[0], | ||||
|         "release_date": content.published.split(" ")[0], | ||||
|         "type": "track", | ||||
|         "disc_number": 1, | ||||
|         "track_number": 1, | ||||
|         "total_tracks": 1, | ||||
|         "publisher": None, | ||||
|         "external_ids": {"isrc": None}, | ||||
|         "lyrics": None, | ||||
|         "copyright": None, | ||||
|         "genre": None, | ||||
|     } | ||||
|  | ||||
|     return meta_tags | ||||
|  | ||||
|   | ||||
| @@ -20,7 +20,7 @@ def load_defaults(): | ||||
| # so that we get same results even if YouTube changes the list/order of videos on their page. | ||||
| GIST_URL = "https://gist.githubusercontent.com/ritiek/e731338e9810e31c2f00f13c249a45f5/raw/c11a27f3b5d11a8d082976f1cdd237bd605ec2c2/search_results.html" | ||||
|  | ||||
|  | ||||
| def monkeypatch_youtube_search_page(*args, **kwargs): | ||||
|     fake_urlopen = urllib.request.urlopen(GIST_URL) | ||||
|     return fake_urlopen | ||||
|  | ||||
|   | ||||
| @@ -101,16 +101,28 @@ class TestDownload: | ||||
|  | ||||
|     def test_m4a(self, monkeypatch, filename_fixture): | ||||
|         expect_download = True | ||||
|         monkeypatch.setattr("pafy.backend_shared.BaseStream.download", self.blank_audio_generator) | ||||
|         monkeypatch.setattr("pafy.backend_youtube_dl.YtdlStream.download", self.blank_audio_generator) | ||||
|         download = youtube_tools.download_song(filename_fixture + ".m4a", pytest.content_fixture) | ||||
|         monkeypatch.setattr( | ||||
|             "pafy.backend_shared.BaseStream.download", self.blank_audio_generator | ||||
|         ) | ||||
|         monkeypatch.setattr( | ||||
|             "pafy.backend_youtube_dl.YtdlStream.download", self.blank_audio_generator | ||||
|         ) | ||||
|         download = youtube_tools.download_song( | ||||
|             filename_fixture + ".m4a", pytest.content_fixture | ||||
|         ) | ||||
|         assert download == expect_download | ||||
|  | ||||
|     def test_webm(self, monkeypatch, filename_fixture): | ||||
|         expect_download = True | ||||
|         monkeypatch.setattr("pafy.backend_shared.BaseStream.download", self.blank_audio_generator) | ||||
|         monkeypatch.setattr("pafy.backend_youtube_dl.YtdlStream.download", self.blank_audio_generator) | ||||
|         download = youtube_tools.download_song(filename_fixture + ".webm", pytest.content_fixture) | ||||
|         monkeypatch.setattr( | ||||
|             "pafy.backend_shared.BaseStream.download", self.blank_audio_generator | ||||
|         ) | ||||
|         monkeypatch.setattr( | ||||
|             "pafy.backend_youtube_dl.YtdlStream.download", self.blank_audio_generator | ||||
|         ) | ||||
|         download = youtube_tools.download_song( | ||||
|             filename_fixture + ".webm", pytest.content_fixture | ||||
|         ) | ||||
|         assert download == expect_download | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import pytest | ||||
| pafy_patcher = patcher.PatchPafy() | ||||
| pafy_patcher.patch_getbestthumb() | ||||
|  | ||||
|  | ||||
| class TestPafyContentAvailable: | ||||
|     pass | ||||
|  | ||||
| @@ -30,7 +31,6 @@ class TestMethodCalls: | ||||
|         thumbnail = patcher._getbestthumb(content_fixture) | ||||
|         assert thumbnail == "https://i.ytimg.com/vi/3nQNiWdeH2Q/sddefault.jpg" | ||||
|  | ||||
|  | ||||
|     def test_pafy_content_available(self): | ||||
|         TestPafyContentAvailable._content_available = patcher._content_available | ||||
|         assert TestPafyContentAvailable()._content_available("https://youtube.com/") | ||||
|   | ||||
| @@ -104,19 +104,19 @@ def content_fixture(metadata_fixture): | ||||
| MATCH_METADATA_NO_FALLBACK_TEST_TABLE = [ | ||||
|     ("https://open.spotify.com/track/5nWduGwBGBn1PSqYTJUDbS", True), | ||||
|     ("http://youtube.com/watch?v=3nQNiWdeH2Q", None), | ||||
|     ("Linux Talk | Working with Drives and Filesystems", None) | ||||
|     ("Linux Talk | Working with Drives and Filesystems", None), | ||||
| ] | ||||
|  | ||||
| MATCH_METADATA_FALLBACK_TEST_TABLE = [ | ||||
|     ("https://open.spotify.com/track/5nWduGwBGBn1PSqYTJUDbS", True), | ||||
|     ("http://youtube.com/watch?v=3nQNiWdeH2Q", False), | ||||
|     ("Linux Talk | Working with Drives and Filesystems", False) | ||||
|     ("Linux Talk | Working with Drives and Filesystems", False), | ||||
| ] | ||||
|  | ||||
| MATCH_METADATA_NO_METADATA_TEST_TABLE = [ | ||||
|     ("https://open.spotify.com/track/5nWduGwBGBn1PSqYTJUDbS", None), | ||||
|     ("http://youtube.com/watch?v=3nQNiWdeH2Q", None), | ||||
|     ("Linux Talk | Working with Drives and Filesystems", None) | ||||
|     ("Linux Talk | Working with Drives and Filesystems", None), | ||||
| ] | ||||
|  | ||||
|  | ||||
| @@ -128,21 +128,37 @@ class TestMetadataOrigin: | ||||
|         else: | ||||
|             assert metadata["spotify_metadata"] == metadata_type | ||||
|  | ||||
|     @pytest.mark.parametrize("track, metadata_type", MATCH_METADATA_NO_FALLBACK_TEST_TABLE) | ||||
|     def test_match_metadata_with_no_fallback(self, track, metadata_type, content_fixture, monkeypatch): | ||||
|         monkeypatch.setattr(youtube_tools, "go_pafy", lambda track, meta_tags: content_fixture) | ||||
|     @pytest.mark.parametrize( | ||||
|         "track, metadata_type", MATCH_METADATA_NO_FALLBACK_TEST_TABLE | ||||
|     ) | ||||
|     def test_match_metadata_with_no_fallback( | ||||
|         self, track, metadata_type, content_fixture, monkeypatch | ||||
|     ): | ||||
|         monkeypatch.setattr( | ||||
|             youtube_tools, "go_pafy", lambda track, meta_tags: content_fixture | ||||
|         ) | ||||
|         const.args.no_fallback_metadata = True | ||||
|         self.match_metadata(track, metadata_type) | ||||
|  | ||||
|     @pytest.mark.parametrize("track, metadata_type", MATCH_METADATA_FALLBACK_TEST_TABLE) | ||||
|     def test_match_metadata_with_fallback(self, track, metadata_type, content_fixture, monkeypatch): | ||||
|         monkeypatch.setattr(youtube_tools, "go_pafy", lambda track, meta_tags: content_fixture) | ||||
|     def test_match_metadata_with_fallback( | ||||
|         self, track, metadata_type, content_fixture, monkeypatch | ||||
|     ): | ||||
|         monkeypatch.setattr( | ||||
|             youtube_tools, "go_pafy", lambda track, meta_tags: content_fixture | ||||
|         ) | ||||
|         const.args.no_fallback_metadata = False | ||||
|         self.match_metadata(track, metadata_type) | ||||
|  | ||||
|     @pytest.mark.parametrize("track, metadata_type", MATCH_METADATA_NO_METADATA_TEST_TABLE) | ||||
|     def test_match_metadata_with_no_metadata(self, track, metadata_type, content_fixture, monkeypatch): | ||||
|         monkeypatch.setattr(youtube_tools, "go_pafy", lambda track, meta_tags: content_fixture) | ||||
|     @pytest.mark.parametrize( | ||||
|         "track, metadata_type", MATCH_METADATA_NO_METADATA_TEST_TABLE | ||||
|     ) | ||||
|     def test_match_metadata_with_no_metadata( | ||||
|         self, track, metadata_type, content_fixture, monkeypatch | ||||
|     ): | ||||
|         monkeypatch.setattr( | ||||
|             youtube_tools, "go_pafy", lambda track, meta_tags: content_fixture | ||||
|         ) | ||||
|         const.args.no_metadata = True | ||||
|         self.match_metadata(track, metadata_type) | ||||
|  | ||||
| @@ -185,7 +201,11 @@ def test_check_exists(metadata_fixture, filename_fixture, tmpdir): | ||||
|  | ||||
|  | ||||
| def test_generate_m3u(tmpdir, monkeypatch): | ||||
|     monkeypatch.setattr(youtube_tools.GenerateYouTubeURL, "_fetch_response", loader.monkeypatch_youtube_search_page) | ||||
|     monkeypatch.setattr( | ||||
|         youtube_tools.GenerateYouTubeURL, | ||||
|         "_fetch_response", | ||||
|         loader.monkeypatch_youtube_search_page, | ||||
|     ) | ||||
|     expect_m3u = ( | ||||
|         "#EXTM3U\n\n" | ||||
|         "#EXTINF:208,Janji - Heroes Tonight (feat. Johnning) [NCS Release]\n" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user