Merge branch 'master' into feat/keep-trackid-as-songname

This commit is contained in:
Linus Groh
2019-09-07 11:49:10 +01:00
committed by GitHub
18 changed files with 168 additions and 86 deletions

View File

@@ -1,6 +1,4 @@
dist: xenial
language: python language: python
sudo: required
python: python:
- "3.4" - "3.4"
- "3.5" - "3.5"

View File

@@ -7,10 +7,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## [Unreleased] ## [Unreleased]
### Added ### Added
- Added `--no-remove-original-file` ([@NightMachinary](https://github.com/NightMachinary)) (#580) - 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) - Added `track_id` key for `--file-format` parameter ([@kadaliao](https://github.com/kadaliao)) (#568)
### Fixed ### Fixed
- - Generate list error --write-m3u ([@arthurlutz](https://github.com/arthurlutz)) (#559)
### Changed ### Changed
- Fetch lyrics from Genius and fallback to LyricWikia if not found ([@ritiek](https://github.com/ritiek)) (#585) - Fetch lyrics from Genius and fallback to LyricWikia if not found ([@ritiek](https://github.com/ritiek)) (#585)

View File

@@ -10,7 +10,7 @@ setup(
name="spotdl", name="spotdl",
# Tests are included automatically: # Tests are included automatically:
# https://docs.python.org/3.6/distutils/sourcedist.html#specifying-the-files-to-distribute # 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__, version=spotdl.__version__,
install_requires=[ install_requires=[
"pathlib >= 1.0.1", "pathlib >= 1.0.1",

View File

@@ -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. """ """ Do the audio format conversion. """
if avconv and trim_silence: if avconv and trim_silence:
raise ValueError("avconv does not support 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: else:
return 0 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: if avconv:
exit_code, command = convert.with_avconv() exit_code, command = convert.with_avconv()
else: else:
@@ -97,7 +106,9 @@ class Converter:
return code, command return code, command
def with_ffmpeg(self, trim_silence=False): 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: if not log.level == 10:
ffmpeg_pre += "-hide_banner -nostats -v panic " ffmpeg_pre += "-hide_banner -nostats -v panic "

View File

@@ -96,6 +96,7 @@ class Downloader:
self.raw_song = raw_song self.raw_song = raw_song
self.number = number self.number = number
self.content, self.meta_tags = youtube_tools.match_video_and_metadata(raw_song) 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): def download_single(self):
""" Logic behind downloading a song. """ """ Logic behind downloading a song. """
@@ -158,7 +159,10 @@ class Downloader:
def refine_songname(self, songname): def refine_songname(self, songname):
if self.meta_tags is not None: if self.meta_tags is not None:
refined_songname = internals.format_string( 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( log.debug(
'Refining songname from "{0}" to "{1}"'.format( 'Refining songname from "{0}" to "{1}"'.format(

View File

@@ -37,7 +37,7 @@ default_conf = {
"write-successful": None, "write-successful": None,
"log-level": "INFO", "log-level": "INFO",
"spotify_client_id": "4fe3fecfe5334023a1472516cc99d805", "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", "-sci",
"--spotify-client-id", "--spotify-client-id",
default=config["spotify_client_id"], default=config["spotify_client_id"],
help=argparse.SUPPRESS help=argparse.SUPPRESS,
) )
parser.add_argument( parser.add_argument(
"-scs", "-scs",
"--spotify-client-secret", "--spotify-client-secret",
default=config["spotify_client_secret"], default=config["spotify_client_secret"],
help=argparse.SUPPRESS help=argparse.SUPPRESS,
) )
parser.add_argument( parser.add_argument(
"-c", "--config", default=None, help="path to custom config.yml file" "-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: if parsed.avconv and parsed.trim_silence:
parser.error("--trim-silence can only be used with FFmpeg") parser.error("--trim-silence can only be used with FFmpeg")
if parsed.write_to and not (parsed.playlist \ if parsed.write_to and not (
or parsed.album \ parsed.playlist or parsed.album or parsed.all_albums or parsed.username
or parsed.all_albums \ ):
or parsed.username): parser.error(
parser.error("--write-to can only be used with --playlist, --album, --all-albums, or --username") "--write-to can only be used with --playlist, --album, --all-albums, or --username"
)
parsed.log_level = log_leveller(parsed.log_level) parsed.log_level = log_leveller(parsed.log_level)

View File

@@ -1,8 +1,10 @@
from logzero import logger as log from logzero import logger as log
import os import os
import sys import sys
import math
import urllib.request import urllib.request
from spotdl import const from spotdl import const
try: try:
@@ -74,7 +76,9 @@ def is_youtube(raw_song):
return status 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. """ """ Generate a string of the format '[artist] - [song]' for the given spotify song. """
format_tags = dict(formats) format_tags = dict(formats)
format_tags[0] = tags["name"] 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) k: sanitize_title(str(v), ok="'-_()[]{}") if slugification else str(v)
for k, v in format_tags.items() 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: for x in formats:
format_tag = "{" + formats[x] + "}" 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]) string_format = string_format.replace(format_tag, format_tags_sanitized[x])
if const.args.no_spaces and not force_spaces: if const.args.no_spaces and not force_spaces:

View File

@@ -18,7 +18,6 @@ class TestGenius:
assert track.base_url == "https://genius.com" assert track.base_url == "https://genius.com"
def test_get_lyrics(self, track, monkeypatch): def test_get_lyrics(self, track, monkeypatch):
def mocked_urlopen(url, timeout=None): def mocked_urlopen(url, timeout=None):
class DummyHTTPResponse: class DummyHTTPResponse:
def read(self): def read(self):
@@ -30,7 +29,6 @@ class TestGenius:
assert track.get_lyrics() == "amazing lyrics!" assert track.get_lyrics() == "amazing lyrics!"
def test_lyrics_not_found_error(self, track, monkeypatch): def test_lyrics_not_found_error(self, track, monkeypatch):
def mocked_urlopen(url, timeout=None): def mocked_urlopen(url, timeout=None):
raise urllib.request.HTTPError("", "", "", "", "") raise urllib.request.HTTPError("", "", "", "", "")

View File

@@ -15,17 +15,21 @@ class TestLyricWikia:
# `LyricWikia` class uses the 3rd party method `lyricwikia.get_lyrics` # `LyricWikia` class uses the 3rd party method `lyricwikia.get_lyrics`
# internally and there is no need to test a 3rd party library as they # internally and there is no need to test a 3rd party library as they
# have their own implementation of tests. # 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") track = LyricWikia("Lyricwikia", "Lyricwikia")
assert track.get_lyrics() == "awesome lyrics!" assert track.get_lyrics() == "awesome lyrics!"
def test_lyrics_not_found_error(self, monkeypatch): def test_lyrics_not_found_error(self, monkeypatch):
def lyricwikia_lyrics_not_found(msg): def lyricwikia_lyrics_not_found(msg):
raise lyricwikia.LyricsNotFound(msg) raise lyricwikia.LyricsNotFound(msg)
# Wrap `lyricwikia.LyricsNotFound` with `exceptions.LyricsNotFound` error. # 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") track = LyricWikia("Lyricwikia", "Lyricwikia")
with pytest.raises(exceptions.LyricsNotFound): with pytest.raises(exceptions.LyricsNotFound):
track.get_lyrics() track.get_lyrics()

View File

@@ -80,7 +80,9 @@ class EmbedMetadata:
audiofile["TYER"] = TYER(encoding=3, text=meta_tags["year"]) audiofile["TYER"] = TYER(encoding=3, text=meta_tags["year"])
if meta_tags["publisher"]: if meta_tags["publisher"]:
audiofile["TPUB"] = TPUB(encoding=3, text=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"]: if meta_tags["lyrics"]:
audiofile["USLT"] = USLT( audiofile["USLT"] = USLT(
encoding=3, desc=u"Lyrics", text=meta_tags["lyrics"] encoding=3, desc=u"Lyrics", text=meta_tags["lyrics"]

View File

@@ -11,24 +11,30 @@ def _getbestthumb(self):
part_url = "https://i.ytimg.com/vi/%s/" % self.videoid part_url = "https://i.ytimg.com/vi/%s/" % self.videoid
# Thumbnail resolution sorted in descending order # Thumbnail resolution sorted in descending order
thumbs = ("maxresdefault.jpg", thumbs = (
"sddefault.jpg", "maxresdefault.jpg",
"hqdefault.jpg", "sddefault.jpg",
"mqdefault.jpg", "hqdefault.jpg",
"default.jpg") "mqdefault.jpg",
"default.jpg",
)
for thumb in thumbs: for thumb in thumbs:
url = part_url + thumb url = part_url + thumb
if self._content_available(url): if self._content_available(url):
return url return url
def _process_streams(self): 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: 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: except KeyError:
pass pass
return backend_youtube_dl.YtdlPafy._old_process_streams(self) return backend_youtube_dl.YtdlPafy._old_process_streams(self)
@classmethod @classmethod
def _content_available(cls, url): def _content_available(cls, url):
return internals.content_available(url) return internals.content_available(url)
@@ -39,6 +45,7 @@ class PatchPafy:
These patches have not been released by pafy on PyPI yet but These patches have not been released by pafy on PyPI yet but
are useful to us. are useful to us.
""" """
def patch_getbestthumb(self): def patch_getbestthumb(self):
# https://github.com/mps-youtube/pafy/pull/211 # https://github.com/mps-youtube/pafy/pull/211
pafy.backend_shared.BasePafy._bestthumb = None pafy.backend_shared.BasePafy._bestthumb = None
@@ -47,7 +54,9 @@ class PatchPafy:
def patch_process_streams(self): def patch_process_streams(self):
# https://github.com/mps-youtube/pafy/pull/230 # 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 backend_youtube_dl.YtdlPafy._process_streams = _process_streams
def patch_insecure_streams(self): def patch_insecure_streams(self):

View File

@@ -28,8 +28,9 @@ def match_args():
track_dl.download_single() track_dl.download_single()
elif const.args.list: elif const.args.list:
if const.args.write_m3u: if const.args.write_m3u:
youtube_tools.generate_m3u(track_file=const.args.list, youtube_tools.generate_m3u(
text_file=const.args.write_to) track_file=const.args.list
)
else: else:
list_dl = downloader.ListDownloader( list_dl = downloader.ListDownloader(
tracks_file=const.args.list, tracks_file=const.args.list,
@@ -38,17 +39,21 @@ def match_args():
) )
list_dl.download_list() list_dl.download_list()
elif const.args.playlist: elif const.args.playlist:
spotify_tools.write_playlist(playlist_url=const.args.playlist, spotify_tools.write_playlist(
text_file=const.args.write_to) playlist_url=const.args.playlist, text_file=const.args.write_to
)
elif const.args.album: elif const.args.album:
spotify_tools.write_album(album_url=const.args.album, spotify_tools.write_album(
text_file=const.args.write_to) album_url=const.args.album, text_file=const.args.write_to
)
elif const.args.all_albums: elif const.args.all_albums:
spotify_tools.write_all_albums_from_artist(artist_url=const.args.all_albums, spotify_tools.write_all_albums_from_artist(
text_file=const.args.write_to) artist_url=const.args.all_albums, text_file=const.args.write_to
)
elif const.args.username: elif const.args.username:
spotify_tools.write_user_playlist(username=const.args.username, spotify_tools.write_user_playlist(
text_file=const.args.write_to) username=const.args.username, text_file=const.args.write_to
)
def main(): def main():

View File

@@ -17,8 +17,6 @@ from spotdl.lyrics.exceptions import LyricsNotFound
spotify = None spotify = None
def generate_token(): def generate_token():
""" Generate the token. """ """ Generate the token. """
credentials = oauth2.SpotifyClientCredentials( credentials = oauth2.SpotifyClientCredentials(
@@ -39,6 +37,7 @@ def must_be_authorized(func, spotify=spotify):
token = generate_token() token = generate_token()
spotify = spotipy.Spotify(auth=token) spotify = spotipy.Spotify(auth=token)
return func(*args, **kwargs) return func(*args, **kwargs)
return wrapper return wrapper

View File

@@ -18,6 +18,7 @@ pafy.g.opener.addheaders.append(("Range", "bytes=0-"))
# More info: https://github.com/mps-youtube/pafy/pull/211 # More info: https://github.com/mps-youtube/pafy/pull/211
if pafy.__version__ <= "0.5.4": if pafy.__version__ <= "0.5.4":
from spotdl import patcher from spotdl import patcher
pafy_patcher = patcher.PatchPafy() pafy_patcher = patcher.PatchPafy()
pafy_patcher.patch_getbestthumb() pafy_patcher.patch_getbestthumb()
pafy_patcher.patch_process_streams() pafy_patcher.patch_process_streams()
@@ -52,10 +53,13 @@ def match_video_and_metadata(track):
""" Get and match track data from YouTube and Spotify. """ """ Get and match track data from YouTube and Spotify. """
meta_tags = None meta_tags = None
def fallback_metadata(meta_tags): def fallback_metadata(meta_tags):
fallback_metadata_info = "Track not found on Spotify, falling back on YouTube metadata" fallback_metadata_info = (
skip_fallback_metadata_warning = "Fallback condition not met, shall not embed metadata" "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 meta_tags is None:
if const.args.no_fallback_metadata: if const.args.no_fallback_metadata:
log.warning(skip_fallback_metadata_warning) log.warning(skip_fallback_metadata_warning)
@@ -64,7 +68,6 @@ def match_video_and_metadata(track):
meta_tags = generate_metadata(content) meta_tags = generate_metadata(content)
return meta_tags return meta_tags
if internals.is_youtube(track): if internals.is_youtube(track):
log.debug("Input song is a YouTube URL") log.debug("Input song is a YouTube URL")
content = go_pafy(track, meta_tags=None) content = go_pafy(track, meta_tags=None)
@@ -95,25 +98,29 @@ def match_video_and_metadata(track):
def generate_metadata(content): def generate_metadata(content):
""" Fetch a song's metadata from YouTube. """ """ Fetch a song's metadata from YouTube. """
meta_tags = {"spotify_metadata": False, meta_tags = {
"name": content.title, "spotify_metadata": False,
"artists": [{"name": content.author}], "name": content.title,
"duration": content.length, "artists": [{"name": content.author}],
"external_urls": {"youtube": content.watchv_url}, "duration": content.length,
"album": {"images" : [{"url": content.getbestthumb()}], "external_urls": {"youtube": content.watchv_url},
"artists": [{"name": None}],"name": None}, "album": {
"year": content.published.split("-")[0], "images": [{"url": content.getbestthumb()}],
"release_date": content.published.split(" ")[0], "artists": [{"name": None}],
"type": "track", "name": None,
"disc_number": 1, },
"track_number": 1, "year": content.published.split("-")[0],
"total_tracks": 1, "release_date": content.published.split(" ")[0],
"publisher": None, "type": "track",
"external_ids": {"isrc": None}, "disc_number": 1,
"lyrics": None, "track_number": 1,
"copyright": None, "total_tracks": 1,
"genre": None, "publisher": None,
} "external_ids": {"isrc": None},
"lyrics": None,
"copyright": None,
"genre": None,
}
return meta_tags return meta_tags

View File

@@ -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. # 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" GIST_URL = "https://gist.githubusercontent.com/ritiek/e731338e9810e31c2f00f13c249a45f5/raw/c11a27f3b5d11a8d082976f1cdd237bd605ec2c2/search_results.html"
def monkeypatch_youtube_search_page(*args, **kwargs): def monkeypatch_youtube_search_page(*args, **kwargs):
fake_urlopen = urllib.request.urlopen(GIST_URL) fake_urlopen = urllib.request.urlopen(GIST_URL)
return fake_urlopen return fake_urlopen

View File

@@ -101,16 +101,28 @@ class TestDownload:
def test_m4a(self, monkeypatch, filename_fixture): def test_m4a(self, monkeypatch, filename_fixture):
expect_download = True expect_download = True
monkeypatch.setattr("pafy.backend_shared.BaseStream.download", self.blank_audio_generator) monkeypatch.setattr(
monkeypatch.setattr("pafy.backend_youtube_dl.YtdlStream.download", self.blank_audio_generator) "pafy.backend_shared.BaseStream.download", self.blank_audio_generator
download = youtube_tools.download_song(filename_fixture + ".m4a", pytest.content_fixture) )
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 assert download == expect_download
def test_webm(self, monkeypatch, filename_fixture): def test_webm(self, monkeypatch, filename_fixture):
expect_download = True expect_download = True
monkeypatch.setattr("pafy.backend_shared.BaseStream.download", self.blank_audio_generator) monkeypatch.setattr(
monkeypatch.setattr("pafy.backend_youtube_dl.YtdlStream.download", self.blank_audio_generator) "pafy.backend_shared.BaseStream.download", self.blank_audio_generator
download = youtube_tools.download_song(filename_fixture + ".webm", pytest.content_fixture) )
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 assert download == expect_download

View File

@@ -6,6 +6,7 @@ import pytest
pafy_patcher = patcher.PatchPafy() pafy_patcher = patcher.PatchPafy()
pafy_patcher.patch_getbestthumb() pafy_patcher.patch_getbestthumb()
class TestPafyContentAvailable: class TestPafyContentAvailable:
pass pass
@@ -30,7 +31,6 @@ class TestMethodCalls:
thumbnail = patcher._getbestthumb(content_fixture) thumbnail = patcher._getbestthumb(content_fixture)
assert thumbnail == "https://i.ytimg.com/vi/3nQNiWdeH2Q/sddefault.jpg" assert thumbnail == "https://i.ytimg.com/vi/3nQNiWdeH2Q/sddefault.jpg"
def test_pafy_content_available(self): def test_pafy_content_available(self):
TestPafyContentAvailable._content_available = patcher._content_available TestPafyContentAvailable._content_available = patcher._content_available
assert TestPafyContentAvailable()._content_available("https://youtube.com/") assert TestPafyContentAvailable()._content_available("https://youtube.com/")

View File

@@ -104,19 +104,19 @@ def content_fixture(metadata_fixture):
MATCH_METADATA_NO_FALLBACK_TEST_TABLE = [ MATCH_METADATA_NO_FALLBACK_TEST_TABLE = [
("https://open.spotify.com/track/5nWduGwBGBn1PSqYTJUDbS", True), ("https://open.spotify.com/track/5nWduGwBGBn1PSqYTJUDbS", True),
("http://youtube.com/watch?v=3nQNiWdeH2Q", None), ("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 = [ MATCH_METADATA_FALLBACK_TEST_TABLE = [
("https://open.spotify.com/track/5nWduGwBGBn1PSqYTJUDbS", True), ("https://open.spotify.com/track/5nWduGwBGBn1PSqYTJUDbS", True),
("http://youtube.com/watch?v=3nQNiWdeH2Q", False), ("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 = [ MATCH_METADATA_NO_METADATA_TEST_TABLE = [
("https://open.spotify.com/track/5nWduGwBGBn1PSqYTJUDbS", None), ("https://open.spotify.com/track/5nWduGwBGBn1PSqYTJUDbS", None),
("http://youtube.com/watch?v=3nQNiWdeH2Q", 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: else:
assert metadata["spotify_metadata"] == metadata_type assert metadata["spotify_metadata"] == metadata_type
@pytest.mark.parametrize("track, metadata_type", MATCH_METADATA_NO_FALLBACK_TEST_TABLE) @pytest.mark.parametrize(
def test_match_metadata_with_no_fallback(self, track, metadata_type, content_fixture, monkeypatch): "track, metadata_type", MATCH_METADATA_NO_FALLBACK_TEST_TABLE
monkeypatch.setattr(youtube_tools, "go_pafy", lambda track, meta_tags: content_fixture) )
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 const.args.no_fallback_metadata = True
self.match_metadata(track, metadata_type) self.match_metadata(track, metadata_type)
@pytest.mark.parametrize("track, metadata_type", MATCH_METADATA_FALLBACK_TEST_TABLE) @pytest.mark.parametrize("track, metadata_type", MATCH_METADATA_FALLBACK_TEST_TABLE)
def test_match_metadata_with_fallback(self, track, metadata_type, content_fixture, monkeypatch): def test_match_metadata_with_fallback(
monkeypatch.setattr(youtube_tools, "go_pafy", lambda track, meta_tags: content_fixture) 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 const.args.no_fallback_metadata = False
self.match_metadata(track, metadata_type) self.match_metadata(track, metadata_type)
@pytest.mark.parametrize("track, metadata_type", MATCH_METADATA_NO_METADATA_TEST_TABLE) @pytest.mark.parametrize(
def test_match_metadata_with_no_metadata(self, track, metadata_type, content_fixture, monkeypatch): "track, metadata_type", MATCH_METADATA_NO_METADATA_TEST_TABLE
monkeypatch.setattr(youtube_tools, "go_pafy", lambda track, meta_tags: content_fixture) )
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 const.args.no_metadata = True
self.match_metadata(track, metadata_type) 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): 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 = ( expect_m3u = (
"#EXTM3U\n\n" "#EXTM3U\n\n"
"#EXTINF:208,Janji - Heroes Tonight (feat. Johnning) [NCS Release]\n" "#EXTINF:208,Janji - Heroes Tonight (feat. Johnning) [NCS Release]\n"