From dea6f5bb68367b878548a80a7d20ae5e1f96f227 Mon Sep 17 00:00:00 2001 From: Thomas Couchoud <1688389+Rakambda@users.noreply.github.com> Date: Tue, 18 Feb 2025 20:00:37 +0100 Subject: [PATCH] Add spotify support --- build.gradle.kts | 4 ++ gradle/libs.versions.toml | 5 +- .../rsndiscord/spring/audio/AudioService.java | 50 ++++++++++++------- .../spring/audio/AudioServiceFactory.java | 7 +-- .../spring/settings/ApplicationSettings.java | 3 +- .../spring/settings/MusicSettings.java | 15 ++++++ 6 files changed, 61 insertions(+), 23 deletions(-) create mode 100644 src/main/java/fr/rakambda/rsndiscord/spring/settings/MusicSettings.java diff --git a/build.gradle.kts b/build.gradle.kts index f27ecd1f..9ebaac7c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -61,6 +61,10 @@ repositories { name = "Lavalink" url = uri("https://maven.lavalink.dev/releases") } + maven { + name = "topi314" + url = uri("https://maven.topi.wtf/releases") + } maven { name = "jitpack" url = uri("https://jitpack.io") diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1a13c8e9..492c2bad 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,6 +2,7 @@ jda-version = "5.3.0" lavaplayer-version = "2.2.3" lavaplayer-youtube-v2-version = "1.11.4" +lavasrc-version = "4.4.1" lp_cross-version = "0.1.1" jetbrains-annotations-version = "26.0.2" opus-version = "1.1.1" @@ -16,6 +17,8 @@ sptringboot-dm-version = "1.1.7" jda = { group = "net.dv8tion", name = "JDA", version.ref = "jda-version" } lavaplayer = { group = "dev.arbjerg", name = "lavaplayer", version.ref = "lavaplayer-version" } lavaplayer-youtube-v2 = { group = "dev.lavalink.youtube", name = "v2", version.ref = "lavaplayer-youtube-v2-version"} +lavasrc = { group = "com.github.topi314.lavasrc", name = "lavasrc", version.ref = "lavasrc-version"} +lavasrc-protocol = { group = "com.github.topi314.lavasrc", name = "lavasrc-protocol", version.ref = "lavasrc-version"} lpCross = { group = "com.github.natanbc", name = "lp-cross", version.ref = "lp_cross-version" } jetbrainsAnnotations = { group = "org.jetbrains", name = "annotations", version.ref = "jetbrains-annotations-version" } opus-api = { group = "club.minnced", name = "opus-java-api", version.ref = "opus-version" } @@ -23,7 +26,7 @@ opus-natives = { group = "club.minnced", name = "opus-java-natives", version.ref [bundles] opus = ["opus-api", "opus-natives"] -lavalink = ["lavaplayer", "lavaplayer-youtube-v2", "lpCross"] +lavalink = ["lavaplayer", "lavaplayer-youtube-v2", "lpCross", "lavasrc", "lavasrc-protocol"] [plugins] names = { id = "com.github.ben-manes.versions", version.ref = "names-version" } diff --git a/src/main/java/fr/rakambda/rsndiscord/spring/audio/AudioService.java b/src/main/java/fr/rakambda/rsndiscord/spring/audio/AudioService.java index 2ba570f7..55b7ad45 100644 --- a/src/main/java/fr/rakambda/rsndiscord/spring/audio/AudioService.java +++ b/src/main/java/fr/rakambda/rsndiscord/spring/audio/AudioService.java @@ -1,8 +1,15 @@ package fr.rakambda.rsndiscord.spring.audio; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.ExecutionException; +import com.github.topi314.lavasrc.mirror.DefaultMirroringAudioTrackResolver; +import com.github.topi314.lavasrc.spotify.SpotifySourceManager; import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager; +import com.sedmelluq.discord.lavaplayer.source.AudioSourceManager; import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import dev.lavalink.youtube.YoutubeAudioSourceManager; @@ -18,6 +25,7 @@ import fr.rakambda.rsndiscord.spring.audio.scheduler.ITrackScheduler; import fr.rakambda.rsndiscord.spring.audio.scheduler.ITrackSchedulerStatusListener; import fr.rakambda.rsndiscord.spring.audio.scheduler.TrackScheduler; +import fr.rakambda.rsndiscord.spring.settings.MusicSettings; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.entities.Guild; @@ -25,10 +33,6 @@ import net.dv8tion.jda.api.entities.channel.unions.AudioChannelUnion; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.ExecutionException; @Slf4j public class AudioService implements ITrackSchedulerStatusListener, ITrackLoadListener{ @@ -38,9 +42,31 @@ public class AudioService implements ITrackSchedulerStatusListener, ITrackLoadLi @Getter private final ITrackScheduler trackScheduler; - public AudioService(@NotNull Guild guild, int volume, @Nullable String refreshToken){ + public AudioService(@NotNull Guild guild, int volume, @NotNull MusicSettings musicSettings){ this.guild = guild; + audioPlayerManager = new DefaultAudioPlayerManager(); + audioPlayerManager.registerSourceManager(createYoutubeSourceManager(musicSettings.getYoutubeRefreshToken())); + audioPlayerManager.registerSourceManager(createSpotifySourceManager(musicSettings.getSpotifyClientId(), musicSettings.getSpotifyClientSecret(), musicSettings.getSpotifyCountryCode())); + audioPlayer = audioPlayerManager.createPlayer(); + + var trackScheduler = new TrackScheduler(audioPlayer); + trackScheduler.addListener(this); + this.trackScheduler = trackScheduler; + + audioPlayer.setVolume(volume); + audioPlayer.addListener(trackScheduler); + + AudioSourceManagers.registerRemoteSources(audioPlayerManager); + } + + @NotNull + private AudioSourceManager createSpotifySourceManager(@NotNull String clientId, @NotNull String clientSecret, @Nullable String countryCode){ + return new SpotifySourceManager(clientId, clientSecret, countryCode, audioPlayerManager, new DefaultMirroringAudioTrackResolver(null)); + } + + @NotNull + private AudioSourceManager createYoutubeSourceManager(@Nullable String refreshToken){ var youtubeAudioSourceManager = new YoutubeAudioSourceManager(true, new MusicWithThumbnail(), new WebWithThumbnail(), @@ -54,19 +80,7 @@ public AudioService(@NotNull Guild guild, int volume, @Nullable String refreshTo else{ youtubeAudioSourceManager.useOauth2(null, false); } - - audioPlayerManager = new DefaultAudioPlayerManager(); - audioPlayerManager.registerSourceManager(youtubeAudioSourceManager); - audioPlayer = audioPlayerManager.createPlayer(); - - var trackScheduler = new TrackScheduler(audioPlayer); - trackScheduler.addListener(this); - this.trackScheduler = trackScheduler; - - audioPlayer.setVolume(volume); - audioPlayer.addListener(trackScheduler); - - AudioSourceManagers.registerRemoteSources(audioPlayerManager); + return youtubeAudioSourceManager; } @Override diff --git a/src/main/java/fr/rakambda/rsndiscord/spring/audio/AudioServiceFactory.java b/src/main/java/fr/rakambda/rsndiscord/spring/audio/AudioServiceFactory.java index c8d0a1d0..d75b33c2 100644 --- a/src/main/java/fr/rakambda/rsndiscord/spring/audio/AudioServiceFactory.java +++ b/src/main/java/fr/rakambda/rsndiscord/spring/audio/AudioServiceFactory.java @@ -1,6 +1,7 @@ package fr.rakambda.rsndiscord.spring.audio; import fr.rakambda.rsndiscord.spring.settings.ApplicationSettings; +import fr.rakambda.rsndiscord.spring.settings.MusicSettings; import fr.rakambda.rsndiscord.spring.storage.repository.AudioRepository; import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.entities.Guild; @@ -14,12 +15,12 @@ @Component public class AudioServiceFactory{ private final AudioRepository audioRepository; - private final String refreshToken; + private final MusicSettings musicSettings; private final Map services; public AudioServiceFactory( AudioRepository audioRepository, ApplicationSettings applicationSettings){ this.audioRepository = audioRepository; - refreshToken = applicationSettings.getYoutubeRefreshToken(); + musicSettings = applicationSettings.getMusic(); services = new ConcurrentHashMap<>(); } @@ -34,7 +35,7 @@ private AudioService buildService(@NotNull Guild guild){ var guildEntity = audioRepository.findByGuildId(guild.getIdLong()).orElseThrow(); var volume = Math.min(100, Math.max(0, guildEntity.getVolume())); - return new AudioService(guild, volume, refreshToken); + return new AudioService(guild, volume, musicSettings); } @NotNull diff --git a/src/main/java/fr/rakambda/rsndiscord/spring/settings/ApplicationSettings.java b/src/main/java/fr/rakambda/rsndiscord/spring/settings/ApplicationSettings.java index 237a927a..933c4bbb 100644 --- a/src/main/java/fr/rakambda/rsndiscord/spring/settings/ApplicationSettings.java +++ b/src/main/java/fr/rakambda/rsndiscord/spring/settings/ApplicationSettings.java @@ -18,7 +18,6 @@ public class ApplicationSettings{ private boolean development; private List developmentGuilds = new LinkedList<>(); private String botToken; - private String youtubeRefreshToken; private String amqpPrefix; @NestedConfigurationProperty private AnilistSettings anilist; @@ -30,4 +29,6 @@ public class ApplicationSettings{ private TraktSettings trakt; @NestedConfigurationProperty private SimklSettings simkl; + @NestedConfigurationProperty + private MusicSettings music; } diff --git a/src/main/java/fr/rakambda/rsndiscord/spring/settings/MusicSettings.java b/src/main/java/fr/rakambda/rsndiscord/spring/settings/MusicSettings.java new file mode 100644 index 00000000..1d50af82 --- /dev/null +++ b/src/main/java/fr/rakambda/rsndiscord/spring/settings/MusicSettings.java @@ -0,0 +1,15 @@ +package fr.rakambda.rsndiscord.spring.settings; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class MusicSettings { + private String youtubeRefreshToken; + private String spotifyClientId; + private String spotifyClientSecret; + private String spotifyCountryCode; +}