Skip to content

Commit e78137a

Browse files
use radio mix playlists as recommendations (#275)
1 parent 4f7c768 commit e78137a

File tree

3 files changed

+39
-2
lines changed

3 files changed

+39
-2
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,10 @@ playerManager.registerSourceManager(new YTDLPSourceManager("path/to/yt-dlp"));
828828
* `spsearch:animals architects` (check out [Spotify Search Docs](https://developer.spotify.com/documentation/web-api/reference/search) for advanced search queries like isrc & co)
829829
* `sprec:seed_artists=3ZztVuWxHzNpl0THurTFCv,4MzJMcHQBl9SIYSjwWn8QW&seed_genres=metalcore&seed_tracks=5ofoB8PFmocBXFBEWVb6Vz,6I5zXzSDByTEmYZ7ePVQeB`
830830
(only works in [Extended quota mode](https://developer.spotify.com/documentation/web-api/concepts/quota-modes#extended-quota-mode) or with anonymous tokens, check out [Spotify Recommendations Docs](https://developer.spotify.com/documentation/web-api/reference/get-recommendations) for the full query parameter list)
831+
* `sprec:mix:artist:0gxyHStUsqpMadRV0Di1Qt`
832+
* `sprec:mix:track:4PTG3Z6ehGkBFwjybzWkR8`
833+
* `sprec:mix:album:7t0YTcJ3HsalOTIE6XzQYo`
834+
* `sprec:mix:isrc:GBARL9300135`
831835
* https://open.spotify.com/track/0eG08cBeKk0mzykKjw4hcQ
832836
* https://open.spotify.com/album/7qemUq4n71awwVPOaX7jw4
833837
* https://open.spotify.com/playlist/7HAO9R9v203gkaPAgknOMp (playlists can include local files if you enabled this via: `plugins.lavasrc.spotify.localFiles: true`. Please note `uri` & `isrc` will be `null` & `identifier` will be `"local"`)

main/src/main/java/com/github/topi314/lavasrc/mirror/DefaultMirroringAudioTrackResolver.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public AudioItem apply(MirroringAudioTrack mirroringAudioTrack) {
3838

3939
if (provider.contains(MirroringAudioSourceManager.ISRC_PATTERN)) {
4040
if (mirroringAudioTrack.getInfo().isrc != null && !mirroringAudioTrack.getInfo().isrc.isEmpty()) {
41-
provider = provider.replace(MirroringAudioSourceManager.ISRC_PATTERN, mirroringAudioTrack.getInfo().isrc);
41+
provider = provider.replace(MirroringAudioSourceManager.ISRC_PATTERN, mirroringAudioTrack.getInfo().isrc.replace("-", ""));
4242
} else {
4343
log.debug("Ignoring identifier \"{}\" because this track does not have an ISRC!", provider);
4444
continue;

main/src/main/java/com/github/topi314/lavasrc/spotify/SpotifySourceManager.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,14 @@
3838
import java.util.Set;
3939
import java.util.function.Consumer;
4040
import java.util.function.Function;
41+
import java.util.regex.Matcher;
4142
import java.util.regex.Pattern;
4243
import java.util.stream.Collectors;
4344

4445
public class SpotifySourceManager extends MirroringAudioSourceManager implements HttpConfigurable, AudioSearchManager, AudioLyricsManager {
4546

4647
public static final Pattern URL_PATTERN = Pattern.compile("(https?://)(www\\.)?open\\.spotify\\.com/((?<region>[a-zA-Z-]+)/)?(user/(?<user>[a-zA-Z0-9-_]+)/)?(?<type>track|album|playlist|artist)/(?<identifier>[a-zA-Z0-9-_]+)");
48+
public static final Pattern RADIO_MIX_QUERY_PATTERN = Pattern.compile("mix:(?<seedType>album|artist|track|isrc):(?<seed>[a-zA-Z0-9-_]+)");
4749
public static final String SEARCH_PREFIX = "spsearch:";
4850
public static final String RECOMMENDATIONS_PREFIX = "sprec:";
4951
public static final String PREVIEW_PREFIX = "spprev:";
@@ -65,6 +67,7 @@ public class SpotifySourceManager extends MirroringAudioSourceManager implements
6567
private boolean localFiles;
6668
private boolean resolveArtistsInSearch = true;
6769
private boolean preferAnonymousToken = false;
70+
6871

6972
public SpotifySourceManager(String[] providers, String clientId, String clientSecret, String countryCode, AudioPlayerManager audioPlayerManager) {
7073
this(clientId, clientSecret, null, countryCode, unused -> audioPlayerManager, new DefaultMirroringAudioTrackResolver(providers));
@@ -83,7 +86,7 @@ public SpotifySourceManager(String clientId, String clientSecret, String country
8386
}
8487

8588
public SpotifySourceManager(String clientId, String clientSecret, String spDc, String countryCode, Function<Void, AudioPlayerManager> audioPlayerManager, MirroringAudioTrackResolver mirroringAudioTrackResolver) {
86-
this(clientId, clientSecret, false, spDc, countryCode, audioPlayerManager, mirroringAudioTrackResolver);
89+
this(clientId, clientSecret, false , spDc, countryCode, audioPlayerManager, mirroringAudioTrackResolver);
8790
}
8891

8992
public SpotifySourceManager(String clientId, String clientSecret, boolean preferAnonymousToken, String spDc, String countryCode, Function<Void, AudioPlayerManager> audioPlayerManager, MirroringAudioTrackResolver mirroringAudioTrackResolver) {
@@ -376,6 +379,36 @@ public AudioItem getSearch(String query, boolean preview) throws IOException {
376379
}
377380

378381
public AudioItem getRecommendations(String query, boolean preview) throws IOException {
382+
Matcher matcher = RADIO_MIX_QUERY_PATTERN.matcher(query);
383+
if (matcher.find()) {
384+
String seedType = matcher.group("seedType");
385+
String seed = matcher.group("seed");
386+
if (seedType.equals("isrc")) {
387+
AudioItem item = this.getSearch("isrc:" + seed, preview);
388+
if (item == AudioReference.NO_TRACK) {
389+
return AudioReference.NO_TRACK;
390+
}
391+
if (item instanceof AudioTrack) {
392+
seed = ((AudioTrack) item).getIdentifier();
393+
seedType = "track";
394+
} else if (item instanceof AudioPlaylist) {
395+
var playlist = (AudioPlaylist) item;
396+
if (!playlist.getTracks().isEmpty()) {
397+
seed = playlist.getTracks().get(0).getIdentifier();
398+
seedType = "track";
399+
} else {
400+
return AudioReference.NO_TRACK;
401+
}
402+
}
403+
}
404+
JsonBrowser rjson = this.getJson(CLIENT_API_BASE + "inspiredby-mix/v2/seed_to_playlist/spotify:" + seedType + ":" + seed + "?response-format=json", true, this.preferAnonymousToken);
405+
JsonBrowser mediaItems = rjson.get("mediaItems");
406+
if (mediaItems.isList() && mediaItems.values().size() > 0) {
407+
String playlistId = mediaItems.index(0).get("uri").text().split(":")[2];
408+
return this.getPlaylist(playlistId, preview);
409+
}
410+
411+
}
379412
var json = this.getJson(API_BASE + "recommendations?" + query, false, false);
380413
if (json == null || json.get("tracks").values().isEmpty()) {
381414
return AudioReference.NO_TRACK;

0 commit comments

Comments
 (0)