Skip to content

Commit e5d4e20

Browse files
committed
refactor Apple Music source manager to support extended audio track info and improve configuration options
1 parent b03db2a commit e5d4e20

24 files changed

+480
-545
lines changed

main/src/main/java/com/github/topi314/lavasrc/http/BaseHttpConfigurable.java

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.sedmelluq.discord.lavaplayer.tools.io.HttpInterfaceManager;
77
import org.apache.http.client.config.RequestConfig;
88
import org.apache.http.impl.client.HttpClientBuilder;
9+
import org.jetbrains.annotations.NotNull;
910
import org.slf4j.Logger;
1011
import org.slf4j.LoggerFactory;
1112

@@ -17,8 +18,10 @@ public interface BaseHttpConfigurable extends HttpConfigurable, AudioSourceManag
1718

1819
Logger log = LoggerFactory.getLogger(BaseHttpConfigurable.class);
1920

21+
@NotNull
2022
HttpInterfaceManager getHttpInterfaceManager();
2123

24+
@NotNull
2225
default HttpInterface getHttpInterface() {
2326
return this.getHttpInterfaceManager().getInterface();
2427
}

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

+23-18
Original file line numberDiff line numberDiff line change
@@ -12,72 +12,77 @@
1212
import org.slf4j.LoggerFactory;
1313

1414
import java.util.Set;
15+
import java.util.function.Supplier;
1516

