mirror of
				https://github.com/KevinMidboe/spotify-downloader.git
				synced 2025-10-29 18:00:15 +00:00 
			
		
		
		
	Merge branch 'release-v1.1.1'
This commit is contained in:
		@@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## [Unreleased]
 | 
					## [Unreleased]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [1.1.1] - 2018-12-29
 | 
				
			||||||
### Added
 | 
					### Added
 | 
				
			||||||
- Output informative message in case of no result found in YouTube search ([@Amit-L](https://github.com/Amit-L)) (#452)
 | 
					- Output informative message in case of no result found in YouTube search ([@Amit-L](https://github.com/Amit-L)) (#452)
 | 
				
			||||||
- Ability to pass multiple tracks with `-s` option ([@ritiek](https://github.com/ritiek)) (#442)
 | 
					- Ability to pass multiple tracks with `-s` option ([@ritiek](https://github.com/ritiek)) (#442)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								setup.py
									
									
									
									
									
								
							@@ -1,6 +1,6 @@
 | 
				
			|||||||
from setuptools import setup
 | 
					from setuptools import setup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
with open("README.md", "r") as f:
 | 
					with open("README.md", "r", encoding="utf-8") as f:
 | 
				
			||||||
    long_description = f.read()
 | 
					    long_description = f.read()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import spotdl
 | 
					import spotdl
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1 +1 @@
 | 
				
			|||||||
__version__ = "1.1.0"
 | 
					__version__ = "1.1.1"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,13 +2,16 @@ import logzero
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
_log_format = "%(color)s%(levelname)s:%(end_color)s %(message)s"
 | 
					_log_format = "%(color)s%(levelname)s:%(end_color)s %(message)s"
 | 
				
			||||||
_formatter = logzero.LogFormatter(fmt=_log_format)
 | 
					_formatter = logzero.LogFormatter(fmt=_log_format)
 | 
				
			||||||
 | 
					_log_level = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Set up a temporary logger with default log level so that
 | 
					# Set up a temporary logger with default log level so that
 | 
				
			||||||
# it can be used before log level argument is determined
 | 
					# it can be used before log level argument is determined
 | 
				
			||||||
logzero.setup_default_logger(formatter=_formatter)
 | 
					logzero.setup_default_logger(formatter=_formatter, level=_log_level)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# options
 | 
					# Options
 | 
				
			||||||
args = None
 | 
					# Initialize an empty object which can be assigned attributes
 | 
				
			||||||
 | 
					# (useful when using spotdl as a library)
 | 
				
			||||||
 | 
					args = type('', (), {})()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Apple has specific tags - see mutagen docs -
 | 
					# Apple has specific tags - see mutagen docs -
 | 
				
			||||||
# http://mutagen.readthedocs.io/en/latest/api/mp4.html
 | 
					# http://mutagen.readthedocs.io/en/latest/api/mp4.html
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,8 +28,7 @@ class CheckExists:
 | 
				
			|||||||
        for song in songs:
 | 
					        for song in songs:
 | 
				
			||||||
            # check if a song with the same name is already present in the given folder
 | 
					            # check if a song with the same name is already present in the given folder
 | 
				
			||||||
            if self._match_filenames(song):
 | 
					            if self._match_filenames(song):
 | 
				
			||||||
                if internals.is_spotify(raw_song) and \
 | 
					                if internals.is_spotify(raw_song) and not self._has_metadata(song):
 | 
				
			||||||
                        not self._has_metadata(song):
 | 
					 | 
				
			||||||
                    return False
 | 
					                    return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                log.warning('"{}" already exists'.format(song))
 | 
					                log.warning('"{}" already exists'.format(song))
 | 
				
			||||||
@@ -53,9 +52,7 @@ class CheckExists:
 | 
				
			|||||||
        already_tagged = metadata.compare(
 | 
					        already_tagged = metadata.compare(
 | 
				
			||||||
            os.path.join(const.args.folder, song), self.meta_tags
 | 
					            os.path.join(const.args.folder, song), self.meta_tags
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        log.debug(
 | 
					        log.debug("Checking if it is already tagged correctly? {}", already_tagged)
 | 
				
			||||||
            "Checking if it is already tagged correctly? {}", already_tagged
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        if not already_tagged:
 | 
					        if not already_tagged:
 | 
				
			||||||
            os.remove(os.path.join(const.args.folder, song))
 | 
					            os.remove(os.path.join(const.args.folder, song))
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
@@ -64,8 +61,7 @@ class CheckExists:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def _prompt_song(self, song):
 | 
					    def _prompt_song(self, song):
 | 
				
			||||||
        log.info(
 | 
					        log.info(
 | 
				
			||||||
            '"{}" has already been downloaded. '
 | 
					            '"{}" has already been downloaded. ' "Re-download? (y/N): ".format(song)
 | 
				
			||||||
            "Re-download? (y/N): ".format(song)
 | 
					 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        prompt = input("> ")
 | 
					        prompt = input("> ")
 | 
				
			||||||
        if prompt.lower() == "y":
 | 
					        if prompt.lower() == "y":
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -99,10 +99,7 @@ def get_arguments(raw_args=None, to_group=True, to_merge=True):
 | 
				
			|||||||
        group = parser.add_mutually_exclusive_group(required=True)
 | 
					        group = parser.add_mutually_exclusive_group(required=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        group.add_argument(
 | 
					        group.add_argument(
 | 
				
			||||||
            "-s",
 | 
					            "-s", "--song", nargs="+", help="download track by spotify link or name"
 | 
				
			||||||
            "--song",
 | 
					 | 
				
			||||||
            nargs='+',
 | 
					 | 
				
			||||||
            help="download track by spotify link or name"
 | 
					 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        group.add_argument("-l", "--list", help="download tracks from a file")
 | 
					        group.add_argument("-l", "--list", help="download tracks from a file")
 | 
				
			||||||
        group.add_argument(
 | 
					        group.add_argument(
 | 
				
			||||||
@@ -116,7 +113,7 @@ def get_arguments(raw_args=None, to_group=True, to_merge=True):
 | 
				
			|||||||
        group.add_argument(
 | 
					        group.add_argument(
 | 
				
			||||||
            "-ab",
 | 
					            "-ab",
 | 
				
			||||||
            "--all-albums",
 | 
					            "--all-albums",
 | 
				
			||||||
            help="load all tracks from artist URL into <artist_name>.txt"
 | 
					            help="load all tracks from artist URL into <artist_name>.txt",
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        group.add_argument(
 | 
					        group.add_argument(
 | 
				
			||||||
            "-u",
 | 
					            "-u",
 | 
				
			||||||
@@ -128,10 +125,10 @@ def get_arguments(raw_args=None, to_group=True, to_merge=True):
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    parser.add_argument(
 | 
					    parser.add_argument(
 | 
				
			||||||
        '--write-m3u',
 | 
					        "--write-m3u",
 | 
				
			||||||
        help="generate an .m3u playlist file with youtube links given "
 | 
					        help="generate an .m3u playlist file with youtube links given "
 | 
				
			||||||
             "a text file containing tracks",
 | 
					        "a text file containing tracks",
 | 
				
			||||||
        action='store_true'
 | 
					        action="store_true",
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    parser.add_argument(
 | 
					    parser.add_argument(
 | 
				
			||||||
        "-m",
 | 
					        "-m",
 | 
				
			||||||
@@ -266,12 +263,19 @@ def get_arguments(raw_args=None, to_group=True, to_merge=True):
 | 
				
			|||||||
    if parsed.config is not None and to_merge:
 | 
					    if parsed.config is not None and to_merge:
 | 
				
			||||||
        parsed = override_config(parsed.config, parser)
 | 
					        parsed = override_config(parsed.config, parser)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if to_group and parsed.list and \
 | 
					    if (
 | 
				
			||||||
            not mimetypes.MimeTypes().guess_type(parsed.list)[0] == "text/plain":
 | 
					        to_group
 | 
				
			||||||
        parser.error("{0} is not of a valid argument to --list, argument must be plain text file".format(parsed.list))
 | 
					        and parsed.list
 | 
				
			||||||
 | 
					        and not mimetypes.MimeTypes().guess_type(parsed.list)[0] == "text/plain"
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
 | 
					        parser.error(
 | 
				
			||||||
 | 
					            "{0} is not of a valid argument to --list, argument must be plain text file".format(
 | 
				
			||||||
 | 
					                parsed.list
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if parsed.write_m3u and not parsed.list:
 | 
					    if parsed.write_m3u and not parsed.list:
 | 
				
			||||||
        parser.error('--write-m3u can only be used with --list')
 | 
					        parser.error("--write-m3u can only be used with --list")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,6 +27,7 @@ def refresh_token():
 | 
				
			|||||||
    new_token = generate_token()
 | 
					    new_token = generate_token()
 | 
				
			||||||
    spotify = spotipy.Spotify(auth=new_token)
 | 
					    spotify = spotipy.Spotify(auth=new_token)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# token is mandatory when using Spotify's API
 | 
					# token is mandatory when using Spotify's API
 | 
				
			||||||
# https://developer.spotify.com/news-stories/2017/01/27/removing-unauthenticated-calls-to-the-web-api/
 | 
					# https://developer.spotify.com/news-stories/2017/01/27/removing-unauthenticated-calls-to-the-web-api/
 | 
				
			||||||
_token = generate_token()
 | 
					_token = generate_token()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -53,7 +53,7 @@ def match_video_and_metadata(track, force_pafy=True):
 | 
				
			|||||||
        # Let it generate metadata, youtube doesn't know spotify slang
 | 
					        # Let it generate metadata, youtube doesn't know spotify slang
 | 
				
			||||||
        if not const.args.no_metadata or internals.is_spotify(track):
 | 
					        if not const.args.no_metadata or internals.is_spotify(track):
 | 
				
			||||||
            meta_tags = spotify_tools.generate_metadata(track)
 | 
					            meta_tags = spotify_tools.generate_metadata(track)
 | 
				
			||||||
        
 | 
					
 | 
				
			||||||
        if force_pafy:
 | 
					        if force_pafy:
 | 
				
			||||||
            content = go_pafy(track, meta_tags)
 | 
					            content = go_pafy(track, meta_tags)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,6 @@ import pytest
 | 
				
			|||||||
def load_defaults():
 | 
					def load_defaults():
 | 
				
			||||||
    const.args = handle.get_arguments(raw_args="", to_group=False, to_merge=False)
 | 
					    const.args = handle.get_arguments(raw_args="", to_group=False, to_merge=False)
 | 
				
			||||||
    const.args.overwrite = "skip"
 | 
					    const.args.overwrite = "skip"
 | 
				
			||||||
    const.args.log_level = 10
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    spotdl.args = const.args
 | 
					    spotdl.args = const.args
 | 
				
			||||||
    spotdl.log = const.logzero.setup_logger(
 | 
					    spotdl.log = const.logzero.setup_logger(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -60,13 +60,21 @@ def monkeypatch_youtube_search_page(*args, **kwargs):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_youtube_url(metadata_fixture, monkeypatch):
 | 
					def test_youtube_url(metadata_fixture, monkeypatch):
 | 
				
			||||||
    monkeypatch.setattr(youtube_tools.GenerateYouTubeURL, "_fetch_response", monkeypatch_youtube_search_page)
 | 
					    monkeypatch.setattr(
 | 
				
			||||||
 | 
					        youtube_tools.GenerateYouTubeURL,
 | 
				
			||||||
 | 
					        "_fetch_response",
 | 
				
			||||||
 | 
					        monkeypatch_youtube_search_page,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    url = youtube_tools.generate_youtube_url(SPOTIFY_TRACK_URL, metadata_fixture)
 | 
					    url = youtube_tools.generate_youtube_url(SPOTIFY_TRACK_URL, metadata_fixture)
 | 
				
			||||||
    assert url == EXPECTED_YOUTUBE_URL
 | 
					    assert url == EXPECTED_YOUTUBE_URL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_youtube_title(metadata_fixture, monkeypatch):
 | 
					def test_youtube_title(metadata_fixture, monkeypatch):
 | 
				
			||||||
    monkeypatch.setattr(youtube_tools.GenerateYouTubeURL, "_fetch_response", monkeypatch_youtube_search_page)
 | 
					    monkeypatch.setattr(
 | 
				
			||||||
 | 
					        youtube_tools.GenerateYouTubeURL,
 | 
				
			||||||
 | 
					        "_fetch_response",
 | 
				
			||||||
 | 
					        monkeypatch_youtube_search_page,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    content = youtube_tools.go_pafy(SPOTIFY_TRACK_URL, metadata_fixture)
 | 
					    content = youtube_tools.go_pafy(SPOTIFY_TRACK_URL, metadata_fixture)
 | 
				
			||||||
    pytest.content_fixture = content
 | 
					    pytest.content_fixture = content
 | 
				
			||||||
    title = youtube_tools.get_youtube_title(content)
 | 
					    title = youtube_tools.get_youtube_title(content)
 | 
				
			||||||
@@ -99,60 +107,78 @@ 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(
 | 
				
			||||||
        download = youtube_tools.download_song(filename_fixture + ".m4a", pytest.content_fixture)
 | 
					            "pafy.backend_shared.BaseStream.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(
 | 
				
			||||||
        download = youtube_tools.download_song(filename_fixture + ".webm", pytest.content_fixture)
 | 
					            "pafy.backend_shared.BaseStream.download", self.blank_audio_generator
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        download = youtube_tools.download_song(
 | 
				
			||||||
 | 
					            filename_fixture + ".webm", pytest.content_fixture
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        assert download == expect_download
 | 
					        assert download == expect_download
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestFFmpeg:
 | 
					class TestFFmpeg:
 | 
				
			||||||
    def test_convert_from_webm_to_mp3(self, filename_fixture, monkeypatch):
 | 
					    def test_convert_from_webm_to_mp3(self, filename_fixture, monkeypatch):
 | 
				
			||||||
 | 
					        expect_command = "ffmpeg -y -hide_banner -nostats -v panic -i {0}.webm -codec:a libmp3lame -ar 44100 -b:a 192k -vn {0}.mp3".format(
 | 
				
			||||||
 | 
					            os.path.join(const.args.folder, filename_fixture)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        monkeypatch.setattr("os.remove", lambda x: None)
 | 
					        monkeypatch.setattr("os.remove", lambda x: None)
 | 
				
			||||||
        expect_command = "ffmpeg -y -i {0}.webm -codec:a libmp3lame -ar 44100 -b:a 192k -vn {0}.mp3".format(os.path.join(const.args.folder, filename_fixture))
 | 
					 | 
				
			||||||
        _, command = convert.song(
 | 
					        _, command = convert.song(
 | 
				
			||||||
            filename_fixture + ".webm", filename_fixture + ".mp3", const.args.folder
 | 
					            filename_fixture + ".webm", filename_fixture + ".mp3", const.args.folder
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        assert ' '.join(command) == expect_command
 | 
					        assert " ".join(command) == expect_command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_convert_from_webm_to_m4a(self, filename_fixture, monkeypatch):
 | 
					    def test_convert_from_webm_to_m4a(self, filename_fixture, monkeypatch):
 | 
				
			||||||
 | 
					        expect_command = "ffmpeg -y -hide_banner -nostats -v panic -i {0}.webm -cutoff 20000 -codec:a aac -ar 44100 -b:a 192k -vn {0}.m4a".format(
 | 
				
			||||||
 | 
					            os.path.join(const.args.folder, filename_fixture)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        monkeypatch.setattr("os.remove", lambda x: None)
 | 
					        monkeypatch.setattr("os.remove", lambda x: None)
 | 
				
			||||||
        expect_command = "ffmpeg -y -i {0}.webm -cutoff 20000 -codec:a aac -ar 44100 -b:a 192k -vn {0}.m4a".format(os.path.join(const.args.folder, filename_fixture))
 | 
					 | 
				
			||||||
        _, command = convert.song(
 | 
					        _, command = convert.song(
 | 
				
			||||||
            filename_fixture + ".webm", filename_fixture + ".m4a", const.args.folder
 | 
					            filename_fixture + ".webm", filename_fixture + ".m4a", const.args.folder
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        assert ' '.join(command) == expect_command
 | 
					        assert " ".join(command) == expect_command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_convert_from_m4a_to_mp3(self, filename_fixture, monkeypatch):
 | 
					    def test_convert_from_m4a_to_mp3(self, filename_fixture, monkeypatch):
 | 
				
			||||||
 | 
					        expect_command = "ffmpeg -y -hide_banner -nostats -v panic -i {0}.m4a -codec:v copy -codec:a libmp3lame -ar 44100 -b:a 192k -vn {0}.mp3".format(
 | 
				
			||||||
 | 
					            os.path.join(const.args.folder, filename_fixture)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        monkeypatch.setattr("os.remove", lambda x: None)
 | 
					        monkeypatch.setattr("os.remove", lambda x: None)
 | 
				
			||||||
        expect_command = "ffmpeg -y -i {0}.m4a -codec:v copy -codec:a libmp3lame -ar 44100 -b:a 192k -vn {0}.mp3".format(os.path.join(const.args.folder, filename_fixture))
 | 
					 | 
				
			||||||
        _, command = convert.song(
 | 
					        _, command = convert.song(
 | 
				
			||||||
            filename_fixture + ".m4a", filename_fixture + ".mp3", const.args.folder
 | 
					            filename_fixture + ".m4a", filename_fixture + ".mp3", const.args.folder
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        assert ' '.join(command) == expect_command
 | 
					        assert " ".join(command) == expect_command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_convert_from_m4a_to_webm(self, filename_fixture, monkeypatch):
 | 
					    def test_convert_from_m4a_to_webm(self, filename_fixture, monkeypatch):
 | 
				
			||||||
 | 
					        expect_command = "ffmpeg -y -hide_banner -nostats -v panic -i {0}.m4a -codec:a libopus -vbr on -b:a 192k -vn {0}.webm".format(
 | 
				
			||||||
 | 
					            os.path.join(const.args.folder, filename_fixture)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        monkeypatch.setattr("os.remove", lambda x: None)
 | 
					        monkeypatch.setattr("os.remove", lambda x: None)
 | 
				
			||||||
        expect_command = "ffmpeg -y -i {0}.m4a -codec:a libopus -vbr on -b:a 192k -vn {0}.webm".format(os.path.join(const.args.folder, filename_fixture))
 | 
					 | 
				
			||||||
        _, command = convert.song(
 | 
					        _, command = convert.song(
 | 
				
			||||||
            filename_fixture + ".m4a", filename_fixture + ".webm", const.args.folder
 | 
					            filename_fixture + ".m4a", filename_fixture + ".webm", const.args.folder
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        assert ' '.join(command) == expect_command
 | 
					        assert " ".join(command) == expect_command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_convert_from_m4a_to_flac(self, filename_fixture, monkeypatch):
 | 
					    def test_convert_from_m4a_to_flac(self, filename_fixture, monkeypatch):
 | 
				
			||||||
 | 
					        expect_command = "ffmpeg -y -hide_banner -nostats -v panic -i {0}.m4a -codec:a flac -ar 44100 -b:a 192k -vn {0}.flac".format(
 | 
				
			||||||
 | 
					            os.path.join(const.args.folder, filename_fixture)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        monkeypatch.setattr("os.remove", lambda x: None)
 | 
					        monkeypatch.setattr("os.remove", lambda x: None)
 | 
				
			||||||
        expect_command = "ffmpeg -y -i {0}.m4a -codec:a flac -ar 44100 -b:a 192k -vn {0}.flac".format(os.path.join(const.args.folder, filename_fixture))
 | 
					 | 
				
			||||||
        _, command = convert.song(
 | 
					        _, command = convert.song(
 | 
				
			||||||
            filename_fixture + ".m4a", filename_fixture + ".flac", const.args.folder
 | 
					            filename_fixture + ".m4a", filename_fixture + ".flac", const.args.folder
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        assert ' '.join(command) == expect_command
 | 
					        assert " ".join(command) == expect_command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_correct_container_for_m4a(self, filename_fixture, monkeypatch):
 | 
					    def test_correct_container_for_m4a(self, filename_fixture, monkeypatch):
 | 
				
			||||||
        expect_command = "ffmpeg -y -i {0}.m4a.temp -acodec copy -b:a 192k -vn {0}.m4a".format(os.path.join(const.args.folder, filename_fixture))
 | 
					        expect_command = "ffmpeg -y -hide_banner -nostats -v panic -i {0}.m4a.temp -acodec copy -b:a 192k -vn {0}.m4a".format(os.path.join(const.args.folder, filename_fixture))
 | 
				
			||||||
        _, command = convert.song(
 | 
					        _, command = convert.song(
 | 
				
			||||||
            filename_fixture + ".m4a", filename_fixture + ".m4a", const.args.folder
 | 
					            filename_fixture + ".m4a", filename_fixture + ".m4a", const.args.folder
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
@@ -162,11 +188,15 @@ class TestFFmpeg:
 | 
				
			|||||||
class TestAvconv:
 | 
					class TestAvconv:
 | 
				
			||||||
    def test_convert_from_m4a_to_mp3(self, filename_fixture, monkeypatch):
 | 
					    def test_convert_from_m4a_to_mp3(self, filename_fixture, monkeypatch):
 | 
				
			||||||
        monkeypatch.setattr("os.remove", lambda x: None)
 | 
					        monkeypatch.setattr("os.remove", lambda x: None)
 | 
				
			||||||
        expect_command = "avconv -loglevel debug -i {0}.m4a -ab 192k {0}.mp3 -y".format(os.path.join(const.args.folder, filename_fixture))
 | 
					        expect_command = "avconv -loglevel 0 -i {0}.m4a -ab 192k {0}.mp3 -y".format(
 | 
				
			||||||
 | 
					            os.path.join(const.args.folder, filename_fixture))
 | 
				
			||||||
        _, command = convert.song(
 | 
					        _, command = convert.song(
 | 
				
			||||||
            filename_fixture + ".m4a", filename_fixture + ".mp3", const.args.folder, avconv=True
 | 
					            filename_fixture + ".m4a",
 | 
				
			||||||
 | 
					            filename_fixture + ".mp3",
 | 
				
			||||||
 | 
					            const.args.folder,
 | 
				
			||||||
 | 
					            avconv=True,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        assert ' '.join(command) == expect_command
 | 
					        assert " ".join(command) == expect_command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.fixture(scope="module")
 | 
					@pytest.fixture(scope="module")
 | 
				
			||||||
@@ -200,7 +230,9 @@ class TestEmbedMetadata:
 | 
				
			|||||||
        assert embed == expect_embed
 | 
					        assert embed == expect_embed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_check_track_exists_after_download(metadata_fixture, filename_fixture, trackpath_fixture):
 | 
					def test_check_track_exists_after_download(
 | 
				
			||||||
 | 
					    metadata_fixture, filename_fixture, trackpath_fixture
 | 
				
			||||||
 | 
					):
 | 
				
			||||||
    expect_check = True
 | 
					    expect_check = True
 | 
				
			||||||
    track_existence = downloader.CheckExists(filename_fixture, metadata_fixture)
 | 
					    track_existence = downloader.CheckExists(filename_fixture, metadata_fixture)
 | 
				
			||||||
    check = track_existence.already_exists(SPOTIFY_TRACK_URL)
 | 
					    check = track_existence.already_exists(SPOTIFY_TRACK_URL)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,13 +10,11 @@ import yaml
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
def test_error_m3u_without_list():
 | 
					def test_error_m3u_without_list():
 | 
				
			||||||
    with pytest.raises(SystemExit):
 | 
					    with pytest.raises(SystemExit):
 | 
				
			||||||
        handle.get_arguments(raw_args=('-s cool song', '--write-m3u',),
 | 
					        handle.get_arguments(raw_args=("-s cool song", "--write-m3u"), to_group=True)
 | 
				
			||||||
                             to_group=True)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_m3u_with_list():
 | 
					def test_m3u_with_list():
 | 
				
			||||||
    handle.get_arguments(raw_args=('-l cool_list.txt', '--write-m3u',),
 | 
					    handle.get_arguments(raw_args=("-l cool_list.txt", "--write-m3u"), to_group=True)
 | 
				
			||||||
                         to_group=True)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_log_str_to_int():
 | 
					def test_log_str_to_int():
 | 
				
			||||||
@@ -27,8 +25,7 @@ def test_log_str_to_int():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@pytest.fixture(scope="module")
 | 
					@pytest.fixture(scope="module")
 | 
				
			||||||
def config_path_fixture(tmpdir_factory):
 | 
					def config_path_fixture(tmpdir_factory):
 | 
				
			||||||
    config_path = os.path.join(str(tmpdir_factory.mktemp("config")),
 | 
					    config_path = os.path.join(str(tmpdir_factory.mktemp("config")), "config.yml")
 | 
				
			||||||
                               "config.yml")
 | 
					 | 
				
			||||||
    return config_path
 | 
					    return config_path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -53,9 +50,12 @@ class TestConfig:
 | 
				
			|||||||
        parser = argparse.ArgumentParser()
 | 
					        parser = argparse.ArgumentParser()
 | 
				
			||||||
        with open(config_path_fixture, "w") as config_file:
 | 
					        with open(config_path_fixture, "w") as config_file:
 | 
				
			||||||
            yaml.dump(modified_config_fixture, config_file, default_flow_style=False)
 | 
					            yaml.dump(modified_config_fixture, config_file, default_flow_style=False)
 | 
				
			||||||
        overridden_config = handle.override_config(config_path_fixture, parser, raw_args="")
 | 
					        overridden_config = handle.override_config(
 | 
				
			||||||
 | 
					            config_path_fixture, parser, raw_args=""
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        modified_values = [
 | 
					        modified_values = [
 | 
				
			||||||
            str(value) for value in modified_config_fixture["spotify-downloader"].values()
 | 
					            str(value)
 | 
				
			||||||
 | 
					            for value in modified_config_fixture["spotify-downloader"].values()
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
        overridden_config.folder = os.path.realpath(overridden_config.folder)
 | 
					        overridden_config.folder = os.path.realpath(overridden_config.folder)
 | 
				
			||||||
        overridden_values = [
 | 
					        overridden_values = [
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -86,7 +86,7 @@ FROM_SECONDS_TEST_TABLE = [
 | 
				
			|||||||
    (158, "2:38"),
 | 
					    (158, "2:38"),
 | 
				
			||||||
    (263, "4:23"),
 | 
					    (263, "4:23"),
 | 
				
			||||||
    (4562, "1:16:02"),
 | 
					    (4562, "1:16:02"),
 | 
				
			||||||
    (26762, "7:26:02")
 | 
					    (26762, "7:26:02"),
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -114,8 +114,7 @@ def test_default_music_directory():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@pytest.fixture(scope="module")
 | 
					@pytest.fixture(scope="module")
 | 
				
			||||||
def directory_fixture(tmpdir_factory):
 | 
					def directory_fixture(tmpdir_factory):
 | 
				
			||||||
    dir_path = os.path.join(str(tmpdir_factory.mktemp("tmpdir")),
 | 
					    dir_path = os.path.join(str(tmpdir_factory.mktemp("tmpdir")), "filter_this_folder")
 | 
				
			||||||
                            "filter_this_folder")
 | 
					 | 
				
			||||||
    return dir_path
 | 
					    return dir_path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,12 +36,16 @@ class TestGenerateMetadata:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_get_playlists():
 | 
					def test_get_playlists():
 | 
				
			||||||
    expect_playlist_ids = [ "34gWCK8gVeYDPKcctB6BQJ",
 | 
					    expect_playlist_ids = [
 | 
				
			||||||
                            "04wTU2c2WNQG9XE5oSLYfj",
 | 
					        "34gWCK8gVeYDPKcctB6BQJ",
 | 
				
			||||||
                            "0fWBMhGh38y0wsYWwmM9Kt" ]
 | 
					        "04wTU2c2WNQG9XE5oSLYfj",
 | 
				
			||||||
 | 
					        "0fWBMhGh38y0wsYWwmM9Kt",
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    expect_playlists = [ "https://open.spotify.com/playlist/" +  playlist_id
 | 
					    expect_playlists = [
 | 
				
			||||||
                         for playlist_id in expect_playlist_ids ]
 | 
					        "https://open.spotify.com/playlist/" + playlist_id
 | 
				
			||||||
 | 
					        for playlist_id in expect_playlist_ids
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    playlists = spotify_tools.get_playlists("uqlakumu7wslkoen46s5bulq0")
 | 
					    playlists = spotify_tools.get_playlists("uqlakumu7wslkoen46s5bulq0")
 | 
				
			||||||
    assert playlists == expect_playlists
 | 
					    assert playlists == expect_playlists
 | 
				
			||||||
@@ -60,7 +64,9 @@ def test_write_user_playlist(tmpdir, monkeypatch):
 | 
				
			|||||||
class TestFetchPlaylist:
 | 
					class TestFetchPlaylist:
 | 
				
			||||||
    @pytest.fixture(scope="module")
 | 
					    @pytest.fixture(scope="module")
 | 
				
			||||||
    def playlist_fixture(self):
 | 
					    def playlist_fixture(self):
 | 
				
			||||||
        playlist = spotify_tools.fetch_playlist("https://open.spotify.com/playlist/0fWBMhGh38y0wsYWwmM9Kt")
 | 
					        playlist = spotify_tools.fetch_playlist(
 | 
				
			||||||
 | 
					            "https://open.spotify.com/playlist/0fWBMhGh38y0wsYWwmM9Kt"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        return playlist
 | 
					        return playlist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_name(self, playlist_fixture):
 | 
					    def test_name(self, playlist_fixture):
 | 
				
			||||||
@@ -73,7 +79,9 @@ class TestFetchPlaylist:
 | 
				
			|||||||
def test_write_playlist(tmpdir):
 | 
					def test_write_playlist(tmpdir):
 | 
				
			||||||
    expect_tracks = 14
 | 
					    expect_tracks = 14
 | 
				
			||||||
    text_file = os.path.join(str(tmpdir), "test_pl.txt")
 | 
					    text_file = os.path.join(str(tmpdir), "test_pl.txt")
 | 
				
			||||||
    spotify_tools.write_playlist("https://open.spotify.com/playlist/0fWBMhGh38y0wsYWwmM9Kt", text_file)
 | 
					    spotify_tools.write_playlist(
 | 
				
			||||||
 | 
					        "https://open.spotify.com/playlist/0fWBMhGh38y0wsYWwmM9Kt", text_file
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    with open(text_file, "r") as f:
 | 
					    with open(text_file, "r") as f:
 | 
				
			||||||
        tracks = len(f.readlines())
 | 
					        tracks = len(f.readlines())
 | 
				
			||||||
    assert tracks == expect_tracks
 | 
					    assert tracks == expect_tracks
 | 
				
			||||||
@@ -83,7 +91,9 @@ def test_write_playlist(tmpdir):
 | 
				
			|||||||
class TestFetchAlbum:
 | 
					class TestFetchAlbum:
 | 
				
			||||||
    @pytest.fixture(scope="module")
 | 
					    @pytest.fixture(scope="module")
 | 
				
			||||||
    def album_fixture(self):
 | 
					    def album_fixture(self):
 | 
				
			||||||
        album = spotify_tools.fetch_album("https://open.spotify.com/album/499J8bIsEnU7DSrosFDJJg")
 | 
					        album = spotify_tools.fetch_album(
 | 
				
			||||||
 | 
					            "https://open.spotify.com/album/499J8bIsEnU7DSrosFDJJg"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        return album
 | 
					        return album
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_name(self, album_fixture):
 | 
					    def test_name(self, album_fixture):
 | 
				
			||||||
@@ -97,7 +107,9 @@ class TestFetchAlbum:
 | 
				
			|||||||
class TestFetchAlbumsFromArtist:
 | 
					class TestFetchAlbumsFromArtist:
 | 
				
			||||||
    @pytest.fixture(scope="module")
 | 
					    @pytest.fixture(scope="module")
 | 
				
			||||||
    def albums_from_artist_fixture(self):
 | 
					    def albums_from_artist_fixture(self):
 | 
				
			||||||
        albums = spotify_tools.fetch_albums_from_artist("https://open.spotify.com/artist/7oPftvlwr6VrsViSDV7fJY")
 | 
					        albums = spotify_tools.fetch_albums_from_artist(
 | 
				
			||||||
 | 
					            "https://open.spotify.com/artist/7oPftvlwr6VrsViSDV7fJY"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        return albums
 | 
					        return albums
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_len(self, albums_from_artist_fixture):
 | 
					    def test_len(self, albums_from_artist_fixture):
 | 
				
			||||||
@@ -122,7 +134,9 @@ def test_write_all_albums_from_artist(tmpdir):
 | 
				
			|||||||
    # in US market only
 | 
					    # in US market only
 | 
				
			||||||
    expect_tracks = 49
 | 
					    expect_tracks = 49
 | 
				
			||||||
    text_file = os.path.join(str(tmpdir), "test_ab.txt")
 | 
					    text_file = os.path.join(str(tmpdir), "test_ab.txt")
 | 
				
			||||||
    spotify_tools.write_all_albums_from_artist("https://open.spotify.com/artist/4dpARuHxo51G3z768sgnrY", text_file)
 | 
					    spotify_tools.write_all_albums_from_artist(
 | 
				
			||||||
 | 
					        "https://open.spotify.com/artist/4dpARuHxo51G3z768sgnrY", text_file
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    with open(text_file, "r") as f:
 | 
					    with open(text_file, "r") as f:
 | 
				
			||||||
        tracks = len(f.readlines())
 | 
					        tracks = len(f.readlines())
 | 
				
			||||||
    assert tracks == expect_tracks
 | 
					    assert tracks == expect_tracks
 | 
				
			||||||
@@ -131,7 +145,9 @@ def test_write_all_albums_from_artist(tmpdir):
 | 
				
			|||||||
def test_write_album(tmpdir):
 | 
					def test_write_album(tmpdir):
 | 
				
			||||||
    expect_tracks = 15
 | 
					    expect_tracks = 15
 | 
				
			||||||
    text_file = os.path.join(str(tmpdir), "test_al.txt")
 | 
					    text_file = os.path.join(str(tmpdir), "test_al.txt")
 | 
				
			||||||
    spotify_tools.write_album("https://open.spotify.com/album/499J8bIsEnU7DSrosFDJJg", text_file)
 | 
					    spotify_tools.write_album(
 | 
				
			||||||
 | 
					        "https://open.spotify.com/album/499J8bIsEnU7DSrosFDJJg", text_file
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    with open(text_file, "r") as f:
 | 
					    with open(text_file, "r") as f:
 | 
				
			||||||
        tracks = len(f.readlines())
 | 
					        tracks = len(f.readlines())
 | 
				
			||||||
    assert tracks == expect_tracks
 | 
					    assert tracks == expect_tracks
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -111,7 +111,9 @@ class TestYouTubeTitle:
 | 
				
			|||||||
        youtube_tools.set_api_key()
 | 
					        youtube_tools.set_api_key()
 | 
				
			||||||
        assert title_fixture == EXPECTED_TITLE
 | 
					        assert title_fixture == EXPECTED_TITLE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_download_from_list_without_youtube_api(self, metadata_fixture, content_fixture):
 | 
					    def test_download_from_list_without_youtube_api(
 | 
				
			||||||
 | 
					        self, metadata_fixture, content_fixture
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
        const.args.youtube_api_key = None
 | 
					        const.args.youtube_api_key = None
 | 
				
			||||||
        youtube_tools.set_api_key()
 | 
					        youtube_tools.set_api_key()
 | 
				
			||||||
        content_fixture = youtube_tools.go_pafy(TRACK_SEARCH, metadata_fixture)
 | 
					        content_fixture = youtube_tools.go_pafy(TRACK_SEARCH, metadata_fixture)
 | 
				
			||||||
@@ -139,11 +141,15 @@ class TestDownload:
 | 
				
			|||||||
        # content_fixture does not have any .webm audiostream
 | 
					        # content_fixture does not have any .webm audiostream
 | 
				
			||||||
        expect_download = False
 | 
					        expect_download = False
 | 
				
			||||||
        monkeypatch.setattr("pafy.backend_shared.BaseStream.download", lambda x: None)
 | 
					        monkeypatch.setattr("pafy.backend_shared.BaseStream.download", lambda x: None)
 | 
				
			||||||
        download = youtube_tools.download_song(filename_fixture + ".webm", content_fixture)
 | 
					        download = youtube_tools.download_song(
 | 
				
			||||||
 | 
					            filename_fixture + ".webm", content_fixture
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        assert download == expect_download
 | 
					        assert download == expect_download
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_other(self, content_fixture, filename_fixture, monkeypatch):
 | 
					    def test_other(self, content_fixture, filename_fixture, monkeypatch):
 | 
				
			||||||
        expect_download = False
 | 
					        expect_download = False
 | 
				
			||||||
        monkeypatch.setattr("pafy.backend_shared.BaseStream.download", lambda x: None)
 | 
					        monkeypatch.setattr("pafy.backend_shared.BaseStream.download", lambda x: None)
 | 
				
			||||||
        download = youtube_tools.download_song(filename_fixture + ".fake_extension", content_fixture)
 | 
					        download = youtube_tools.download_song(
 | 
				
			||||||
 | 
					            filename_fixture + ".fake_extension", content_fixture
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        assert download == expect_download
 | 
					        assert download == expect_download
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user