Skip to content

Commit

Permalink
beta
Browse files Browse the repository at this point in the history
  • Loading branch information
appujet committed Oct 12, 2024
1 parent 97c790d commit 9df90f0
Show file tree
Hide file tree
Showing 9 changed files with 295 additions and 207 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,18 @@
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
import com.sedmelluq.discord.lavaplayer.track.BasicAudioPlaylist;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;


import java.util.List;

public class ExtendedAudioPlaylist extends BasicAudioPlaylist {

@NotNull
protected final Type type;
@Nullable
protected final String url;
@Nullable
protected final String artworkURL;
@Nullable
protected final String author;
@Nullable
protected final Integer totalTracks;
protected final @NotNull String url;
protected final @NotNull String artworkURL;
protected final @NotNull String author;
protected final @NotNull Integer totalTracks;

public ExtendedAudioPlaylist(String name, List<AudioTrack> tracks, @NotNull Type type, @NotNull String url, @NotNull String artworkURL, @NotNull String author, @NotNull Integer totalTracks) {
super(name, tracks, null, false);
Expand All @@ -34,23 +30,19 @@ public Type getType() {
return type;
}

@Nullable
public String getUrl() {
public @NotNull String getUrl() {
return this.url;
}

@Nullable
public String getArtworkURL() {
public @NotNull String getArtworkURL() {
return this.artworkURL;
}

@Nullable
public String getAuthor() {
public @NotNull String getAuthor() {
return this.author;
}

@Nullable
public Integer getTotalTracks() {
public @NotNull Integer getTotalTracks() {
return this.totalTracks;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,40 @@

import com.sedmelluq.discord.lavaplayer.source.AudioSourceManager;
import com.sedmelluq.discord.lavaplayer.tools.ExceptionTools;
import com.sedmelluq.discord.lavaplayer.tools.JsonBrowser;
import com.sedmelluq.discord.lavaplayer.tools.http.HttpContextFilter;
import com.sedmelluq.discord.lavaplayer.tools.io.HttpClientTools;
import com.sedmelluq.discord.lavaplayer.tools.io.HttpConfigurable;
import com.sedmelluq.discord.lavaplayer.tools.io.HttpInterface;
import com.sedmelluq.discord.lavaplayer.tools.io.HttpInterfaceManager;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.function.Consumer;
import java.util.function.Function;


public abstract class ExtendedAudioSourceManager implements AudioSourceManager, HttpConfigurable {
public static final Logger log = LoggerFactory.getLogger(ExtendedAudioSourceManager.class);
protected final HttpInterfaceManager httpInterfaceManager;

public static String BASE_API = null;
private static final String BASE_API_URL = "https://www.jiosaavn.com/api.php?";
public ExtendedAudioSourceManager () {
this(true);
}
Expand All @@ -42,6 +56,48 @@ public HttpInterface getHttpInterface() {
return httpInterfaceManager.getInterface();
}

public JsonBrowser fetchJson(String pageURl) {
final HttpGet httpGet = new HttpGet(BASE_API + pageURl);
try (final CloseableHttpResponse response = this.getHttpInterface().execute(httpGet)) {
final String content = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
return JsonBrowser.parse(content);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

public JsonBrowser fetchJson(String endpoint, String[] params, String context) {
try {
URI uri = getUri(endpoint, params, context);
final HttpGet httpGet = new HttpGet(uri);
try (final CloseableHttpResponse response = this.getHttpInterface().execute(httpGet)) {
final String content = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
//log.info("Response from API: {}", content);
return JsonBrowser.parse(content);
}
} catch (Exception e) {
throw new RuntimeException("Error fetching JSON from JioSaavn API", e);
}
}

private static URI getUri(String endpoint, String[] params, String context) throws URISyntaxException {
URIBuilder uriBuilder = new URIBuilder(BASE_API_URL);
uriBuilder.addParameter("__call", endpoint);
uriBuilder.addParameter("_format", "json");
uriBuilder.addParameter("_marker", "0");
uriBuilder.addParameter("api_version", "4");
uriBuilder.addParameter("ctx", context != null ? context : "web6dot0");

if (params != null) {
for (int i = 0; i < params.length; i += 2) {
if (i + 1 < params.length) {
uriBuilder.addParameter(params[i], params[i + 1]);
}
}
}
return uriBuilder.build();
}

@Override
public void shutdown() {
ExceptionTools.closeWithWarnings(httpInterfaceManager);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,19 @@ public void process(LocalAudioTrackExecutor executor) throws Exception {

protected void loadStream(LocalAudioTrackExecutor localExecutor, HttpInterface httpInterface) throws Exception {
final String trackUrl = getPlaybackUrl();
try (PersistentHttpStream stream = new PersistentHttpStream(httpInterface, new URI(trackUrl), this.getTrackDuration())) {
try (final var stream = this
.wrapStream(new PersistentHttpStream(httpInterface, new URI(trackUrl), this.getTrackDuration()))) {
processDelegate(createAudioTrack(this.trackInfo, stream), localExecutor);
} catch (Exception e) {
log.error("Failed to load track from URL: {}", trackUrl, e);
throw e;
}
}


protected SeekableInputStream wrapStream(SeekableInputStream stream) {
return stream;
}

protected InternalAudioTrack createAudioTrack(AudioTrackInfo trackInfo, SeekableInputStream stream) {
return new MpegAudioTrack(trackInfo, stream);
}
Expand Down
111 changes: 110 additions & 1 deletion main/src/main/java/com/github/appujet/jiosaavn/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,85 @@
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Base64;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Utils {

private static final String KEY = "38346591";
private static final String ALGORITHM = "DES/ECB/NoPadding";
private static final String[] QUALITIES = { "_320", "_160", "_96", "_48", "_12" };

// Regular expressions for extracting tokens
private static final Pattern SONG_PATTERN = Pattern.compile("jiosaavn\\.com/song/[^/]+/([^/]+)$");
private static final Pattern ARTIST_PATTERN = Pattern.compile("jiosaavn\\.com/artist/[^/]+/([^/]+)$");
private static final Pattern ALBUM_PATTERN = Pattern.compile("jiosaavn\\.com/album/[^/]+/([^/]+)$");
private static final Pattern PLAYLIST_PATTERN = Pattern.compile("jiosaavn\\.com/(?:featured|s/playlist)/[^/]+/([^/]+)$");

/**
* Extracts a song token from a JioSaavn song URL.
*
* @param url The song URL.
* @return The song token or null if not found.
*/
public static String extractSongToken(String url) {
return extractToken(url, SONG_PATTERN);
}

/**
* Extracts an artist token from a JioSaavn artist URL.
*
* @param url The artist URL.
* @return The artist token or null if not found.
*/
public static String extractArtistToken(String url) {
return extractToken(url, ARTIST_PATTERN);
}

/**
* Extracts an album token from a JioSaavn album URL.
*
* @param url The album URL.
* @return The album token or null if not found.
*/
public static String extractAlbumToken(String url) {
return extractToken(url, ALBUM_PATTERN);
}

/**
* Extracts a playlist token from a JioSaavn playlist URL.
*
* @param url The playlist URL.
* @return The playlist token or null if not found.
*/
public static String extractPlaylistToken(String url) {
return extractToken(url, PLAYLIST_PATTERN);
}

/**
* Extracts a token using the provided pattern.
*
* @param url The URL to extract the token from.
* @param pattern The regex pattern to match the token.
* @return The token if found, or null if not.
*/
private static String extractToken(String url, Pattern pattern) {
if (url == null || url.isEmpty()) {
return null;
}

Matcher matcher = pattern.matcher(url);
if (matcher.find()) {
return matcher.group(1); // Return the first captured group
}
return null;
}
public static JsonBrowser fetchJson(String pageURl, ExtendedAudioSourceManager sourceManager) {
final HttpGet httpGet = new HttpGet(pageURl);
try (final CloseableHttpResponse response = sourceManager.getHttpInterface().execute(httpGet)) {
Expand All @@ -19,4 +93,39 @@ public static JsonBrowser fetchJson(String pageURl, ExtendedAudioSourceManager s
throw new RuntimeException(e);
}
}
}
/**
* Generates a download link by decrypting the encrypted media URL.
*
* @param encryptedMediaUrl The encrypted media URL.
* @return The download link or null if not valid.
*/
public static String getDownloadLink(String encryptedMediaUrl) {
if (encryptedMediaUrl == null || encryptedMediaUrl.isEmpty())
return null;

try {
byte[] encryptedBytes = Base64.getDecoder().decode(encryptedMediaUrl);
Key key = new SecretKeySpec(KEY.getBytes(), "DES");
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);

byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
String decryptedLink = new String(decryptedBytes).trim();
System.out.println("Decrypted Link: " + decryptedLink);
for (String quality : QUALITIES) {
String downloadUrl = decryptedLink.replace("_96", quality);
if (isValidUrl(downloadUrl)) {
return downloadUrl;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

// Helper method to check if a URL is valid
private static boolean isValidUrl(String url) {
return url.startsWith("https://aac.saavncdn.com/") && url.endsWith(".mp4");
}
}
Loading

0 comments on commit 9df90f0

Please sign in to comment.