From 015f392a6f86ada5e9af55af6e5bb95362eedf13 Mon Sep 17 00:00:00 2001 From: topi314 Date: Wed, 20 Dec 2023 12:59:04 +0100 Subject: [PATCH] cache deezer api token & license token --- .../deezer/DeezerAudioSourceManager.java | 45 +++++++++++++++++++ .../lavasrc/deezer/DeezerAudioTrack.java | 36 +++------------ 2 files changed, 51 insertions(+), 30 deletions(-) diff --git a/main/src/main/java/com/github/topi314/lavasrc/deezer/DeezerAudioSourceManager.java b/main/src/main/java/com/github/topi314/lavasrc/deezer/DeezerAudioSourceManager.java index 5fe2b16a..74516dd8 100644 --- a/main/src/main/java/com/github/topi314/lavasrc/deezer/DeezerAudioSourceManager.java +++ b/main/src/main/java/com/github/topi314/lavasrc/deezer/DeezerAudioSourceManager.java @@ -13,8 +13,10 @@ import com.sedmelluq.discord.lavaplayer.tools.io.HttpInterface; import com.sedmelluq.discord.lavaplayer.tools.io.HttpInterfaceManager; import com.sedmelluq.discord.lavaplayer.track.*; +import kotlin.Pair; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.HttpClientBuilder; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -25,13 +27,17 @@ import java.io.IOException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; +import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.function.Function; import java.util.regex.Pattern; +import java.util.stream.Collectors; public class DeezerAudioSourceManager extends ExtendedAudioSourceManager implements HttpConfigurable, AudioSearchManager { @@ -49,6 +55,9 @@ public class DeezerAudioSourceManager extends ExtendedAudioSourceManager impleme private final String masterDecryptionKey; private final HttpInterfaceManager httpInterfaceManager; + private String apiToken; + private String licenseToken; + private Instant expires; public DeezerAudioSourceManager(String masterDecryptionKey) { if (masterDecryptionKey == null || masterDecryptionKey.isEmpty()) { @@ -56,6 +65,42 @@ public DeezerAudioSourceManager(String masterDecryptionKey) { } this.masterDecryptionKey = masterDecryptionKey; this.httpInterfaceManager = HttpClientTools.createDefaultThreadLocalManager(); + this.expires = Instant.ofEpochMilli(0); + } + + private void refreshSession() throws IOException{ + var getSessionID = new HttpPost(DeezerAudioSourceManager.PRIVATE_API_BASE + "?method=deezer.ping&input=3&api_version=1.0&api_token="); + var json = LavaSrcTools.fetchResponseAsJson(this.getHttpInterface(), getSessionID); + + checkResponse(json, "Failed to get session ID: "); + var sessionID = json.get("results").get("SESSION").text(); + + var getUserToken = new HttpPost(DeezerAudioSourceManager.PRIVATE_API_BASE + "?method=deezer.getUserData&input=3&api_version=1.0&api_token="); + getUserToken.setHeader("Cookie", "sid=" + sessionID); + json = LavaSrcTools.fetchResponseAsJson(this.getHttpInterface(), getUserToken); + + checkResponse(json, "Failed to get user token: "); + this.licenseToken = json.get("results").get("USER").get("OPTIONS").get("license_token").text(); + this.apiToken = json.get("results").get("checkForm").text(); + this.expires = Instant.now().plus(3600, ChronoUnit.SECONDS); + } + + public Pair getTokens() throws IOException{ + if (Instant.now().isAfter(this.expires)) { + this.refreshSession(); + } + return new Pair<>(this.apiToken, this.licenseToken); + } + + static void checkResponse(JsonBrowser json, String message) throws IllegalStateException { + if (json == null) { + throw new IllegalStateException(message + "No response"); + } + var errors = json.get("data").index(0).get("errors").values(); + if (!errors.isEmpty()) { + var errorsStr = errors.stream().map(error -> error.get("code").text() + ": " + error.get("message").text()).collect(Collectors.joining(", ")); + throw new IllegalStateException(message + errorsStr); + } } @NotNull diff --git a/main/src/main/java/com/github/topi314/lavasrc/deezer/DeezerAudioTrack.java b/main/src/main/java/com/github/topi314/lavasrc/deezer/DeezerAudioTrack.java index d1ddf4cf..da8f8d01 100644 --- a/main/src/main/java/com/github/topi314/lavasrc/deezer/DeezerAudioTrack.java +++ b/main/src/main/java/com/github/topi314/lavasrc/deezer/DeezerAudioTrack.java @@ -36,46 +36,22 @@ public DeezerAudioTrack(AudioTrackInfo trackInfo, String albumName, String album } private URI getTrackMediaURI() throws IOException, URISyntaxException { - var getSessionID = new HttpPost(DeezerAudioSourceManager.PRIVATE_API_BASE + "?method=deezer.ping&input=3&api_version=1.0&api_token="); - var json = LavaSrcTools.fetchResponseAsJson(this.sourceManager.getHttpInterface(), getSessionID); - - this.checkResponse(json, "Failed to get session ID: "); - var sessionID = json.get("results").get("SESSION").text(); - - var getUserToken = new HttpPost(DeezerAudioSourceManager.PRIVATE_API_BASE + "?method=deezer.getUserData&input=3&api_version=1.0&api_token="); - getUserToken.setHeader("Cookie", "sid=" + sessionID); - json = LavaSrcTools.fetchResponseAsJson(this.sourceManager.getHttpInterface(), getUserToken); - - this.checkResponse(json, "Failed to get user token: "); - var userLicenseToken = json.get("results").get("USER").get("OPTIONS").get("license_token").text(); - var apiToken = json.get("results").get("checkForm").text(); - - var getTrackToken = new HttpPost(DeezerAudioSourceManager.PRIVATE_API_BASE + "?method=song.getData&input=3&api_version=1.0&api_token=" + apiToken); + var tokens = this.sourceManager.getTokens(); + var getTrackToken = new HttpPost(DeezerAudioSourceManager.PRIVATE_API_BASE + "?method=song.getData&input=3&api_version=1.0&api_token=" + tokens.getFirst()); getTrackToken.setEntity(new StringEntity("{\"sng_id\":\"" + this.trackInfo.identifier + "\"}", ContentType.APPLICATION_JSON)); - json = LavaSrcTools.fetchResponseAsJson(this.sourceManager.getHttpInterface(), getTrackToken); + var json = LavaSrcTools.fetchResponseAsJson(this.sourceManager.getHttpInterface(), getTrackToken); - this.checkResponse(json, "Failed to get track token: "); + DeezerAudioSourceManager.checkResponse(json, "Failed to get track token: "); var trackToken = json.get("results").get("TRACK_TOKEN").text(); var getMediaURL = new HttpPost(DeezerAudioSourceManager.MEDIA_BASE + "/get_url"); - getMediaURL.setEntity(new StringEntity("{\"license_token\":\"" + userLicenseToken + "\",\"media\": [{\"type\": \"FULL\",\"formats\": [{\"cipher\": \"BF_CBC_STRIPE\", \"format\": \"MP3_128\"}]}],\"track_tokens\": [\"" + trackToken + "\"]}", ContentType.APPLICATION_JSON)); + getMediaURL.setEntity(new StringEntity("{\"license_token\":\"" + tokens.getSecond() + "\",\"media\": [{\"type\": \"FULL\",\"formats\": [{\"cipher\": \"BF_CBC_STRIPE\", \"format\": \"MP3_128\"}]}],\"track_tokens\": [\"" + trackToken + "\"]}", ContentType.APPLICATION_JSON)); json = LavaSrcTools.fetchResponseAsJson(this.sourceManager.getHttpInterface(), getMediaURL); - this.checkResponse(json, "Failed to get media URL: "); + DeezerAudioSourceManager.checkResponse(json, "Failed to get media URL: "); return new URI(json.get("data").index(0).get("media").index(0).get("sources").index(0).get("url").text()); } - private void checkResponse(JsonBrowser json, String message) throws IllegalStateException { - if (json == null) { - throw new IllegalStateException(message + "No response"); - } - var errors = json.get("data").index(0).get("errors").values(); - if (!errors.isEmpty()) { - var errorsStr = errors.stream().map(error -> error.get("code").text() + ": " + error.get("message").text()).collect(Collectors.joining(", ")); - throw new IllegalStateException(message + errorsStr); - } - } - private byte[] getTrackDecryptionKey() throws NoSuchAlgorithmException { var md5 = Hex.encodeHex(MessageDigest.getInstance("MD5").digest(this.trackInfo.identifier.getBytes()), true); var master_key = this.sourceManager.getMasterDecryptionKey().getBytes();