1617
public class DefaultMirrorResolver implements MirrorResolver {
1718

1819
private static final Logger log = LoggerFactory.getLogger(DefaultMirrorResolver.class);
1920

20-
private static final Set<String> MIRROR_PROVIDERS = Set.of(
21+
private static final Set<String> MIRRORING_RESOLVERS = Set.of(
2122
SpotifySourceManager.SEARCH_PREFIX,
2223
AppleMusicSourceManager.SEARCH_PREFIX,
2324
TidalSourceManager.SEARCH_PREFIX
2425
);
2526

26-
private String[] providers = {
27+
private String[] resolvers = {
2728
"ytsearch:\"" + MirrorResolver.ISRC_PATTERN + "\"",
2829
"ytsearch:" + MirrorResolver.QUERY_PATTERN
2930
};
30-
private final AudioPlayerManager playerManager;
31+
private final Supplier<AudioPlayerManager> playerManager;
3132

32-
public DefaultMirrorResolver(AudioPlayerManager playerManager, String[] providers) {
33+
public DefaultMirrorResolver(AudioPlayerManager playerManager, String[] resolvers) {
34+
this(() -> playerManager, resolvers);
35+
}
36+
37+
public DefaultMirrorResolver(Supplier<AudioPlayerManager> playerManager, String[] resolvers) {
3338
this.playerManager = playerManager;
34-
if (providers != null && providers.length > 0) {
35-
this.providers = providers;
39+
if (resolvers != null && resolvers.length > 0) {
40+
this.resolvers = resolvers;
3641
}
3742
}
3843

3944
@Nullable
4045
@Override
4146
public AudioTrack find(MirroringAudioTrack<?> track) {
42-
for (var provider : providers) {
43-
if (MIRROR_PROVIDERS.contains(provider)) {
44-
log.debug("Ignoring provider \"{}\" because it is a mirroring provider itself!", provider);
47+
for (var resolver : resolvers) {
48+
if (MIRRORING_RESOLVERS.contains(resolver)) {
49+
log.debug("Ignoring resolver \"{}\" because it is a mirroring source itself!", resolver);
4550
continue;
4651
}
4752

48-
if (provider.contains(MirrorResolver.ISRC_PATTERN)) {
53+
if (resolver.contains(MirrorResolver.ISRC_PATTERN)) {
4954
var isrc = track.getInfo().isrc;
5055
if (isrc == null || isrc.isEmpty()) {
51-
log.debug("Ignoring provider \"{}\" because this track does not have an ISRC!", provider);
56+
log.debug("Ignoring resolver \"{}\" because this track does not have an ISRC!", resolver);
5257
continue;
5358
}
54-
provider = provider.replace(MirrorResolver.ISRC_PATTERN, isrc);
59+
resolver = resolver.replace(MirrorResolver.ISRC_PATTERN, isrc);
5560
}
5661

57-
provider = provider.replace(MirrorResolver.QUERY_PATTERN, MirrorResolver.getTrackTitle(track));
62+
resolver = resolver.replace(MirrorResolver.QUERY_PATTERN, MirrorResolver.getTrackTitle(track));
5863

5964
AudioItem item;
6065
try {
61-
item = MirrorResolver.loadItem(this.playerManager, provider);
66+
item = MirrorResolver.loadItem(this.playerManager.get(), resolver);
6267
} catch (Exception e) {
63-
log.error("Failed to load track from provider \"{}\"!", provider, e);
68+
log.error("Failed to load track from resolver \"{}\"!", resolver, e);
6469
continue;
6570
}
6671
if (item instanceof AudioTrack) {
6772
return (AudioTrack) item;
6873
}
69-
// If the track is an empty playlist, skip the provider
74+
// If the track is an empty playlist, skip the resolver
7075
if (item instanceof AudioPlaylist) {
7176
var playlist = (AudioPlaylist) item;
7277
if (!playlist.isSearchResult()) {
73-
log.debug("Ignoring non-search playlist from provider \"{}\"!", provider);
78+
log.debug("Ignoring non-search playlist from resolver \"{}\"!", resolver);
7479
continue;
7580
}
7681
if (playlist.getSelectedTrack() != null) {
7782
return playlist.getSelectedTrack();
7883
}
7984
if (playlist.getTracks().isEmpty()) {
80-
log.debug("Ignoring empty playlist from provider \"{}\"!", provider);
85+
log.debug("Ignoring empty playlist from resolver \"{}\"!", resolver);
8186
continue;
8287
}
8388
return playlist.getTracks().get(0);
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package com.github.topi314.lavasrc.mirror;
22

33
import com.sedmelluq.discord.lavaplayer.source.AudioSourceManager;
4+
import org.jetbrains.annotations.NotNull;
45

56
public interface MirroringAudioSourceManager extends AudioSourceManager {
67

8+
@NotNull
79
MirrorResolver getMirrorResolver();
810

911
}
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,30 @@
11
package com.github.topi314.lavasrc.source.applemusic;
22

3-
import com.github.topi314.lavasrc.mirror.MirroringAudioSourceManager;
3+
import com.github.topi314.lavasrc.extended.ExtendedAudioTrack;
4+
import com.github.topi314.lavasrc.extended.ExtendedAudioTrackInfo;
45
import com.github.topi314.lavasrc.mirror.MirroringAudioTrack;
5-
import com.sedmelluq.discord.lavaplayer.container.mpeg.MpegAudioTrack;
6-
import com.sedmelluq.discord.lavaplayer.tools.io.SeekableInputStream;
76
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
87
import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo;
9-
import com.sedmelluq.discord.lavaplayer.track.InternalAudioTrack;
8+
import org.jetbrains.annotations.NotNull;
109

11-
public class AppleMusicAudioTrack extends MirroringAudioTrack {
10+
public class AppleMusicAudioTrack extends MirroringAudioTrack<AppleMusicSourceManager> implements ExtendedAudioTrack {
1211

13-
public AppleMusicAudioTrack(AudioTrackInfo trackInfo, AppleMusicSourceManager sourceManager) {
14-
this(trackInfo, null, null, null, null, null, false, sourceManager);
15-
}
12+
private final ExtendedAudioTrackInfo extendedTrackInfo;
1613

17-
public AppleMusicAudioTrack(AudioTrackInfo trackInfo, String albumName, String albumUrl, String artistUrl, String artistArtworkUrl, String previewUrl, boolean isPreview, MirroringAudioSourceManager sourceManager) {
18-
super(trackInfo, albumName, albumUrl, artistUrl, artistArtworkUrl, previewUrl, isPreview, sourceManager);
14+
public AppleMusicAudioTrack(AudioTrackInfo trackInfo, ExtendedAudioTrackInfo extendedTrackInfo, AppleMusicSourceManager sourceManager) {
15+
super(trackInfo, sourceManager);
16+
this.extendedTrackInfo = extendedTrackInfo;
1917
}
2018

19+
@NotNull
2120
@Override
22-
protected InternalAudioTrack createAudioTrack(AudioTrackInfo trackInfo, SeekableInputStream stream) {
23-
return new MpegAudioTrack(trackInfo, stream);
21+
public ExtendedAudioTrackInfo getExtendedInfo() {
22+
return this.extendedTrackInfo;
2423
}
2524

2625
@Override
2726
protected AudioTrack makeShallowClone() {
28-
return new AppleMusicAudioTrack(this.trackInfo, (AppleMusicSourceManager) this.sourceManager);
27+
return new AppleMusicAudioTrack(this.trackInfo, this.extendedTrackInfo, this.sourceManager);
2928
}
3029

3130
}

main/src/main/java/com/github/topi314/lavasrc/source/applemusic/AppleMusicSourceManager.java

+51-42
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@
77
import com.github.topi314.lavasearch.result.AudioText;
88
import com.github.topi314.lavasearch.result.BasicAudioSearchResult;
99
import com.github.topi314.lavasearch.result.BasicAudioText;
10-
import com.github.topi314.lavasrc.extended.ExtendedAudioPlaylist;
1110
import com.github.topi314.lavasrc.LavaSrcTools;
12-
import com.github.topi314.lavasrc.mirror.DefaultMirrorResolver;
11+
import com.github.topi314.lavasrc.extended.ExtendedAudioPlaylist;
12+
import com.github.topi314.lavasrc.extended.ExtendedAudioSourceManager;
13+
import com.github.topi314.lavasrc.extended.ExtendedAudioTrackInfo;
14+
import com.github.topi314.lavasrc.http.BaseHttpConfigurable;
15+
import com.github.topi314.lavasrc.mirror.MirrorResolver;
1316
import com.github.topi314.lavasrc.mirror.MirroringAudioSourceManager;
14-
import com.github.topi314.lavasrc.mirror.MirroringAudioTrackResolver;
1517
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
1618
import com.sedmelluq.discord.lavaplayer.tools.JsonBrowser;
19+
import com.sedmelluq.discord.lavaplayer.tools.io.HttpClientTools;
20+
import com.sedmelluq.discord.lavaplayer.tools.io.HttpInterfaceManager;
1721
import com.sedmelluq.discord.lavaplayer.track.*;
1822
import org.apache.http.client.methods.HttpGet;
1923
import org.apache.http.client.utils.URIBuilder;
@@ -34,44 +38,61 @@
3438
import java.time.Duration;
3539
import java.time.Instant;
3640
import java.util.*;
37-
import java.util.function.Function;
3841
import java.util.function.Predicate;
3942
import java.util.regex.Pattern;
4043
import java.util.stream.Collectors;
4144

42-
public class AppleMusicSourceManager extends MirroringAudioSourceManager implements AudioSearchManager {
45+
public class AppleMusicSourceManager implements MirroringAudioSourceManager, ExtendedAudioSourceManager, AudioSearchManager, BaseHttpConfigurable {
4346

4447
public static final Pattern URL_PATTERN = Pattern.compile("(https?://)?(www\\.)?music\\.apple\\.com/((?<countrycode>[a-zA-Z]{2})/)?(?<type>album|playlist|artist|song)(/[a-zA-Z\\p{L}\\d\\-%]+)?/(?<identifier>[a-zA-Z\\d\\-.]+)(\\?i=(?<identifier2>\\d+))?");
4548
public static final String SEARCH_PREFIX = "amsearch:";
4649
public static final String PREVIEW_PREFIX = "amprev:";
4750
public static final long PREVIEW_LENGTH = 30000;
4851
public static final int MAX_PAGE_ITEMS = 300;
49-
public static final String API_BASE = "https://api.music.apple.com/v1/";
52+
private static final String API_BASE = "https://api.music.apple.com/v1/";
5053
public static final Set<AudioSearchResult.Type> SEARCH_TYPES = Set.of(AudioSearchResult.Type.TRACK, AudioSearchResult.Type.ALBUM, AudioSearchResult.Type.PLAYLIST, AudioSearchResult.Type.ARTIST, AudioSearchResult.Type.TEXT);
5154
public static final Set<AudioSearchResult.Type> TOP_RESULT_SEARCH_TYPES = Set.of(AudioSearchResult.Type.TRACK, AudioSearchResult.Type.ALBUM, AudioSearchResult.Type.PLAYLIST, AudioSearchResult.Type.ARTIST);
5255

53-
private final String countryCode;
56+
private final HttpInterfaceManager httpInterfaceManager = HttpClientTools.createDefaultThreadLocalManager();
57+
private final AppleMusicTokenManager tokenManager;
58+
private final MirrorResolver mirrorResolver;
59+
private final String countryCode = "US";
5460
private int playlistPageLimit;
5561
private int albumPageLimit;
56-
private final AppleMusicTokenManager tokenManager;
57-
58-
public AppleMusicSourceManager(String[] providers, String mediaAPIToken, String countryCode, Function<Void, AudioPlayerManager> audioPlayerManager) {
59-
this(mediaAPIToken, countryCode, audioPlayerManager, new DefaultMirrorResolver(providers));
60-
}
61-
62-
public AppleMusicSourceManager(String mediaAPIToken, String countryCode, AudioPlayerManager audioPlayerManager, MirroringAudioTrackResolver mirroringAudioTrackResolver) {
63-
this(mediaAPIToken, countryCode, unused -> audioPlayerManager, mirroringAudioTrackResolver);
64-
}
65-
66-
public AppleMusicSourceManager(String mediaAPIToken, String countryCode, Function<Void, AudioPlayerManager> audioPlayerManager, MirroringAudioTrackResolver mirroringAudioTrackResolver) {
67-
super(audioPlayerManager, mirroringAudioTrackResolver);
68-
this.countryCode = (countryCode == null || countryCode.isEmpty()) ? "US" : countryCode;
6962

63+
public AppleMusicSourceManager(String mediaAPIToken, MirrorResolver mirrorResolver) {
7064
try {
7165
this.tokenManager = new AppleMusicTokenManager(mediaAPIToken);
7266
} catch (IOException e) {
7367
throw new RuntimeException("Failed to initialize token manager", e);
7468
}
69+
this.mirrorResolver = mirrorResolver;
70+
}
71+
72+
@NotNull
73+
@Override
74+
public String getSourceName() {
75+
return "applemusic";
76+
}
77+
78+
@NotNull
79+
@Override
80+
public MirrorResolver getMirrorResolver() {
81+
return this.mirrorResolver;
82+
}
83+
84+
@NotNull
85+
@Override
86+
public HttpInterfaceManager getHttpInterfaceManager() {
87+
return this.httpInterfaceManager;
88+
}
89+
90+
@Override
91+
public AudioTrack decodeTrack(AudioTrackInfo trackInfo, DataInput input) throws IOException {
92+
return new AppleMusicAudioTrack(trackInfo,
93+
decodeTrack(input),
94+
this
95+
);
7596
}
7697

7798
public void setPlaylistPageLimit(int playlistPageLimit) {
@@ -90,25 +111,6 @@ public void setMediaAPIToken(String mediaAPIToken) {
90111
}
91112
}
92113

93-
@NotNull
94-
@Override
95-
public String getSourceName() {
96-
return "applemusic";
97-
}
98-
99-
@Override
100-
public AudioTrack decodeTrack(AudioTrackInfo trackInfo, DataInput input) throws IOException {
101-
var extendedAudioTrackInfo = super.decodeTrack(input);
102-
return new AppleMusicAudioTrack(trackInfo,
103-
extendedAudioTrackInfo.albumName,
104-
extendedAudioTrackInfo.albumUrl,
105-
extendedAudioTrackInfo.artistUrl,
106-
extendedAudioTrackInfo.artistArtworkUrl,
107-
extendedAudioTrackInfo.previewUrl,
108-
extendedAudioTrackInfo.isPreview,
109-
this
110-
);
111-
}
112114

113115
@Override
114116
public @Nullable AudioSearchResult loadSearch(@NotNull String query, @NotNull Set<AudioSearchResult.Type> types) {
@@ -254,7 +256,14 @@ public AudioSearchResult getSearchSuggestions(String query, Set<AudioSearchResul
254256
artworkUrl,
255257
isrc
256258
);
257-
var track = new AppleMusicAudioTrack(info, albumName, albumUrl, artistUrl, null, previewUrl, false, this);
259+
var extendedInfo = new ExtendedAudioTrackInfo(
260+
albumName,
261+
albumUrl,
262+
artistUrl,
263+
artworkUrl,
264+
false
265+
);
266+
var track = new AppleMusicAudioTrack(info, extendedInfo, this);
258267
tracks.add(track);
259268
break;
260269
}
@@ -463,7 +472,7 @@ private String parseArtistId(JsonBrowser json) {
463472
}
464473

465474

466-
public static AppleMusicSourceManager fromMusicKitKey(String musicKitKey, String keyId, String teamId, String countryCode, AudioPlayerManager audioPlayerManager, MirroringAudioTrackResolver mirroringAudioTrackResolver) throws NoSuchAlgorithmException, InvalidKeySpecException {
475+
public static AppleMusicSourceManager fromMusicKitKey(String musicKitKey, String keyId, String teamId, MirrorResolver mirrorResolver) throws NoSuchAlgorithmException, InvalidKeySpecException {
467476
var base64 = musicKitKey.replaceAll("-----BEGIN PRIVATE KEY-----\n", "")
468477
.replaceAll("-----END PRIVATE KEY-----", "")
469478
.replaceAll("\\s", "");
@@ -477,6 +486,6 @@ public static AppleMusicSourceManager fromMusicKitKey(String musicKitKey, String
477486
.withExpiresAt(Instant.now().plus(Duration.ofSeconds(15777000)))
478487
.withKeyId(keyId)
479488
.sign(Algorithm.ECDSA256(key));
480-
return new AppleMusicSourceManager(jwt, countryCode, audioPlayerManager, mirroringAudioTrackResolver);
489+
return new AppleMusicSourceManager(jwt, mirrorResolver);
481490
}
482491
}

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

+2
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,13 @@ public String getSourceName() {
7373
return "spotify";
7474
}
7575

76+
@NotNull
7677
@Override
7778
public MirrorResolver getMirrorResolver() {
7879
return this.mirrorResolver;
7980
}
8081

82+
@NotNull
8183
@Override
8284
public HttpInterfaceManager getHttpInterfaceManager() {
8385
return this.httpInterfaceManager;

main/src/main/java/com/github/topi314/lavasrc/source/vkmusic/VkMusicAudioTrack.java

+15-9
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,34 @@
11
package com.github.topi314.lavasrc.source.vkmusic;
22

33
import com.github.topi314.lavasrc.extended.ExtendedAudioTrack;
4+
import com.github.topi314.lavasrc.extended.ExtendedAudioTrackInfo;
45
import com.sedmelluq.discord.lavaplayer.container.mp3.Mp3AudioTrack;
5-
import com.sedmelluq.discord.lavaplayer.source.AudioSourceManager;
66
import com.sedmelluq.discord.lavaplayer.tools.io.PersistentHttpStream;
77
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
88
import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo;
9+
import com.sedmelluq.discord.lavaplayer.track.DelegatedAudioTrack;
910
import com.sedmelluq.discord.lavaplayer.track.playback.LocalAudioTrackExecutor;
11+
import org.jetbrains.annotations.NotNull;
1012

1113
import java.io.IOException;
1214
import java.net.URI;
1315
import java.net.URISyntaxException;
1416

15-
public class VkMusicAudioTrack extends ExtendedAudioTrack {
17+
public class VkMusicAudioTrack extends DelegatedAudioTrack implements ExtendedAudioTrack {
1618

19+
private final ExtendedAudioTrackInfo extendedTrackInfo;
1720
private final VkMusicSourceManager sourceManager;
1821

19-
public VkMusicAudioTrack(AudioTrackInfo trackInfo, VkMusicSourceManager sourceManager) {
20-
this(trackInfo, null, null, null, null, null, sourceManager);
22+
public VkMusicAudioTrack(AudioTrackInfo trackInfo, ExtendedAudioTrackInfo extendedTrackInfo, VkMusicSourceManager sourceManager) {
23+
super(trackInfo);
24+
this.extendedTrackInfo = extendedTrackInfo;
25+
this.sourceManager = sourceManager;
2126
}
2227

23-
public VkMusicAudioTrack(AudioTrackInfo trackInfo, String albumName, String albumUrl, String artistUrl, String artistArtworkUrl, String previewUrl, VkMusicSourceManager sourceManager) {
24-
super(trackInfo, albumName, albumUrl, artistUrl, artistArtworkUrl, previewUrl, false);
25-
this.sourceManager = sourceManager;
28+
@NotNull
29+
@Override
30+
public ExtendedAudioTrackInfo getExtendedInfo() {
31+
return this.extendedTrackInfo;
2632
}
2733

2834
@Override
@@ -51,11 +57,11 @@ public URI getMp3TrackUri() throws URISyntaxException, IOException {
5157

5258
@Override
5359
protected AudioTrack makeShallowClone() {
54-
return new VkMusicAudioTrack(this.trackInfo, this.sourceManager);
60+
return new VkMusicAudioTrack(this.trackInfo, this.extendedTrackInfo, this.sourceManager);
5561
}
5662

5763
@Override
58-
public AudioSourceManager getSourceManager() {
64+
public VkMusicSourceManager getSourceManager() {
5965
return this.sourceManager;
6066
}
6167
}

0 commit comments

Comments
 (0)