Skip to content

Commit

Permalink
Release v4.0.0.rc.5
Browse files Browse the repository at this point in the history
  • Loading branch information
xnetcat authored Oct 10, 2022
2 parents c159840 + 07fadad commit a393cc4
Show file tree
Hide file tree
Showing 42 changed files with 52,704 additions and 57,799 deletions.
8 changes: 7 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,16 @@ RUN apk add --no-cache \
# Install poetry and update pip/wheel
RUN pip install --upgrade pip poetry wheel

# Copy requirements files
COPY poetry.lock pyproject.toml /

# Install spotdl requirements
RUN poetry install

# Add source code files to WORKDIR
ADD . .

# Install requirements
# Install spotdl itself
RUN poetry install

# Create music directory
Expand Down
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
version: '3'
version: "3"
services:
spotdl:
image: "spotDL/spotify-downloader"
image: "spotdl/spotify-downloader"
volumes:
- .:/music
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "spotdl"
version = "4.0.0-rc.4"
version = "4.0.0-rc.5"
description = "Download your Spotify playlists and songs along with album art and metadata"
license = "MIT"
authors = ["spotDL Team <spotdladmins@googlegroups.com>"]
Expand All @@ -26,7 +26,7 @@ classifiers = [
]

[tool.poetry.dependencies]
python = ">=3.7,<3.11"
python = ">=3.7,<=3.11"

spotipy = "^2.19.0"
ytmusicapi = "^0.22.0"
Expand Down
2 changes: 1 addition & 1 deletion spotdl/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
Version module for spotdl.
"""

__version__ = "4.0.0-rc.4"
__version__ = "4.0.0-rc.5"
5 changes: 3 additions & 2 deletions spotdl/console/entry_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,12 +171,13 @@ def entry_point():
bitrate=settings["bitrate"],
ffmpeg_args=settings["ffmpeg_args"],
output_format=settings["format"],
save_file=settings["save_file"],
threads=settings["threads"],
output=settings["output"],
save_file=settings["save_file"],
overwrite=settings["overwrite"],
search_query=settings["search_query"],
cookie_file=settings["cookie_file"],
filter_results=settings["filter_results"],
search_query=settings["search_query"],
log_level=settings["log_level"],
simple_tui=settings["simple_tui"],
restrict=settings["restrict"],
Expand Down
6 changes: 5 additions & 1 deletion spotdl/console/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,11 @@ def process_file(file: Path):
f"Fetching lyrics for {song.display_name}"
)
lyrics = downloader.search_lyrics(song)
song.lyrics = lyrics
if lyrics:
song.lyrics = lyrics
downloader.progress_handler.log(
f"No lyrics found for song: {song.display_name}"
)

# Apply metadata to the song
embed_metadata(file, song, file.suffix.split(".")[-1])
Expand Down
34 changes: 12 additions & 22 deletions spotdl/download/downloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from yt_dlp.postprocessor.sponsorblock import SponsorBlockPP
from yt_dlp.postprocessor.modify_chapters import ModifyChaptersPP

from spotdl.types import Song, SongList
from spotdl.types import Song
from spotdl.utils.ffmpeg import FFmpegError, convert, get_ffmpeg_path
from spotdl.utils.metadata import embed_metadata, MetadataError, get_song_metadata
from spotdl.utils.formatter import create_file_name, restrict_filename
Expand All @@ -26,6 +26,7 @@
from spotdl.providers.audio import YouTube, YouTubeMusic
from spotdl.download.progress_handler import NAME_TO_LEVEL, ProgressHandler
from spotdl.utils.config import get_errors_path, get_temp_path
from spotdl.utils.search import reinit_song


AUDIO_PROVIDERS: Dict[str, Type[AudioProvider]] = {
Expand Down Expand Up @@ -80,10 +81,10 @@ def __init__(
search_query: Optional[str] = None,
log_level: str = "INFO",
simple_tui: bool = False,
loop: Optional[asyncio.AbstractEventLoop] = None,
restrict: bool = False,
print_errors: bool = False,
sponsor_block: bool = False,
loop: Optional[asyncio.AbstractEventLoop] = None,
):
"""
Initialize the Downloader class.
Expand Down Expand Up @@ -299,15 +300,15 @@ def search(self, song: Song) -> Tuple[str, AudioProvider]:

raise LookupError(f"No results found for song: {song.display_name}")

def search_lyrics(self, song: Song) -> str:
def search_lyrics(self, song: Song) -> Optional[str]:
"""
Search for lyrics using all available providers.
### Arguments
- song: The song to search for.
### Returns
- lyrics if successful.
- lyrics if successful else None.
"""

