Skip to content

Commit

Permalink
Allow specifying subsonic playlist ID to overwrite
Browse files Browse the repository at this point in the history
If given the playlist upload to subsonic will look for an existing
playlist with the given ID and update it. If no playlist with the given
ID is found a new playlist gets created.
  • Loading branch information
phw committed Dec 3, 2024
1 parent 2f3a152 commit 0eb0cb6
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 12 deletions.
15 changes: 9 additions & 6 deletions troi/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,12 +183,13 @@ def info_cmd(patch):
@click.option("-d", "--db_file", help="Database file for the local collection", required=False, is_flag=False)
@click.option('-t', '--threshold', default=.80, help="Minimum match percentage for metadata matches. Must be 0.0 - 1.0")
@click.option('-u', '--upload-to-subsonic', required=False, is_flag=True, help="upload playlist via subsonic API")
@click.option('-i', '--subsonic-id', required=False, help="overwrite existing subsonic playlist with the given ID")
@click.option('-m', '--save-to-m3u', required=False, help="save to specified m3u playlist")
@click.option('-j', '--save-to-jspf', required=False, help="save to specified JSPF playlist")
@click.option('-y', '--dont-ask', required=False, is_flag=True, help="save playlist without asking user")
@click.option('-q', '--quiet', 'quiet', help="Do no print out anything", required=False, is_flag=True)
@click.argument('jspf_playlist')
def resolve(db_file, threshold, upload_to_subsonic, save_to_m3u, save_to_jspf, dont_ask, quiet, jspf_playlist):
def resolve(db_file, threshold, upload_to_subsonic, subsonic_id, save_to_m3u, save_to_jspf, dont_ask, quiet, jspf_playlist):
""" Resolve a global JSPF playlist with MusicBrainz MBIDs to files in the local collection"""
set_log_level(quiet)
db_file = db_file_check(db_file)
Expand All @@ -197,20 +198,21 @@ def resolve(db_file, threshold, upload_to_subsonic, save_to_m3u, save_to_jspf, d
lbrl = ListenBrainzRadioLocal(quiet)
playlist = read_jspf_playlist(jspf_playlist)
lbrl.resolve_playlist(threshold, playlist)
output_playlist(db, playlist, upload_to_subsonic, save_to_m3u, save_to_jspf, dont_ask)
output_playlist(db, playlist, upload_to_subsonic, save_to_m3u, save_to_jspf, dont_ask, subsonic_id)


@cli.command(name="lb-radio", context_settings=dict(ignore_unknown_options=True, ))
@click.option("-d", "--db_file", help="Database file for the local collection", required=False, is_flag=False)
@click.option('-t', '--threshold', default=.80, help="Minimum match percentage for metadata matches. Must be 0.0 - 1.0")
@click.option('-u', '--upload-to-subsonic', required=False, is_flag=True, help="upload playlist via subsonic API")
@click.option('-i', '--subsonic-id', required=False, help="overwrite existing subsonic playlist with the given ID")
@click.option('-m', '--save-to-m3u', required=False, help="save to specified m3u playlist")
@click.option('-j', '--save-to-jspf', required=False, help="save to specified JSPF playlist")
@click.option('-y', '--dont-ask', required=False, is_flag=True, help="save playlist without asking user")
@click.option('-q', '--quiet', 'quiet', help="Do no print out anything", required=False, is_flag=True)
@click.argument('mode')
@click.argument('prompt')
def lb_radio(db_file, threshold, upload_to_subsonic, save_to_m3u, save_to_jspf, dont_ask, quiet, mode, prompt):
def lb_radio(db_file, threshold, upload_to_subsonic, subsonic_id, save_to_m3u, save_to_jspf, dont_ask, quiet, mode, prompt):
"""Use LB Radio to create a playlist from a prompt, using a local music collection"""
set_log_level(quiet)
db_file = db_file_check(db_file)
Expand All @@ -224,19 +226,20 @@ def lb_radio(db_file, threshold, upload_to_subsonic, save_to_m3u, save_to_jspf,
db.metadata_sanity_check(include_subsonic=upload_to_subsonic)
return

output_playlist(db, playlist, upload_to_subsonic, save_to_m3u, save_to_jspf, dont_ask)
output_playlist(db, playlist, upload_to_subsonic, save_to_m3u, save_to_jspf, dont_ask, subsonic_id)


@cli.command("weekly-jams", context_settings=dict(ignore_unknown_options=True, ))
@click.option("-d", "--db_file", help="Database file for the local collection", required=False, is_flag=False)
@click.option('-t', '--threshold', default=.80, help="Minimum match percentage for metadata matches. Must be 0.0 - 1.0")
@click.option('-u', '--upload-to-subsonic', required=False, is_flag=True, help="upload playlist via subsonic API")
@click.option('-i', '--subsonic-id', required=False, help="overwrite existing subsonic playlist with the given ID")
@click.option('-m', '--save-to-m3u', required=False, help="save to specified m3u playlist")
@click.option('-j', '--save-to-jspf', required=False, help="save to specified JSPF playlist")
@click.option('-y', '--dont-ask', required=False, is_flag=True, help="save playlist without asking user")
@click.option('-q', '--quiet', 'quiet', help="Do no print out anything", required=False, is_flag=True)
@click.argument('user_name')
def periodic_jams(db_file, threshold, upload_to_subsonic, save_to_m3u, save_to_jspf, dont_ask, quiet, user_name):
def periodic_jams(db_file, threshold, upload_to_subsonic, subsonic_id, save_to_m3u, save_to_jspf, dont_ask, quiet, user_name):
"Generate a weekly jams playlist for your local collection"
set_log_level(quiet)
db_file = db_file_check(db_file)
Expand All @@ -251,7 +254,7 @@ def periodic_jams(db_file, threshold, upload_to_subsonic, save_to_m3u, save_to_j
db.metadata_sanity_check(include_subsonic=upload_to_subsonic)
return

output_playlist(db, playlist, upload_to_subsonic, save_to_m3u, save_to_jspf, dont_ask)
output_playlist(db, playlist, upload_to_subsonic, save_to_m3u, save_to_jspf, dont_ask, subsonic_id)


@cli.command(context_settings=dict(ignore_unknown_options=True, ))
Expand Down
4 changes: 2 additions & 2 deletions troi/content_resolver/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
DEFAULT_CHUNKSIZE = 100


def output_playlist(db, playlist, upload_to_subsonic, save_to_m3u, save_to_jspf, dont_ask):
def output_playlist(db, playlist, upload_to_subsonic, save_to_m3u, save_to_jspf, dont_ask, subsonic_id=None):
try:
recording = playlist.playlists[0].recordings[0]
except (KeyError, IndexError):
Expand All @@ -43,7 +43,7 @@ def output_playlist(db, playlist, upload_to_subsonic, save_to_m3u, save_to_jspf,

if dont_ask or ask_yes_no_question("Upload via subsonic? (Y/n)"):
logger.info("uploading playlist")
db.upload_playlist(playlist)
db.upload_playlist(playlist, subsonic_id)
return

if save_to_m3u or save_to_jspf:
Expand Down
19 changes: 15 additions & 4 deletions troi/content_resolver/subsonic.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import datetime
import logging

from libsonic.errors import DataNotFoundError
import peewee
from tqdm import tqdm

Expand Down Expand Up @@ -235,9 +236,7 @@ def update_recordings(self, recordings):
# , subsonic_id = excluded.subsonic_id
# , last_updated = excluded.last_updated""", recordings)



def upload_playlist(self, playlist):
def upload_playlist(self, playlist, playlist_id=None):
"""
Given a Troi playlist, upload the playlist to the subsonic API.
"""
Expand All @@ -253,4 +252,16 @@ def upload_playlist(self, playlist):
except KeyError:
continue

conn.createPlaylist(name=playlist.playlists[0].name, songIds=song_ids)
if playlist_id:
try:
remote_playlist = conn.getPlaylist(pid=playlist_id)
conn.updatePlaylist(
lid=playlist_id,
name=playlist.playlists[0].name,
songIdsToAdd=song_ids,
songIndexesToRemove=list(range(0, len(remote_playlist["playlist"]) - 1)),
)
except DataNotFoundError:
conn.createPlaylist(name=playlist.playlists[0].name, songIds=song_ids)
else:
conn.createPlaylist(name=playlist.playlists[0].name, songIds=song_ids)

0 comments on commit 0eb0cb6

Please sign in to comment.