mirror of
https://github.com/KevinMidboe/spotify-downloader.git
synced 2025-10-29 18:00:15 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ca4317944 | ||
|
|
f4cd70b603 | ||
|
|
b6c5c88550 | ||
|
|
9f1f361dcb | ||
|
|
fd74adb42f | ||
|
|
b808265c38 | ||
|
|
21a1f1a150 | ||
|
|
951ae02e08 | ||
|
|
dfd48f75ce | ||
|
|
bb385a3bfd | ||
|
|
a9477c7873 | ||
|
|
c225e5821b | ||
|
|
d61309b0ce | ||
|
|
5b2a073033 | ||
|
|
f17e5f58d8 | ||
|
|
d3668f55bb | ||
|
|
6ca136f039 | ||
|
|
e2a136d885 | ||
|
|
d10f3e9df0 | ||
|
|
46eb2e3e32 |
12
CHANGES.md
12
CHANGES.md
@@ -14,6 +14,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|||||||
### Changed
|
### Changed
|
||||||
-
|
-
|
||||||
|
|
||||||
|
## [1.2.2] - 2019-06-03
|
||||||
|
### Fixed
|
||||||
|
- Patch bug in Pafy to prefer secure HTTPS ([@ritiek](https://github.com/ritiek)) (#558)
|
||||||
|
|
||||||
|
## [1.2.1] - 2019-04-28
|
||||||
|
### Fixed
|
||||||
|
- Patch bug in Pafy when fetching audiostreams with latest youtube-dl ([@ritiek](https://github.com/ritiek)) (#539)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Removed duplicate debug log entry from `internals.trim_song` ([@ritiek](https://github.com/ritiek)) (#519)
|
||||||
|
- Fix YAMLLoadWarning ([@cyberboysumanjay](https://github.com/cyberboysumanjay)) (#517)
|
||||||
|
|
||||||
## [1.2.0] - 2019-03-01
|
## [1.2.0] - 2019-03-01
|
||||||
### Added
|
### Added
|
||||||
- `--write-to` parameter for setting custom file to write Spotify track URLs to ([@ritiek](https://github.com/ritiek)) (#507)
|
- `--write-to` parameter for setting custom file to write Spotify track URLs to ([@ritiek](https://github.com/ritiek)) (#507)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ If you still need to use Python 2 - check out the (outdated)
|
|||||||
spotify-downloader works with all major distributions and even on low-powered devices such as a Raspberry Pi.
|
spotify-downloader works with all major distributions and even on low-powered devices such as a Raspberry Pi.
|
||||||
|
|
||||||
spotify-downloader can be installed via pip with:
|
spotify-downloader can be installed via pip with:
|
||||||
```
|
```console
|
||||||
$ pip3 install spotdl
|
$ pip3 install spotdl
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ page for detailed OS-specific instructions to get it and other dependencies it r
|
|||||||
|
|
||||||
For the most basic usage, downloading tracks is as easy as
|
For the most basic usage, downloading tracks is as easy as
|
||||||
|
|
||||||
```
|
```console
|
||||||
$ spotdl --song https://open.spotify.com/track/2DGa7iaidT5s0qnINlwMjJ
|
$ spotdl --song https://open.spotify.com/track/2DGa7iaidT5s0qnINlwMjJ
|
||||||
$ spotdl --song "ncs - spectre"
|
$ spotdl --song "ncs - spectre"
|
||||||
```
|
```
|
||||||
@@ -49,7 +49,7 @@ $ spotdl --song "ncs - spectre"
|
|||||||
For downloading playlist and albums, you need to first load all the tracks into text file and then pass
|
For downloading playlist and albums, you need to first load all the tracks into text file and then pass
|
||||||
this text file to `--list` argument. Here is how you would do it for a playlist
|
this text file to `--list` argument. Here is how you would do it for a playlist
|
||||||
|
|
||||||
```
|
```console
|
||||||
$ spotdl --playlist https://open.spotify.com/user/nocopyrightsounds/playlist/7sZbq8QGyMnhKPcLJvCUFD
|
$ spotdl --playlist https://open.spotify.com/user/nocopyrightsounds/playlist/7sZbq8QGyMnhKPcLJvCUFD
|
||||||
INFO: Writing 62 tracks to ncs-releases.txt
|
INFO: Writing 62 tracks to ncs-releases.txt
|
||||||
$ spotdl --list ncs-releases.txt
|
$ spotdl --list ncs-releases.txt
|
||||||
@@ -73,7 +73,7 @@ Check out [CONTRIBUTING.md](CONTRIBUTING.md) for more info.
|
|||||||
|
|
||||||
## Running Tests
|
## Running Tests
|
||||||
|
|
||||||
```
|
```console
|
||||||
$ python3 -m pytest test
|
$ python3 -m pytest test
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
__version__ = "1.2.0"
|
__version__ = "1.2.2"
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ def merge(default, config):
|
|||||||
def get_config(config_file):
|
def get_config(config_file):
|
||||||
try:
|
try:
|
||||||
with open(config_file, "r") as ymlfile:
|
with open(config_file, "r") as ymlfile:
|
||||||
cfg = yaml.load(ymlfile)
|
cfg = yaml.safe_load(ymlfile)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
log.info("Writing default configuration to {0}:".format(config_file))
|
log.info("Writing default configuration to {0}:".format(config_file))
|
||||||
with open(config_file, "w") as ymlfile:
|
with open(config_file, "w") as ymlfile:
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ def input_link(links):
|
|||||||
|
|
||||||
def trim_song(tracks_file):
|
def trim_song(tracks_file):
|
||||||
""" Remove the first song from file. """
|
""" Remove the first song from file. """
|
||||||
log.debug("Removing downloaded song from tracks file")
|
|
||||||
with open(tracks_file, "r") as file_in:
|
with open(tracks_file, "r") as file_in:
|
||||||
data = file_in.read().splitlines(True)
|
data = file_in.read().splitlines(True)
|
||||||
with open(tracks_file, "w") as file_out:
|
with open(tracks_file, "w") as file_out:
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from pafy import backend_youtube_dl
|
||||||
import pafy
|
import pafy
|
||||||
|
|
||||||
from spotdl import internals
|
from spotdl import internals
|
||||||
@@ -20,12 +21,35 @@ def _getbestthumb(self):
|
|||||||
if self._content_available(url):
|
if self._content_available(url):
|
||||||
return url
|
return url
|
||||||
|
|
||||||
|
def _process_streams(self):
|
||||||
|
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']
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
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)
|
||||||
|
|
||||||
def patch_pafy():
|
|
||||||
pafy.backend_shared.BasePafy._bestthumb = None
|
class PatchPafy:
|
||||||
pafy.backend_shared.BasePafy._content_available = _content_available
|
"""
|
||||||
pafy.backend_shared.BasePafy.getbestthumb = _getbestthumb
|
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
|
||||||
|
pafy.backend_shared.BasePafy._content_available = _content_available
|
||||||
|
pafy.backend_shared.BasePafy.getbestthumb = _getbestthumb
|
||||||
|
|
||||||
|
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._process_streams = _process_streams
|
||||||
|
|
||||||
|
def patch_insecure_streams(self):
|
||||||
|
# https://github.com/mps-youtube/pafy/pull/235
|
||||||
|
pafy.g.def_ydl_opts["prefer_insecure"] = False
|
||||||
|
|||||||
@@ -18,7 +18,10 @@ 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
|
||||||
patcher.patch_pafy()
|
pafy_patcher = patcher.PatchPafy()
|
||||||
|
pafy_patcher.patch_getbestthumb()
|
||||||
|
pafy_patcher.patch_process_streams()
|
||||||
|
pafy_patcher.patch_insecure_streams()
|
||||||
|
|
||||||
|
|
||||||
def set_api_key():
|
def set_api_key():
|
||||||
|
|||||||
@@ -176,6 +176,7 @@ class TestFFmpeg:
|
|||||||
|
|
||||||
|
|
||||||
class TestAvconv:
|
class TestAvconv:
|
||||||
|
@pytest.mark.skip(reason="avconv is no longer provided with FFmpeg")
|
||||||
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 0 -i {0}.m4a -ab 192k {0}.mp3 -y".format(
|
expect_command = "avconv -loglevel 0 -i {0}.m4a -ab 192k {0}.mp3 -y".format(
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import pafy
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
patcher.patch_pafy()
|
pafy_patcher = patcher.PatchPafy()
|
||||||
|
pafy_patcher.patch_getbestthumb()
|
||||||
|
|
||||||
class TestPafyContentAvailable:
|
class TestPafyContentAvailable:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ def test_write_playlist(tmpdir):
|
|||||||
assert tracks == expect_tracks
|
assert tracks == expect_tracks
|
||||||
|
|
||||||
|
|
||||||
# XXX: Mock this test off if it fails in future
|
# XXX: Monkeypatch these tests if they fail in future
|
||||||
class TestFetchAlbum:
|
class TestFetchAlbum:
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def album_fixture(self):
|
def album_fixture(self):
|
||||||
@@ -131,7 +131,7 @@ class TestFetchAlbum:
|
|||||||
assert album_fixture["tracks"]["total"] == 15
|
assert album_fixture["tracks"]["total"] == 15
|
||||||
|
|
||||||
|
|
||||||
# XXX: Mock this test off if it fails in future
|
# XXX: Monkeypatch these tests if they fail in future
|
||||||
class TestFetchAlbumsFromArtist:
|
class TestFetchAlbumsFromArtist:
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def albums_from_artist_fixture(self):
|
def albums_from_artist_fixture(self):
|
||||||
@@ -141,7 +141,7 @@ class TestFetchAlbumsFromArtist:
|
|||||||
return albums
|
return albums
|
||||||
|
|
||||||
def test_len(self, albums_from_artist_fixture):
|
def test_len(self, albums_from_artist_fixture):
|
||||||
assert len(albums_from_artist_fixture) == 52
|
assert len(albums_from_artist_fixture) == 53
|
||||||
|
|
||||||
def test_zeroth_album_name(self, albums_from_artist_fixture):
|
def test_zeroth_album_name(self, albums_from_artist_fixture):
|
||||||
assert albums_from_artist_fixture[0]["name"] == "Revolution Radio"
|
assert albums_from_artist_fixture[0]["name"] == "Revolution Radio"
|
||||||
|
|||||||
Reference in New Issue
Block a user