mirror of
https://github.com/KevinMidboe/spotify-downloader.git
synced 2025-10-29 18:00:15 +00:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ddb4b01897 | ||
|
|
1d401d26c1 | ||
|
|
cfa9f78ce4 | ||
|
|
01c6c11a1d | ||
|
|
eb1be87039 | ||
|
|
925521aa3b | ||
|
|
1d2b43a5f9 | ||
|
|
542201091d | ||
|
|
a182fe5eb3 | ||
|
|
3dac0125a9 | ||
|
|
fbf930fe43 | ||
|
|
b72eb773f3 | ||
|
|
8944dec8e0 | ||
|
|
76906cfdbc | ||
|
|
a18f888e97 | ||
|
|
6c07267312 | ||
|
|
f078875f0e | ||
|
|
31cd1c5856 | ||
|
|
54d3336aa2 | ||
|
|
94500e31a3 | ||
|
|
bf6e6fb0c5 | ||
|
|
67ae7d5c4c |
19
CHANGES.md
19
CHANGES.md
@@ -4,7 +4,26 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
### Added
|
||||||
|
-
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
-
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
-
|
||||||
|
|
||||||
|
## [1.1.2] - 2019-02-10
|
||||||
|
### Changed
|
||||||
|
- Fetch all artist albums by default instead of only fetching the "album" type ([@ritiek](https://github.com/ritiek)) (#493)
|
||||||
|
- Option `-f` (`--folder`) is used when exporting text files using `-p` (`--playlist`) for playlists or `-b` (`--album`) for albums ([@Silverfeelin](https://github.com/Silverfeelin)) (#476)
|
||||||
|
- Use first artist from album object for album artist ([@tillhainbach](https://github.com/tillhainbach))
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fix renaming files when encoder is not found ([@ritiek](https://github.com/ritiek)) (#475)
|
||||||
|
- Add missing `import time` ([@ifduyue](https://github.com/ifduyue)) (#465)
|
||||||
|
|
||||||
## [1.1.1] - 2019-01-03
|
## [1.1.1] - 2019-01-03
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
__version__ = "1.1.1"
|
__version__ = "1.1.2"
|
||||||
|
|||||||
@@ -83,7 +83,12 @@ class Converter:
|
|||||||
os.rename(self.output_file, self.input_file)
|
os.rename(self.output_file, self.input_file)
|
||||||
|
|
||||||
log.debug(command)
|
log.debug(command)
|
||||||
|
try:
|
||||||
code = subprocess.call(command)
|
code = subprocess.call(command)
|
||||||
|
except FileNotFoundError:
|
||||||
|
if self.rename_to_temp:
|
||||||
|
os.rename(self.input_file, self.output_file)
|
||||||
|
raise
|
||||||
|
|
||||||
if self.delete_original:
|
if self.delete_original:
|
||||||
log.debug('Removing original file: "{}"'.format(self.input_file))
|
log.debug('Removing original file: "{}"'.format(self.input_file))
|
||||||
@@ -134,7 +139,12 @@ class Converter:
|
|||||||
os.rename(self.output_file, self.input_file)
|
os.rename(self.output_file, self.input_file)
|
||||||
|
|
||||||
log.debug(command)
|
log.debug(command)
|
||||||
|
try:
|
||||||
code = subprocess.call(command)
|
code = subprocess.call(command)
|
||||||
|
except FileNotFoundError:
|
||||||
|
if self.rename_to_temp:
|
||||||
|
os.rename(self.input_file, self.output_file)
|
||||||
|
raise
|
||||||
|
|
||||||
if self.delete_original:
|
if self.delete_original:
|
||||||
log.debug('Removing original file: "{}"'.format(self.input_file))
|
log.debug('Removing original file: "{}"'.format(self.input_file))
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import spotipy
|
import spotipy
|
||||||
import urllib
|
import urllib
|
||||||
import os
|
import os
|
||||||
|
import time
|
||||||
from logzero import logger as log
|
from logzero import logger as log
|
||||||
|
|
||||||
from spotdl import const
|
from spotdl import const
|
||||||
@@ -130,6 +131,8 @@ class Downloader:
|
|||||||
trim_silence=const.args.trim_silence,
|
trim_silence=const.args.trim_silence,
|
||||||
)
|
)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
|
encoder = "avconv" if const.args.avconv else "ffmpeg"
|
||||||
|
log.warning("Could not find {0}, skip encoding".format(encoder))
|
||||||
output_song = self.unconverted_filename(songname)
|
output_song = self.unconverted_filename(songname)
|
||||||
|
|
||||||
if not const.args.no_metadata and self.meta_tags is not None:
|
if not const.args.no_metadata and self.meta_tags is not None:
|
||||||
@@ -168,8 +171,6 @@ class Downloader:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def unconverted_filename(songname):
|
def unconverted_filename(songname):
|
||||||
encoder = "avconv" if const.args.avconv else "ffmpeg"
|
|
||||||
log.warning("Could not find {0}, skipping conversion".format(encoder))
|
|
||||||
const.args.output_ext = const.args.input_ext
|
const.args.output_ext = const.args.input_ext
|
||||||
output_song = songname + const.args.output_ext
|
output_song = songname + const.args.output_ext
|
||||||
return output_song
|
return output_song
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import argparse
|
|||||||
import mimetypes
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
import spotdl
|
||||||
from spotdl import internals
|
from spotdl import internals
|
||||||
|
|
||||||
|
|
||||||
@@ -120,9 +121,6 @@ def get_arguments(raw_args=None, to_group=True, to_merge=True):
|
|||||||
"--username",
|
"--username",
|
||||||
help="load tracks from user's playlist into <playlist_name>.txt",
|
help="load tracks from user's playlist into <playlist_name>.txt",
|
||||||
)
|
)
|
||||||
group.add_argument(
|
|
||||||
"-V", "--version", help="show version and exit", action="store_true"
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--write-m3u",
|
"--write-m3u",
|
||||||
@@ -257,6 +255,12 @@ def get_arguments(raw_args=None, to_group=True, to_merge=True):
|
|||||||
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"
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-V",
|
||||||
|
"--version",
|
||||||
|
action="version",
|
||||||
|
version="%(prog)s {}".format(spotdl.__version__),
|
||||||
|
)
|
||||||
|
|
||||||
parsed = parser.parse_args(raw_args)
|
parsed = parser.parse_args(raw_args)
|
||||||
|
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ class EmbedMetadata:
|
|||||||
def _embed_basic_metadata(self, audiofile, preset=TAG_PRESET):
|
def _embed_basic_metadata(self, audiofile, preset=TAG_PRESET):
|
||||||
meta_tags = self.meta_tags
|
meta_tags = self.meta_tags
|
||||||
audiofile[preset["artist"]] = meta_tags["artists"][0]["name"]
|
audiofile[preset["artist"]] = meta_tags["artists"][0]["name"]
|
||||||
audiofile[preset["albumartist"]] = meta_tags["artists"][0]["name"]
|
audiofile[preset["albumartist"]] = meta_tags["album"]["artists"][0]["name"]
|
||||||
audiofile[preset["album"]] = meta_tags["album"]["name"]
|
audiofile[preset["album"]] = meta_tags["album"]["name"]
|
||||||
audiofile[preset["title"]] = meta_tags["name"]
|
audiofile[preset["title"]] = meta_tags["name"]
|
||||||
audiofile[preset["date"]] = meta_tags["release_date"]
|
audiofile[preset["date"]] = meta_tags["release_date"]
|
||||||
|
|||||||
@@ -49,10 +49,6 @@ def match_args():
|
|||||||
def main():
|
def main():
|
||||||
const.args = handle.get_arguments()
|
const.args = handle.get_arguments()
|
||||||
|
|
||||||
if const.args.version:
|
|
||||||
print("spotdl {version}".format(version=__version__))
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
internals.filter_path(const.args.folder)
|
internals.filter_path(const.args.folder)
|
||||||
youtube_tools.set_api_key()
|
youtube_tools.set_api_key()
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ from titlecase import titlecase
|
|||||||
from logzero import logger as log
|
from logzero import logger as log
|
||||||
import pprint
|
import pprint
|
||||||
import sys
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
from spotdl import const
|
||||||
from spotdl import internals
|
from spotdl import internals
|
||||||
|
|
||||||
|
|
||||||
@@ -146,7 +148,8 @@ def write_playlist(playlist_url, text_file=None):
|
|||||||
tracks = playlist["tracks"]
|
tracks = playlist["tracks"]
|
||||||
if not text_file:
|
if not text_file:
|
||||||
text_file = u"{0}.txt".format(slugify(playlist["name"], ok="-_()[]{}"))
|
text_file = u"{0}.txt".format(slugify(playlist["name"], ok="-_()[]{}"))
|
||||||
return write_tracks(tracks, text_file)
|
filepath = os.path.join(const.args.folder if const.args.folder else "", text_file)
|
||||||
|
return write_tracks(tracks, filepath)
|
||||||
|
|
||||||
|
|
||||||
def fetch_album(album):
|
def fetch_album(album):
|
||||||
@@ -155,13 +158,13 @@ def fetch_album(album):
|
|||||||
return album
|
return album
|
||||||
|
|
||||||
|
|
||||||
def fetch_albums_from_artist(artist_url, album_type="album"):
|
def fetch_albums_from_artist(artist_url, album_type=None):
|
||||||
"""
|
"""
|
||||||
This funcction returns all the albums from a give artist_url using the US
|
This funcction returns all the albums from a give artist_url using the US
|
||||||
market
|
market
|
||||||
:param artist_url - spotify artist url
|
:param artist_url - spotify artist url
|
||||||
:param album_type - the type of album to fetch (ex: single) the default is
|
:param album_type - the type of album to fetch (ex: single) the default is
|
||||||
a standard album
|
all albums
|
||||||
:param return - the album from the artist
|
:param return - the album from the artist
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -192,7 +195,7 @@ def write_all_albums_from_artist(artist_url, text_file=None):
|
|||||||
album_base_url = "https://open.spotify.com/album/"
|
album_base_url = "https://open.spotify.com/album/"
|
||||||
|
|
||||||
# fetching all default albums
|
# fetching all default albums
|
||||||
albums = fetch_albums_from_artist(artist_url)
|
albums = fetch_albums_from_artist(artist_url, album_type=None)
|
||||||
|
|
||||||
# if no file if given, the default save file is in the current working
|
# if no file if given, the default save file is in the current working
|
||||||
# directory with the name of the artist
|
# directory with the name of the artist
|
||||||
@@ -204,20 +207,14 @@ def write_all_albums_from_artist(artist_url, text_file=None):
|
|||||||
log.info("Fetching album: " + album["name"])
|
log.info("Fetching album: " + album["name"])
|
||||||
write_album(album_base_url + album["id"], text_file=text_file)
|
write_album(album_base_url + album["id"], text_file=text_file)
|
||||||
|
|
||||||
# fetching all single albums
|
|
||||||
singles = fetch_albums_from_artist(artist_url, album_type="single")
|
|
||||||
|
|
||||||
for single in singles:
|
|
||||||
log.info("Fetching single: " + single["name"])
|
|
||||||
write_album(album_base_url + single["id"], text_file=text_file)
|
|
||||||
|
|
||||||
|
|
||||||
def write_album(album_url, text_file=None):
|
def write_album(album_url, text_file=None):
|
||||||
album = fetch_album(album_url)
|
album = fetch_album(album_url)
|
||||||
tracks = spotify.album_tracks(album["id"])
|
tracks = spotify.album_tracks(album["id"])
|
||||||
if not text_file:
|
if not text_file:
|
||||||
text_file = u"{0}.txt".format(slugify(album["name"], ok="-_()[]{}"))
|
text_file = u"{0}.txt".format(slugify(album["name"], ok="-_()[]{}"))
|
||||||
return write_tracks(tracks, text_file)
|
filepath = os.path.join(const.args.folder if const.args.folder else "", text_file)
|
||||||
|
return write_tracks(tracks, filepath)
|
||||||
|
|
||||||
|
|
||||||
def write_tracks(tracks, text_file):
|
def write_tracks(tracks, text_file):
|
||||||
|
|||||||
@@ -113,7 +113,8 @@ 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) == 18
|
# TODO: Mock this test (failed in #493)
|
||||||
|
assert len(albums_from_artist_fixture) == 52
|
||||||
|
|
||||||
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"
|
||||||
@@ -128,11 +129,9 @@ class TestFetchAlbumsFromArtist:
|
|||||||
assert albums_from_artist_fixture[0]["total_tracks"] == 12
|
assert albums_from_artist_fixture[0]["total_tracks"] == 12
|
||||||
|
|
||||||
|
|
||||||
# XXX: Mock this test off if it fails in future
|
# TODO: Mock this test (failed in #493)
|
||||||
def test_write_all_albums_from_artist(tmpdir):
|
def test_write_all_albums_from_artist(tmpdir):
|
||||||
# current number of tracks on spotify since as of 10/10/2018
|
expect_tracks = 282
|
||||||
# in US market only
|
|
||||||
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(
|
spotify_tools.write_all_albums_from_artist(
|
||||||
"https://open.spotify.com/artist/4dpARuHxo51G3z768sgnrY", text_file
|
"https://open.spotify.com/artist/4dpARuHxo51G3z768sgnrY", text_file
|
||||||
|
|||||||
Reference in New Issue
Block a user