for lyrics_provider in self.lyrics_providers:
Expand All @@ -323,7 +324,7 @@ def search_lyrics(self, song: Song) -> str:
f"for {song.display_name}"
)

raise LookupError(f"No lyrics found for song: {song.display_name}")
return None

def search_and_download(self, song: Song) -> Tuple[Song, Optional[Path]]:
"""
Expand All @@ -344,30 +345,19 @@ def search_and_download(self, song: Song) -> Tuple[Song, Optional[Path]]:
# If it's None extract the current metadata
# And reinitialize the song object
if song.name is None and song.url:
data = song.json
new_data = Song.from_url(data["url"]).json
data.update((k, v) for k, v in new_data.items() if v is not None)

if data.get("song_list"):
# Reinitialize the correct song list object
song_list: Type[SongList] = song.song_list.__class__(
**data["song_list"]
)
data["song_list"] = song_list
data["list_position"] = song_list.urls.index(song.url)

# Reinitialize the song object
song = Song(**data)
song = reinit_song(song)

# Find song lyrics and add them to the song object
try:
song.lyrics = self.search_lyrics(song)
except LookupError:
lyrics = self.search_lyrics(song)
if song.lyrics is None:
self.progress_handler.debug(
f"No lyrics found for {song.display_name}, "
"lyrics providers: "
f"{', '.join([lprovider.name for lprovider in self.lyrics_providers])}"
)
else:
song.lyrics = lyrics
self.progress_handler.log(f"No lyrics found for song: {song.display_name}")

# Create the output file path
output_file = create_file_name(song, self.output, self.output_format)
Expand Down
4 changes: 4 additions & 0 deletions spotdl/utils/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ def parse_main_options(parser: _ArgumentGroup):
parser.add_argument(
"--dont-filter-results",
dest="filter_results",
action="store_const",
const=False,
help="Disable filtering results.",
)

Expand All @@ -193,6 +195,8 @@ def parse_spotify_options(parser: _ArgumentGroup):
# Add login argument
parser.add_argument(
"--user-auth",
action="store_const",
const=True,
help="Login to Spotify using OAuth.",
)

Expand Down
82 changes: 32 additions & 50 deletions spotdl/utils/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,59 +68,14 @@ def parse_query(
- List of song objects
"""

urls: List[str] = []
songs: List[Song] = []
for request in query:
if (
"youtube.com/watch?v=" in request
or "youtu.be/" in request
and "open.spotify.com" in request
and "track" in request
and "|" in request
):
split_urls = request.split("|")
if (
len(split_urls) <= 1
or "youtube" not in split_urls[0]
and "youtu.be" not in split_urls[0]
or "spotify" not in split_urls[1]
):
raise QueryError(
"Incorrect format used, please use YouTubeURL|SpotifyURL"
)

songs.append(
Song.from_dict(
{
**Song.from_url(split_urls[1]).json,
"download_url": split_urls[0],
}
)
)
elif "open.spotify.com" in request and "track" in request:
urls.append(request)
elif "open.spotify.com" in request and "playlist" in request:
urls.extend(Playlist.get_urls(request))
elif "open.spotify.com" in request and "album" in request:
urls.extend(Album.get_urls(request))
elif "open.spotify.com" in request and "artist" in request:
for album_url in Artist.get_albums(request):
urls.extend(Album.get_urls(album_url))
elif request == "saved":
urls.extend(Saved.get_urls("saved"))
elif request.endswith(".spotdl"):
with open(request, "r", encoding="utf-8") as m3u_file:
for track in json.load(m3u_file):
# Append to songs
songs.append(Song.from_dict(track))
else:
songs.append(Song.from_search_term(request))
songs: List[Song] = get_simple_songs(query)

results = []
with concurrent.futures.ThreadPoolExecutor(max_workers=threads) as executor:
for song in executor.map(Song.from_url, urls):
songs.append(song)
for song in executor.map(reinit_song, songs):
results.append(song)

return songs
return results


def create_empty_song(
Expand Down Expand Up @@ -263,3 +218,30 @@ def get_simple_songs(
) # type: ignore

return songs


def reinit_song(song: Song) -> Song:
"""
Update song object with new data
from Spotify
### Arguments
- song: Song object
### Returns
- Updated song object
"""

data = song.json
new_data = Song.from_url(data["url"]).json
data.update((k, v) for k, v in new_data.items() if v is not None)

if data.get("song_list"):
# Reinitialize the correct song list object
if song.song_list:
song_list = song.song_list.__class__(**data["song_list"])
data["song_list"] = song_list
data["list_position"] = song_list.urls.index(song.url)

# return reinitialized song object
return Song(**data)
Loading

0 comments on commit a393cc4

Please sign in to comment.