remove harcoded html tag, parses next chunks to find track
This commit is contained in:
1 parent
d6fa27923b
commit
c442619531
1 file changed
+101
-13
@@ -5,10 +5,8 @@ package me.bobert.netneutrality.music.source;
|
|||||||
* https://discord.gg/qUa6zNFZsd
|
* https://discord.gg/qUa6zNFZsd
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonParseException;
|
|
||||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
|
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
|
||||||
import com.sedmelluq.discord.lavaplayer.source.AudioSourceManager;
|
import com.sedmelluq.discord.lavaplayer.source.AudioSourceManager;
|
||||||
import com.sedmelluq.discord.lavaplayer.tools.DataFormatTools;
|
|
||||||
import com.sedmelluq.discord.lavaplayer.tools.ExceptionTools;
|
import com.sedmelluq.discord.lavaplayer.tools.ExceptionTools;
|
||||||
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
|
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
|
||||||
import com.sedmelluq.discord.lavaplayer.tools.JsonBrowser;
|
import com.sedmelluq.discord.lavaplayer.tools.JsonBrowser;
|
||||||
@@ -30,6 +28,7 @@ import java.io.DataInput;
|
|||||||
import java.io.DataOutput;
|
import java.io.DataOutput;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import static com.sedmelluq.discord.lavaplayer.tools.FriendlyException.Severity.SUSPICIOUS;
|
import static com.sedmelluq.discord.lavaplayer.tools.FriendlyException.Severity.SUSPICIOUS;
|
||||||
@@ -38,6 +37,10 @@ public class UdioAudioSourceManager implements AudioSourceManager {
|
|||||||
private static final Logger log = LogManager.getLogger(UdioAudioSourceManager.class);
|
private static final Logger log = LogManager.getLogger(UdioAudioSourceManager.class);
|
||||||
private static final String TRACK_URL_REGEX = "^https://www.udio.com/songs/[0-9A-Za-z]+$";
|
private static final String TRACK_URL_REGEX = "^https://www.udio.com/songs/[0-9A-Za-z]+$";
|
||||||
private static final Pattern trackUrlPattern = Pattern.compile(TRACK_URL_REGEX);
|
private static final Pattern trackUrlPattern = Pattern.compile(TRACK_URL_REGEX);
|
||||||
|
private static final Pattern NEXT_PUSH_PATTERN = Pattern.compile(
|
||||||
|
"self\\.__next_f\\.push\\(\\[(\\d+),\"(.*?)\"]\\)",
|
||||||
|
Pattern.DOTALL
|
||||||
|
);
|
||||||
private final HttpInterfaceManager httpInterfaceManager;
|
private final HttpInterfaceManager httpInterfaceManager;
|
||||||
|
|
||||||
public UdioAudioSourceManager() {
|
public UdioAudioSourceManager() {
|
||||||
@@ -120,24 +123,109 @@ public class UdioAudioSourceManager implements AudioSourceManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected JsonBrowser loadTrackInfoFromPageContent(String content) throws IOException {
|
protected JsonBrowser loadTrackInfoFromPageContent(String content) throws IOException {
|
||||||
String startTag = "self.__next_f.push([1,\"33:";
|
Matcher matcher = NEXT_PUSH_PATTERN.matcher(content);
|
||||||
String endTag = "\\n\"])";
|
while (matcher.find()) {
|
||||||
|
String payload = matcher.group(2);
|
||||||
|
JsonBrowser trackInfo = tryExtractTrackFromNextChunk(payload);
|
||||||
|
|
||||||
|
if (trackInfo != null) {
|
||||||
|
return trackInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String json = DataFormatTools.extractBetween(content, startTag, endTag);
|
|
||||||
if (json == null || json.isEmpty() || json.equals("null")) {
|
|
||||||
log.error("Track JSON not found in page");
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private JsonBrowser tryExtractTrackFromNextChunk(String payload) {
|
||||||
try {
|
try {
|
||||||
String unescapedJson = json.replace("\\", "");
|
int trackKeyIndex = payload.indexOf("\\\"track\\\":{");
|
||||||
JsonBrowser parsedJson = JsonBrowser.parse(unescapedJson);
|
if (trackKeyIndex < 0) {
|
||||||
|
|
||||||
return parsedJson.index(3).get("children").index(3).get("children").index(3).get("track");
|
|
||||||
} catch (JsonParseException e) {
|
|
||||||
log.error("Failed to parse track JSON: {}", json);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int objectStart = payload.indexOf('{', trackKeyIndex);
|
||||||
|
if (objectStart < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String escapedTrackJson = extractJsonObjectFromString(payload, objectStart);
|
||||||
|
if (escapedTrackJson == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String trackJson = unescapeJsonStringFragment(escapedTrackJson);
|
||||||
|
JsonBrowser track = JsonBrowser.parse(trackJson);
|
||||||
|
|
||||||
|
if (isValidTrack(track)) {
|
||||||
|
return track;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.debug("Skipping unparsable track payload fragment", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts a JSON object from a given string starting at the specified index. This method parses the string
|
||||||
|
* to locate and retrieve the JSON object, ensuring proper handling of nested structures and escaped characters.
|
||||||
|
*
|
||||||
|
* @param text The input string containing the JSON object to be extracted.
|
||||||
|
* @param startIndex The index at which to start searching for the JSON object within the input string.
|
||||||
|
* @return The extracted JSON object as a string, or {@code null} if no valid JSON object is found.
|
||||||
|
*/
|
||||||
|
private String extractJsonObjectFromString(String text, int startIndex) {
|
||||||
|
boolean escaped = false;
|
||||||
|
boolean inString = false;
|
||||||
|
int depth = 0;
|
||||||
|
|
||||||
|
for (int i = startIndex; i < text.length(); i++) {
|
||||||
|
char c = text.charAt(i);
|
||||||
|
|
||||||
|
if (escaped) {
|
||||||
|
escaped = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '\\') {
|
||||||
|
escaped = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '"') {
|
||||||
|
inString = !inString;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inString) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '{') {
|
||||||
|
depth++;
|
||||||
|
} else if (c == '}') {
|
||||||
|
depth--;
|
||||||
|
if (depth == 0) {
|
||||||
|
return text.substring(startIndex, i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String unescapeJsonStringFragment(String value) {
|
||||||
|
return value.replace("\\\"", "\"").replace("\\\\", "\\");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isValidTrack(JsonBrowser track) {
|
||||||
|
return track != null
|
||||||
|
&& !track.isNull()
|
||||||
|
&& !track.get("title").isNull()
|
||||||
|
&& !track.get("artist").isNull()
|
||||||
|
&& !track.get("duration").isNull()
|
||||||
|
&& !track.get("song_path").isNull()
|
||||||
|
&& !track.get("image_path").isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getArtworkUrlFromImagePath(JsonBrowser trackInfo) {
|
private String getArtworkUrlFromImagePath(JsonBrowser trackInfo) {
|
||||||
|
|||||||
Reference in new issue
Block a user