From 36762961a191027104d4eec5cac3272a509163f1 Mon Sep 17 00:00:00 2001 From: duncte123 Date: Sun, 30 Jun 2024 13:14:02 +0200 Subject: [PATCH] Add pixeldrain 'support' --- .../lavalinkplugin/DuncteBotConfig.java | 9 ++ .../lavalinkplugin/DuncteBotInjector.java | 6 + .../pixeldrain/PixelDrainAudioTrack.java | 24 ++++ .../PixeldrainAudioSourceManager.java | 131 ++++++++++++++++++ .../src/test/java/LocalPlaybackTest.java | 7 +- .../src/test/java/PixeldrainTest.java | 13 ++ 6 files changed, 187 insertions(+), 3 deletions(-) create mode 100644 source-managers/src/main/java/com/dunctebot/sourcemanagers/pixeldrain/PixelDrainAudioTrack.java create mode 100644 source-managers/src/main/java/com/dunctebot/sourcemanagers/pixeldrain/PixeldrainAudioSourceManager.java create mode 100644 source-managers/src/test/java/PixeldrainTest.java diff --git a/plugin/src/main/java/com/dunctebot/lavalinkplugin/DuncteBotConfig.java b/plugin/src/main/java/com/dunctebot/lavalinkplugin/DuncteBotConfig.java index d79ce6b..5a20175 100644 --- a/plugin/src/main/java/com/dunctebot/lavalinkplugin/DuncteBotConfig.java +++ b/plugin/src/main/java/com/dunctebot/lavalinkplugin/DuncteBotConfig.java @@ -29,6 +29,7 @@ public static class Sources { private boolean mixcloud = true; private boolean soundgasm = true; private boolean elgato = false; + private boolean pixeldrain = false; public boolean isGetyarn() { return getyarn; @@ -109,5 +110,13 @@ public boolean isElgato() { public void setElgato(boolean elgato) { this.elgato = elgato; } + + public boolean isPixeldrain() { + return pixeldrain; + } + + public void setPixeldrain(boolean pixeldrain) { + this.pixeldrain = pixeldrain; + } } } diff --git a/plugin/src/main/java/com/dunctebot/lavalinkplugin/DuncteBotInjector.java b/plugin/src/main/java/com/dunctebot/lavalinkplugin/DuncteBotInjector.java index 6810640..bf7fc17 100644 --- a/plugin/src/main/java/com/dunctebot/lavalinkplugin/DuncteBotInjector.java +++ b/plugin/src/main/java/com/dunctebot/lavalinkplugin/DuncteBotInjector.java @@ -5,6 +5,7 @@ import com.dunctebot.sourcemanagers.getyarn.GetyarnAudioSourceManager; import com.dunctebot.sourcemanagers.mixcloud.MixcloudAudioSourceManager; import com.dunctebot.sourcemanagers.ocremix.OCRemixAudioSourceManager; +import com.dunctebot.sourcemanagers.pixeldrain.PixeldrainAudioSourceManager; import com.dunctebot.sourcemanagers.pornhub.PornHubAudioSourceManager; import com.dunctebot.sourcemanagers.reddit.RedditAudioSourceManager; import com.dunctebot.sourcemanagers.soundgasm.SoundGasmAudioSourceManager; @@ -89,6 +90,11 @@ public AudioPlayerManager configure(@NotNull AudioPlayerManager manager) { // manager.registerSourceManager(new StreamDeckAudioSourceManager()); } + if (this.sourcesConfig.isPixeldrain()) { + logger.info("Registering pixeldrain audio source manager"); + manager.registerSourceManager(new PixeldrainAudioSourceManager()); + } + return manager; } } diff --git a/source-managers/src/main/java/com/dunctebot/sourcemanagers/pixeldrain/PixelDrainAudioTrack.java b/source-managers/src/main/java/com/dunctebot/sourcemanagers/pixeldrain/PixelDrainAudioTrack.java new file mode 100644 index 0000000..2af20c6 --- /dev/null +++ b/source-managers/src/main/java/com/dunctebot/sourcemanagers/pixeldrain/PixelDrainAudioTrack.java @@ -0,0 +1,24 @@ +package com.dunctebot.sourcemanagers.pixeldrain; + +import com.dunctebot.sourcemanagers.AbstractDuncteBotHttpSource; +import com.dunctebot.sourcemanagers.Mp3Track; +import com.sedmelluq.discord.lavaplayer.container.wav.WavAudioTrack; +import com.sedmelluq.discord.lavaplayer.tools.io.SeekableInputStream; +import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo; +import com.sedmelluq.discord.lavaplayer.track.InternalAudioTrack; + +public class PixelDrainAudioTrack extends Mp3Track { + public PixelDrainAudioTrack(AudioTrackInfo trackInfo, AbstractDuncteBotHttpSource manager) { + super(trackInfo, manager); + } + + @Override + protected InternalAudioTrack createAudioTrack(AudioTrackInfo trackInfo, SeekableInputStream stream) { + return new WavAudioTrack(trackInfo, stream); + } + + @Override + public String getPlaybackUrl() { + return String.format(PixeldrainAudioSourceManager.AUDIO_TEMPLATE, this.trackInfo.identifier); + } +} diff --git a/source-managers/src/main/java/com/dunctebot/sourcemanagers/pixeldrain/PixeldrainAudioSourceManager.java b/source-managers/src/main/java/com/dunctebot/sourcemanagers/pixeldrain/PixeldrainAudioSourceManager.java new file mode 100644 index 0000000..1885502 --- /dev/null +++ b/source-managers/src/main/java/com/dunctebot/sourcemanagers/pixeldrain/PixeldrainAudioSourceManager.java @@ -0,0 +1,131 @@ +package com.dunctebot.sourcemanagers.pixeldrain; + +import com.dunctebot.sourcemanagers.AbstractDuncteBotHttpSource; +import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; +import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; +import com.sedmelluq.discord.lavaplayer.tools.Units; +import com.sedmelluq.discord.lavaplayer.track.AudioItem; +import com.sedmelluq.discord.lavaplayer.track.AudioReference; +import com.sedmelluq.discord.lavaplayer.track.AudioTrack; +import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo; +import org.apache.commons.io.IOUtils; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +public class PixeldrainAudioSourceManager extends AbstractDuncteBotHttpSource { + private static final String PIXELDRAIN_LOOKUP_BASE = "https://pixeldrain.com/u/"; + + /* package */ static final String AUDIO_TEMPLATE = "https://pixeldrain.com/api/file/%s"; + private static final String THUMBNAIL_TEMPLATE = AUDIO_TEMPLATE + "/thumbnail"; + + @Override + public String getSourceName() { + return "pixeldrain"; + } + + @Override + public AudioItem loadItem(AudioPlayerManager manager, AudioReference reference) { + final var id = reference.getIdentifier(); + + if (id.startsWith(PIXELDRAIN_LOOKUP_BASE)) { + final var parts = id.split(PIXELDRAIN_LOOKUP_BASE); + + if (parts.length < 2) { + return null; + } + + final var identifier = parts[1]; + + try { + final var trackInfo = downloadInfo(identifier); + + return decodeTrack(trackInfo, null); + } catch (IOException e) { + throw new FriendlyException( + "Could not download pixeldrain track info", + FriendlyException.Severity.SUSPICIOUS, + e + ); + } + } + + return null; + } + + private AudioTrackInfo downloadInfo(String identifier) throws IOException { + final var document = loadHtml(identifier); + + if (document == null) { + notAvailable(); + } + +// System.out.println(document.select("meta[property]")); + + final var title = document.selectFirst("meta[property='og:title']").attr("content"); + final var type = document.selectFirst("meta[property='og:type']").attr("content"); + + if (!"music.song".equals(type)) { + throw new FriendlyException("Type " + type + " is currently not supported", FriendlyException.Severity.COMMON, null); + } + + System.out.println(type); + System.out.println(title); + + return new AudioTrackInfo( + title, + "Unknown artist", + Units.CONTENT_LENGTH_UNKNOWN, + identifier, + false, + PIXELDRAIN_LOOKUP_BASE + identifier, + String.format(THUMBNAIL_TEMPLATE, identifier), + null + ); + } + + private Document loadHtml(String identifier) throws IOException { + final var httpGet = new HttpGet(PIXELDRAIN_LOOKUP_BASE + identifier); + + try (final CloseableHttpResponse response = getHttpInterface().execute(httpGet)) { + final int statusCode = response.getStatusLine().getStatusCode(); + + if (statusCode != 200) { + if (statusCode == 404) { + return null; + } + + throw new IOException("Unexpected status code for pixeldrain page response: " + statusCode); + } + + final var html = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8); + + return Jsoup.parse(html); + } + } + + @Override + public boolean isTrackEncodable(AudioTrack track) { + return false; + } + + @Override + public void encodeTrack(AudioTrack track, DataOutput output) throws IOException { + // Nothing to encode + } + + @Override + public AudioTrack decodeTrack(AudioTrackInfo trackInfo, DataInput input) throws IOException { + return new PixelDrainAudioTrack(trackInfo, this); + } + + private void notAvailable() { + throw new FriendlyException("This item is not available", FriendlyException.Severity.COMMON, null); + } +} diff --git a/source-managers/src/test/java/LocalPlaybackTest.java b/source-managers/src/test/java/LocalPlaybackTest.java index 4b448bf..b3792a1 100644 --- a/source-managers/src/test/java/LocalPlaybackTest.java +++ b/source-managers/src/test/java/LocalPlaybackTest.java @@ -1,4 +1,5 @@ import com.dunctebot.sourcemanagers.elgato.streamdeck.StreamDeckAudioSourceManager; +import com.dunctebot.sourcemanagers.pixeldrain.PixeldrainAudioSourceManager; import com.sedmelluq.discord.lavaplayer.format.AudioDataFormat; import com.sedmelluq.discord.lavaplayer.format.AudioPlayerInputStream; import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; @@ -15,7 +16,7 @@ public class LocalPlaybackTest { public static void main(String[] args) throws Exception { - final var mngr = new StreamDeckAudioSourceManager(); + final var mngr = new PixeldrainAudioSourceManager(); AudioPlayerManager manager = new DefaultAudioPlayerManager(); @@ -25,10 +26,10 @@ public static void main(String[] args) throws Exception { AudioPlayer player = manager.createPlayer(); - player.setVolume(35); + player.setVolume(100); manager.loadItem( - "https://cdn.discordapp.com/attachments/340834322674089986/1242398908815118376/Fanfare_-_Show_Intro.streamDeckAudio?ex=664f0326&is=664db1a6&hm=9a4898f7301601b3bc14cfda4101aab0ed94cdfb5fe89d2a0917dc4e01514da6&", + "https://pixeldrain.com/u/WUJkkH3F", new FunctionalResultHandler(item -> { player.playTrack(item); }, playlist -> { diff --git a/source-managers/src/test/java/PixeldrainTest.java b/source-managers/src/test/java/PixeldrainTest.java new file mode 100644 index 0000000..a1f67a1 --- /dev/null +++ b/source-managers/src/test/java/PixeldrainTest.java @@ -0,0 +1,13 @@ +import com.dunctebot.sourcemanagers.pixeldrain.PixeldrainAudioSourceManager; +import com.sedmelluq.discord.lavaplayer.track.AudioReference; + +public class PixeldrainTest { + + public static void main(String[] args) { + final var id1 = "https://pixeldrain.com/u/WUJkkH3F"; + final var mngr = new PixeldrainAudioSourceManager(); + final var res1 = mngr.loadItem(null, new AudioReference(id1, "")); + + System.out.println(res1); + } +}