2020-11-12 21:19:45 +00:00
|
|
|
package me.kavin.piped.utils;
|
|
|
|
|
2022-02-02 21:05:22 +00:00
|
|
|
import me.kavin.piped.consts.Constants;
|
2023-11-20 05:17:29 +00:00
|
|
|
import org.apache.commons.codec.binary.Hex;
|
2022-02-02 21:05:22 +00:00
|
|
|
import org.apache.commons.lang3.StringUtils;
|
2023-10-10 21:43:36 +00:00
|
|
|
import org.schabi.newpipe.extractor.Image;
|
2022-02-02 21:05:22 +00:00
|
|
|
|
|
|
|
import java.net.MalformedURLException;
|
|
|
|
import java.net.URL;
|
2021-03-04 14:14:52 +00:00
|
|
|
import java.net.URLDecoder;
|
2020-11-12 21:19:45 +00:00
|
|
|
import java.net.URLEncoder;
|
2022-02-02 21:05:22 +00:00
|
|
|
import java.nio.charset.StandardCharsets;
|
2023-11-20 05:17:29 +00:00
|
|
|
import java.security.MessageDigest;
|
|
|
|
import java.security.NoSuchAlgorithmException;
|
|
|
|
import java.util.Comparator;
|
2023-10-10 21:43:36 +00:00
|
|
|
import java.util.List;
|
2023-11-20 05:17:29 +00:00
|
|
|
import java.util.Set;
|
|
|
|
import java.util.TreeSet;
|
|
|
|
|
|
|
|
import static me.kavin.piped.consts.Constants.PROXY_HASH_SECRET;
|
2020-11-12 21:19:45 +00:00
|
|
|
|
|
|
|
public class URLUtils {
|
|
|
|
|
|
|
|
public static String silentEncode(String s) {
|
2021-02-24 09:52:29 +00:00
|
|
|
try {
|
2022-02-02 21:05:22 +00:00
|
|
|
return URLEncoder.encode(s, StandardCharsets.UTF_8);
|
2021-02-24 09:52:29 +00:00
|
|
|
} catch (Exception e) {
|
|
|
|
// ignored
|
|
|
|
}
|
|
|
|
return s;
|
2020-11-12 21:19:45 +00:00
|
|
|
}
|
2021-03-04 14:14:52 +00:00
|
|
|
|
|
|
|
public static String silentDecode(String s) {
|
|
|
|
try {
|
2022-02-02 21:05:22 +00:00
|
|
|
return URLDecoder.decode(s, StandardCharsets.UTF_8);
|
2021-03-04 14:14:52 +00:00
|
|
|
} catch (Exception e) {
|
|
|
|
// ignored
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
2022-02-02 21:05:22 +00:00
|
|
|
|
|
|
|
public static String substringYouTube(String s) {
|
|
|
|
return StringUtils.isEmpty(s) ? null : StringUtils.substringAfter(s, "youtube.com");
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String rewriteURL(final String old) {
|
2022-04-25 06:42:59 +00:00
|
|
|
return rewriteURL(old, Constants.IMAGE_PROXY_PART);
|
|
|
|
}
|
|
|
|
|
2023-10-10 21:43:36 +00:00
|
|
|
public static String getLastThumbnail(final List<Image> thumbnails) {
|
|
|
|
return thumbnails.isEmpty() ? null : rewriteURL(thumbnails.getLast().getUrl());
|
|
|
|
}
|
|
|
|
|
2022-04-25 06:42:59 +00:00
|
|
|
public static String rewriteVideoURL(final String old) {
|
|
|
|
return rewriteURL(old, Constants.PROXY_PART);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String rewriteURL(final String old, final String proxy) {
|
2022-02-02 21:05:22 +00:00
|
|
|
|
|
|
|
if (StringUtils.isEmpty(old)) return null;
|
|
|
|
|
|
|
|
URL url = null;
|
|
|
|
try {
|
|
|
|
url = new URL(old);
|
|
|
|
} catch (MalformedURLException e) {
|
|
|
|
ExceptionHandler.handle(e);
|
|
|
|
}
|
|
|
|
assert url != null;
|
|
|
|
|
|
|
|
final String host = url.getHost();
|
|
|
|
|
|
|
|
String query = url.getQuery();
|
|
|
|
|
|
|
|
boolean hasQuery = query != null;
|
|
|
|
|
2023-11-20 05:17:29 +00:00
|
|
|
Comparator<List<String>> listComparator = (o1, o2) -> {
|
|
|
|
for (int i = 0; i < Math.min(o1.size(), o2.size()); i++) {
|
|
|
|
int result = o1.get(i).compareTo(o2.get(i));
|
|
|
|
if (result != 0) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Integer.compare(o1.size(), o2.size()); // compare list sizes if all elements are equal
|
|
|
|
};
|
|
|
|
|
|
|
|
Set<List<String>> queryPairs = new TreeSet<>(listComparator);
|
|
|
|
|
|
|
|
if (hasQuery) {
|
|
|
|
String[] pairs = query.split("&");
|
|
|
|
|
|
|
|
for (String pair : pairs) {
|
|
|
|
int idx = pair.indexOf("=");
|
|
|
|
queryPairs.add(List.of(
|
|
|
|
silentDecode(pair.substring(0, idx)),
|
|
|
|
silentDecode(pair.substring(idx + 1))
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// look for host param, and add it if it doesn't exist
|
|
|
|
boolean hasHost = false;
|
|
|
|
for (List<String> pair : queryPairs) {
|
|
|
|
if (pair.get(0).equals("host")) {
|
|
|
|
hasHost = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!hasHost) {
|
|
|
|
queryPairs.add(List.of("host", host));
|
|
|
|
}
|
|
|
|
|
2023-11-20 08:31:19 +00:00
|
|
|
String path = url.getPath();
|
|
|
|
|
|
|
|
if (path.contains("=")) {
|
|
|
|
path = StringUtils.substringBefore(path, "=") + "=" + StringUtils.substringAfter(path, "=").replace("-rj", "-rw");
|
|
|
|
}
|
|
|
|
|
2023-11-20 05:17:29 +00:00
|
|
|
if (PROXY_HASH_SECRET != null)
|
|
|
|
try {
|
|
|
|
MessageDigest md = MessageDigest.getInstance("BLAKE3-256");
|
|
|
|
for (List<String> pair : queryPairs) {
|
|
|
|
md.update(pair.get(0).getBytes(StandardCharsets.UTF_8));
|
|
|
|
md.update(pair.get(1).getBytes(StandardCharsets.UTF_8));
|
|
|
|
}
|
|
|
|
|
2023-11-20 08:31:19 +00:00
|
|
|
md.update(path.getBytes(StandardCharsets.UTF_8));
|
|
|
|
|
2023-11-20 05:17:29 +00:00
|
|
|
md.update(PROXY_HASH_SECRET);
|
|
|
|
|
|
|
|
queryPairs.add(List.of("qhash", Hex.encodeHexString(md.digest()).substring(0, 8)));
|
|
|
|
} catch (NoSuchAlgorithmException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
|
|
|
|
String newUrl = proxy + path;
|
|
|
|
|
|
|
|
StringBuilder qstring = null;
|
|
|
|
|
2023-11-20 06:09:26 +00:00
|
|
|
for (List<String> pair : queryPairs) {
|
|
|
|
if (qstring == null) {
|
|
|
|
qstring = new StringBuilder();
|
|
|
|
} else {
|
|
|
|
qstring.append("&");
|
2023-11-20 05:17:29 +00:00
|
|
|
}
|
2023-11-20 06:09:26 +00:00
|
|
|
|
2023-11-20 08:31:19 +00:00
|
|
|
qstring.append(silentEncode(pair.get(0)));
|
2023-11-20 06:09:26 +00:00
|
|
|
qstring.append("=");
|
2023-11-20 08:31:19 +00:00
|
|
|
qstring.append(silentEncode(pair.get(1)));
|
2023-11-20 05:17:29 +00:00
|
|
|
}
|
|
|
|
|
2023-11-20 05:46:57 +00:00
|
|
|
newUrl += "?" + qstring;
|
2023-11-20 05:17:29 +00:00
|
|
|
|
|
|
|
return newUrl;
|
2022-02-02 21:05:22 +00:00
|
|
|
|
|
|
|
}
|
2020-11-12 21:19:45 +00:00
|
|
|
}
|