Reorganization and features to support label_playlist
First practical-scale usecase!
This commit is contained in:
@ -1,46 +1,106 @@
|
||||
# pylint: disable=missing-module-docstring, missing-function-docstring
|
||||
|
||||
from argparse import ArgumentParser
|
||||
from datetime import date, datetime, timedelta
|
||||
from typing import Dict, Iterable
|
||||
|
||||
from spotify_model import SimplifiedAlbum
|
||||
from spotipy import Spotify
|
||||
|
||||
from spotify_actions.album import (
|
||||
album_filter_label,
|
||||
album_filter_release,
|
||||
album_from_ids,
|
||||
album_sort_release,
|
||||
album_to_simplified,
|
||||
album_to_tracks,
|
||||
)
|
||||
from spotify_actions.combinator import combinator_join
|
||||
from spotify_actions.playlist import (
|
||||
playlist_current_user_all,
|
||||
playlist_current_user_assure,
|
||||
playlist_replace,
|
||||
playlist_tracks,
|
||||
)
|
||||
from spotify_actions.search import Query, search_albums
|
||||
from spotify_actions.track import track_unique_albums
|
||||
from spotify_actions.util import read_credentials_oauth
|
||||
|
||||
|
||||
def label_playlist(client: Spotify, label_name: str, playlist_id: str) -> None:
|
||||
# Given a label name, replace all songs in the provided `playlist_id` with the
|
||||
# label's songs, ordered by descending release date.
|
||||
|
||||
albums_search = search_albums(client, Query(label=label_name))
|
||||
albums_unfiltered = album_from_ids(client, albums_search)
|
||||
albums_unsorted = album_filter_label(albums_unfiltered, label_name)
|
||||
albums = album_sort_release(albums_unsorted, descending=True)
|
||||
tracks = album_to_tracks(client, albums)
|
||||
|
||||
playlist_replace(client, playlist_id, tracks)
|
||||
|
||||
|
||||
def label_recent(client: Spotify, playlist_id: str, released_after: date) -> Iterable[SimplifiedAlbum]:
|
||||
# Get all albums in a playlist released after the provided date
|
||||
tracks = playlist_tracks(client, [playlist_id])
|
||||
albums = track_unique_albums(tracks)
|
||||
|
||||
# Because the playlists were created in descending release date order,
|
||||
# `is_sorted=True` is enabled to reduce the number of API queries needed
|
||||
return album_filter_release(albums, released_after, is_sorted=True)
|
||||
|
||||
|
||||
def run(client: Spotify, recent_releases_id: str, label_ids: Dict[str, str], released_after: date) -> None:
|
||||
|
||||
# Create the individual label playlists
|
||||
for label_name, playlist_id in label_ids.items():
|
||||
label_playlist(client, label_name, playlist_id)
|
||||
|
||||
# Get albums from the playlists we just created
|
||||
album_iterables = [label_recent(client, playlist_id, released_after) for _, playlist_id in label_ids.items()]
|
||||
|
||||
# Merge all the albums from each label playlist
|
||||
recent_albums = combinator_join(*album_iterables)
|
||||
recent_tracks = album_to_tracks(client, recent_albums)
|
||||
|
||||
# Create the recent releases playlist
|
||||
playlist_replace(client, recent_releases_id, recent_tracks)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
one_week_ago = (datetime.now().date() - timedelta(days=7)).strftime("%Y-%m-%d")
|
||||
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument("-c", "--credentials", required=True)
|
||||
parser.add_argument("label")
|
||||
parser.add_argument("-r", "--redirect-uri", required=True)
|
||||
parser.add_argument(
|
||||
"-d", "--released-after", help="YYYY-MM-DD date that albums must be released after", default=one_week_ago
|
||||
)
|
||||
parser.add_argument("recent_release", help='Name of the "recent releases" playlist constructed from all labels')
|
||||
parser.add_argument("label", nargs="+")
|
||||
|
||||
cmdline = parser.parse_args()
|
||||
|
||||
client = read_credentials_oauth(
|
||||
cmdline.credentials,
|
||||
redirect_uri="https://speice.io/spotify/",
|
||||
redirect_uri=cmdline.redirect_uri,
|
||||
scopes=["playlist-read-private", "playlist-modify-private", "playlist-modify-public"],
|
||||
)
|
||||
|
||||
user_playlists = playlist_current_user_all(client)
|
||||
playlists = playlist_current_user_assure(client, user_playlists, cmdline.label)
|
||||
playlist = list(playlists)[0]
|
||||
released_after = datetime.strptime(cmdline.released_after, "%Y-%m-%d")
|
||||
|
||||
albums_search = search_albums(client, Query(label=cmdline.label))
|
||||
albums_unfiltered = album_to_simplified(client, albums_search)
|
||||
albums_unsorted = album_filter_label(albums_unfiltered, cmdline.label)
|
||||
albums = album_sort_release(albums_unsorted, descending=True)
|
||||
tracks = album_to_tracks(client, albums)
|
||||
# Get all user playlists; we'll be iterating over this a couple times
|
||||
user_playlists = list(playlist_current_user_all(client))
|
||||
|
||||
playlist_replace(client, playlist.spotify_id, tracks)
|
||||
# To simplify, this assumes that the label playlist name is unique for this user
|
||||
def _locate_playlist(name: str) -> str:
|
||||
assured = playlist_current_user_assure(client, user_playlists, name)
|
||||
# The `str()` wrapper is technically unnecessary, but keeps mypy happy
|
||||
return str(list(assured)[0].spotify_id)
|
||||
|
||||
recent_releases = _locate_playlist(cmdline.recent_release)
|
||||
label_playlists = {label: _locate_playlist(label) for label in cmdline.label}
|
||||
|
||||
run(client, recent_releases, label_playlists, released_after)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -1,35 +0,0 @@
|
||||
# pylint: disable=missing-module-docstring, missing-function-docstring
|
||||
|
||||
from argparse import ArgumentParser
|
||||
from datetime import date, timedelta
|
||||
|
||||
from spotify_actions.album import album_to_simplified, album_to_tracks
|
||||
from spotify_actions.combinator import combinator_join
|
||||
from spotify_actions.echo import echo_tracks
|
||||
from spotify_actions.search import Query, search_albums
|
||||
from spotify_actions.temporal import temporal_released_after
|
||||
from spotify_actions.util import read_credentials
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument("-c", "--credentials", required=True)
|
||||
parser.add_argument("label", nargs="+")
|
||||
|
||||
cmdline = parser.parse_args()
|
||||
|
||||
today = date.today()
|
||||
four_weeks = timedelta(days=28)
|
||||
|
||||
client = read_credentials(cmdline.credentials)
|
||||
|
||||
label_albums_search = [search_albums(client, Query(label=l)) for l in cmdline.label]
|
||||
albums_search = combinator_join(*label_albums_search)
|
||||
albums_search_recent = temporal_released_after(albums_search, today - four_weeks)
|
||||
albums_recent = album_to_simplified(client, albums_search_recent)
|
||||
tracks_recent = album_to_tracks(client, albums_recent)
|
||||
echo_tracks(tracks_recent)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -1,25 +0,0 @@
|
||||
# pylint: disable=missing-module-docstring, missing-function-docstring
|
||||
|
||||
from argparse import ArgumentParser
|
||||
|
||||
from spotify_actions.combinator import combinator_take
|
||||
from spotify_actions.echo import echo_tracks
|
||||
from spotify_actions.search import search_tracks
|
||||
from spotify_actions.util import read_credentials
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument("-c", "--credentials", required=True)
|
||||
parser.add_argument("query")
|
||||
|
||||
cmdline = parser.parse_args()
|
||||
|
||||
client = read_credentials(cmdline.credentials)
|
||||
tracks = search_tracks(client, cmdline.query)
|
||||
tracks_take = combinator_take(tracks, count=100)
|
||||
echo_tracks(tracks_take)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Reference in New Issue
Block a user