[web] Instant mixes support albums and playlists too
All checks were successful
Deploy to mopidy1 / deploy (push) Successful in 10s

This commit is contained in:
2026-06-26 14:32:50 -04:00
parent a29d1d0487
commit 48e82a2084
2 changed files with 31 additions and 18 deletions

View File

@ -236,10 +236,10 @@
<div class="card" style="order: 1; grid-column: 1 / -1;"> <div class="card" style="order: 1; grid-column: 1 / -1;">
<h3>Instant Mix</h3> <h3>Instant Mix</h3>
<p>Generate a mix or insert into queue based on a track URI (same genre + similar artists).</p> <p>Generate a mix from a track, album, artist, or playlist URI (same genre + similar artists).</p>
<div class="field" style="flex-direction: column; gap: 0.5rem;"> <div class="field" style="flex-direction: column; gap: 0.5rem;">
<div style="display: flex; gap: 0.5rem;"> <div style="display: flex; gap: 0.5rem;">
<input id="instant-uri-input" type="text" placeholder="e.g. local:track:456" style="flex: 2;" /> <input id="instant-uri-input" type="text" placeholder="e.g. local:track:456 or local:album:123 or mopidy:playlist:..." style="flex: 2;" />
<input id="instant-limit-input" type="number" value="15" min="1" max="500" style="flex: 0 0 70px;" /> <input id="instant-limit-input" type="number" value="15" min="1" max="500" style="flex: 0 0 70px;" />
</div> </div>
<div style="display: flex; gap: 0.5rem;"> <div style="display: flex; gap: 0.5rem;">

View File

@ -166,30 +166,24 @@ class InstantMixHandler(tornado.web.RequestHandler):
def post(self) -> None: def post(self) -> None:
data = json.loads(self.request.body) data = json.loads(self.request.body)
track_uri = data.get("uri", "") uri = data.get("uri", "")
limit = data.get("limit", 50) limit = data.get("limit", 50)
if not track_uri: if not uri:
self.set_status(400) self.set_status(400)
self.write({"error": "Missing 'uri' in request body"}) self.write({"error": "Missing 'uri' in request body"})
return return
tracks = build_instant_mix(self.core, track_uri, limit, uris=self.uris)
seed = self._resolve_seed_track(uri)
if not seed or not seed.uri:
self.write({"playlist": None, "tracks": 0})
return
tracks = build_instant_mix(self.core, seed.uri, limit, uris=self.uris)
if not tracks: if not tracks:
self.write({"playlist": None, "tracks": 0}) self.write({"playlist": None, "tracks": 0})
return return
try: seed_name = seed.name or "Instant Mix"
lookup_result = self.core.library.lookup([track_uri]).get()
except Exception:
logger.exception("Track lookup failed for %s", track_uri)
self.write({"playlist": None, "tracks": 0})
return
seed_name = "Instant Mix"
for uri_tracks in lookup_result.values():
for t in uri_tracks:
if t.name:
seed_name = t.name
break
playlist = save_smart_playlist( playlist = save_smart_playlist(
self.core, self.prefix, f"Instant Mix: {seed_name}", tracks, self.core, self.prefix, f"Instant Mix: {seed_name}", tracks,
playlist_dir=self.playlist_dir, playlist_dir=self.playlist_dir,
@ -204,6 +198,25 @@ class InstantMixHandler(tornado.web.RequestHandler):
} }
) )
def _resolve_seed_track(self, uri: str):
try:
lookup = self.core.library.lookup([uri]).get()
except Exception:
lookup = None
if lookup:
tracks = [t for ts in lookup.values() for t in (ts or []) if t.uri]
if tracks:
return random.choice(tracks)
try:
pl = self.core.playlists.lookup(uri).get()
except Exception:
pl = None
if pl and pl.tracks:
valid = [t for t in pl.tracks if t.uri]
if valid:
return random.choice(valid)
return None
class PlaylistMixHandler(tornado.web.RequestHandler): class PlaylistMixHandler(tornado.web.RequestHandler):
def initialize( def initialize(