2020-11-12 21:19:45 +00:00
|
|
|
package me.kavin.piped.utils;
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.net.MalformedURLException;
|
|
|
|
import java.net.URI;
|
|
|
|
import java.net.URL;
|
|
|
|
import java.net.http.HttpRequest;
|
|
|
|
import java.net.http.HttpRequest.BodyPublishers;
|
|
|
|
import java.net.http.HttpResponse.BodyHandlers;
|
|
|
|
import java.util.List;
|
2020-11-17 05:34:50 +00:00
|
|
|
import java.util.concurrent.CompletableFuture;
|
2020-11-12 21:19:45 +00:00
|
|
|
import java.util.concurrent.TimeUnit;
|
2021-01-20 15:43:41 +00:00
|
|
|
import java.util.stream.Stream;
|
2020-11-12 21:19:45 +00:00
|
|
|
|
2020-11-25 05:26:25 +00:00
|
|
|
import org.apache.commons.lang3.StringUtils;
|
2020-11-17 05:34:50 +00:00
|
|
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
2020-11-12 21:19:45 +00:00
|
|
|
import org.json.JSONObject;
|
2020-12-14 07:11:42 +00:00
|
|
|
import org.schabi.newpipe.extractor.InfoItem;
|
2020-11-25 05:26:25 +00:00
|
|
|
import org.schabi.newpipe.extractor.ListExtractor.InfoItemsPage;
|
|
|
|
import org.schabi.newpipe.extractor.Page;
|
2020-11-12 21:19:45 +00:00
|
|
|
import org.schabi.newpipe.extractor.channel.ChannelInfo;
|
|
|
|
import org.schabi.newpipe.extractor.comments.CommentsInfo;
|
|
|
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
|
|
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
|
|
|
import org.schabi.newpipe.extractor.kiosk.KioskInfo;
|
2021-01-04 05:47:28 +00:00
|
|
|
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
2020-12-09 13:30:42 +00:00
|
|
|
import org.schabi.newpipe.extractor.search.SearchInfo;
|
2020-11-12 21:19:45 +00:00
|
|
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
|
|
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
|
|
|
|
2020-11-25 05:26:25 +00:00
|
|
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
2020-11-12 21:19:45 +00:00
|
|
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
|
|
|
import com.github.benmanes.caffeine.cache.LoadingCache;
|
|
|
|
|
|
|
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
|
|
|
import me.kavin.piped.consts.Constants;
|
|
|
|
import me.kavin.piped.utils.obj.Channel;
|
2020-11-25 05:26:25 +00:00
|
|
|
import me.kavin.piped.utils.obj.PipedStream;
|
2021-01-04 05:47:28 +00:00
|
|
|
import me.kavin.piped.utils.obj.Playlist;
|
2020-12-14 07:11:42 +00:00
|
|
|
import me.kavin.piped.utils.obj.SearchResults;
|
2020-11-12 21:19:45 +00:00
|
|
|
import me.kavin.piped.utils.obj.StreamItem;
|
|
|
|
import me.kavin.piped.utils.obj.Streams;
|
2021-01-04 05:47:28 +00:00
|
|
|
import me.kavin.piped.utils.obj.StreamsPage;
|
2020-11-12 21:19:45 +00:00
|
|
|
import me.kavin.piped.utils.obj.Subtitle;
|
2020-12-09 13:30:42 +00:00
|
|
|
import me.kavin.piped.utils.obj.search.SearchItem;
|
|
|
|
import me.kavin.piped.utils.obj.search.SearchStream;
|
2020-11-12 21:19:45 +00:00
|
|
|
|
|
|
|
public class ResponseHelper {
|
|
|
|
|
|
|
|
public static final LoadingCache<String, CommentsInfo> commentsCache = Caffeine.newBuilder()
|
|
|
|
.expireAfterWrite(1, TimeUnit.HOURS).maximumSize(1000)
|
|
|
|
.build(key -> CommentsInfo.getInfo("https://www.youtube.com/watch?v=" + key));
|
|
|
|
|
2021-01-12 08:15:09 +00:00
|
|
|
public static final byte[] streamsResponse(String videoId) throws Exception {
|
2020-11-17 05:34:50 +00:00
|
|
|
|
|
|
|
CompletableFuture<StreamInfo> futureStream = CompletableFuture.supplyAsync(() -> {
|
|
|
|
try {
|
|
|
|
return StreamInfo.getInfo("https://www.youtube.com/watch?v=" + videoId);
|
|
|
|
} catch (Exception e) {
|
|
|
|
ExceptionUtils.rethrow(e);
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
});
|
2020-11-12 21:19:45 +00:00
|
|
|
|
2020-11-17 05:34:50 +00:00
|
|
|
CompletableFuture<String> futureLBRY = CompletableFuture.supplyAsync(() -> {
|
|
|
|
try {
|
|
|
|
return getLBRYStreamURL(videoId);
|
|
|
|
} catch (Exception e) {
|
|
|
|
ExceptionUtils.rethrow(e);
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
});
|
2020-11-12 21:19:45 +00:00
|
|
|
|
|
|
|
final List<Subtitle> subtitles = new ObjectArrayList<>();
|
|
|
|
|
2020-11-17 05:34:50 +00:00
|
|
|
final StreamInfo info = futureStream.get();
|
|
|
|
|
2020-11-12 21:19:45 +00:00
|
|
|
info.getSubtitles().forEach(subtitle -> subtitles
|
|
|
|
.add(new Subtitle(rewriteURL(subtitle.getUrl()), subtitle.getFormat().getMimeType())));
|
|
|
|
|
2020-11-25 05:26:25 +00:00
|
|
|
final List<PipedStream> videoStreams = new ObjectArrayList<>();
|
|
|
|
final List<PipedStream> audioStreams = new ObjectArrayList<>();
|
2020-11-12 21:19:45 +00:00
|
|
|
|
2020-11-17 05:34:50 +00:00
|
|
|
final String lbryURL = futureLBRY.get();
|
2020-11-12 21:19:45 +00:00
|
|
|
|
|
|
|
if (lbryURL != null)
|
2021-01-04 05:47:28 +00:00
|
|
|
videoStreams.add(new PipedStream(lbryURL, "MP4", "LBRY", "video/mp4", false));
|
2020-11-12 21:19:45 +00:00
|
|
|
|
2021-01-20 15:35:13 +00:00
|
|
|
final String hls;
|
2020-11-17 05:34:50 +00:00
|
|
|
boolean livestream = false;
|
|
|
|
|
|
|
|
if ((hls = info.getHlsUrl()) != null && !hls.isEmpty())
|
|
|
|
livestream = true;
|
|
|
|
|
2021-01-20 15:35:13 +00:00
|
|
|
if (hls != null) {
|
|
|
|
|
2021-01-20 15:46:29 +00:00
|
|
|
java.util.stream.Stream<String> resp = Constants.h2client
|
2021-01-20 15:35:13 +00:00
|
|
|
.send(HttpRequest.newBuilder(URI.create(hls)).GET().build(), BodyHandlers.ofLines()).body();
|
|
|
|
ObjectArrayList<String> lines = new ObjectArrayList<>();
|
|
|
|
resp.forEach(line -> lines.add(line));
|
|
|
|
|
|
|
|
for (int i = lines.size() - 1; i > 2; i--) {
|
|
|
|
String line = lines.get(i);
|
|
|
|
if (line.startsWith("https://manifest.googlevideo.com")) {
|
|
|
|
String prevLine = lines.get(i - 1);
|
|
|
|
String height = StringUtils.substringBetween(prevLine, "RESOLUTION=", ",").split("x")[1];
|
|
|
|
int fps = Integer.parseInt(StringUtils.substringBetween(prevLine, "FRAME-RATE=", ","));
|
|
|
|
String quality = height + "p";
|
|
|
|
if (fps > 30)
|
|
|
|
quality += fps;
|
|
|
|
videoStreams.add(new PipedStream(line, "HLS", quality, "application/x-mpegURL", false));
|
|
|
|
}
|
|
|
|
}
|
2020-11-25 05:26:25 +00:00
|
|
|
}
|
|
|
|
|
2021-01-20 15:35:13 +00:00
|
|
|
if (!livestream) {
|
|
|
|
info.getVideoOnlyStreams()
|
|
|
|
.forEach(stream -> videoStreams
|
|
|
|
.add(new PipedStream(rewriteURL(stream.getUrl()), String.valueOf(stream.getFormat()),
|
|
|
|
stream.getResolution(), stream.getFormat().getMimeType(), true)));
|
|
|
|
info.getVideoStreams()
|
|
|
|
.forEach(stream -> videoStreams
|
|
|
|
.add(new PipedStream(rewriteURL(stream.getUrl()), String.valueOf(stream.getFormat()),
|
|
|
|
stream.getResolution(), stream.getFormat().getMimeType(), false)));
|
|
|
|
|
|
|
|
info.getAudioStreams()
|
|
|
|
.forEach(stream -> audioStreams
|
|
|
|
.add(new PipedStream(rewriteURL(stream.getUrl()), String.valueOf(stream.getFormat()),
|
|
|
|
stream.getAverageBitrate() + " kbps", stream.getFormat().getMimeType(), false)));
|
|
|
|
}
|
2020-11-12 21:19:45 +00:00
|
|
|
|
|
|
|
final List<StreamItem> relatedStreams = new ObjectArrayList<>();
|
|
|
|
|
|
|
|
info.getRelatedStreams().forEach(o -> {
|
|
|
|
StreamInfoItem item = (StreamInfoItem) o;
|
|
|
|
relatedStreams.add(new StreamItem(item.getUrl().substring(23), item.getName(),
|
|
|
|
rewriteURL(item.getThumbnailUrl()), item.getUploaderName(), item.getUploaderUrl().substring(23),
|
2021-01-04 05:47:28 +00:00
|
|
|
item.getTextualUploadDate(), item.getDuration(), item.getViewCount()));
|
2020-11-12 21:19:45 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
final Streams streams = new Streams(info.getName(), info.getDescription().getContent(),
|
|
|
|
info.getTextualUploadDate(), info.getUploaderName(), info.getUploaderUrl().substring(23),
|
|
|
|
rewriteURL(info.getUploaderAvatarUrl()), rewriteURL(info.getThumbnailUrl()), info.getDuration(),
|
|
|
|
info.getViewCount(), info.getLikeCount(), info.getDislikeCount(), audioStreams, videoStreams,
|
2020-11-17 05:34:50 +00:00
|
|
|
relatedStreams, subtitles, livestream, hls);
|
2020-11-12 21:19:45 +00:00
|
|
|
|
2021-01-12 08:15:09 +00:00
|
|
|
return Constants.mapper.writeValueAsBytes(streams);
|
2020-11-12 21:19:45 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-01-12 08:15:09 +00:00
|
|
|
public static final byte[] channelResponse(String channelId)
|
2020-11-12 21:19:45 +00:00
|
|
|
throws IOException, ExtractionException, InterruptedException {
|
|
|
|
|
|
|
|
final ChannelInfo info = ChannelInfo.getInfo("https://youtube.com/channel/" + channelId);
|
|
|
|
|
|
|
|
final List<StreamItem> relatedStreams = new ObjectArrayList<>();
|
|
|
|
|
|
|
|
info.getRelatedItems().forEach(o -> {
|
|
|
|
StreamInfoItem item = o;
|
|
|
|
relatedStreams.add(new StreamItem(item.getUrl().substring(23), item.getName(),
|
|
|
|
rewriteURL(item.getThumbnailUrl()), item.getUploaderName(), item.getUploaderUrl().substring(23),
|
2021-01-04 05:47:28 +00:00
|
|
|
item.getTextualUploadDate(), item.getDuration(), item.getViewCount()));
|
2020-11-12 21:19:45 +00:00
|
|
|
});
|
|
|
|
|
2020-11-25 05:26:25 +00:00
|
|
|
String nextpage = info.hasNextPage() ? info.getNextPage().getUrl() : null;
|
|
|
|
|
2020-11-25 06:41:06 +00:00
|
|
|
final Channel channel = new Channel(info.getName(), rewriteURL(info.getAvatarUrl()),
|
|
|
|
rewriteURL(info.getBannerUrl()), info.getDescription(), nextpage, relatedStreams);
|
2020-11-12 21:19:45 +00:00
|
|
|
|
2021-01-12 08:15:09 +00:00
|
|
|
return Constants.mapper.writeValueAsBytes(channel);
|
2020-11-12 21:19:45 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-01-12 08:15:09 +00:00
|
|
|
public static final byte[] channelPageResponse(String channelId, String url)
|
2020-11-25 05:26:25 +00:00
|
|
|
throws IOException, ExtractionException, InterruptedException {
|
|
|
|
|
|
|
|
InfoItemsPage<StreamInfoItem> page = ChannelInfo.getMoreItems(Constants.YOUTUBE_SERVICE,
|
|
|
|
"https://youtube.com/channel/" + channelId, new Page(url));
|
|
|
|
|
|
|
|
final List<StreamItem> relatedStreams = new ObjectArrayList<>();
|
|
|
|
|
|
|
|
page.getItems().forEach(o -> {
|
|
|
|
StreamInfoItem item = o;
|
|
|
|
relatedStreams.add(new StreamItem(item.getUrl().substring(23), item.getName(),
|
|
|
|
rewriteURL(item.getThumbnailUrl()), item.getUploaderName(), item.getUploaderUrl().substring(23),
|
2021-01-04 05:47:28 +00:00
|
|
|
item.getTextualUploadDate(), item.getDuration(), item.getViewCount()));
|
2020-11-25 05:26:25 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
String nextpage = page.hasNextPage() ? page.getNextPage().getUrl() : null;
|
|
|
|
|
2021-01-04 05:47:28 +00:00
|
|
|
final StreamsPage streamspage = new StreamsPage(nextpage, relatedStreams);
|
2020-11-25 05:26:25 +00:00
|
|
|
|
2021-01-12 08:15:09 +00:00
|
|
|
return Constants.mapper.writeValueAsBytes(streamspage);
|
2020-11-25 05:26:25 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-01-12 08:15:09 +00:00
|
|
|
public static final byte[] trendingResponse() throws ParsingException, ExtractionException, IOException {
|
2020-11-12 21:19:45 +00:00
|
|
|
|
|
|
|
final List<StreamItem> relatedStreams = new ObjectArrayList<>();
|
|
|
|
|
|
|
|
String url = Constants.YOUTUBE_SERVICE.getKioskList().getListLinkHandlerFactoryByType("Trending")
|
|
|
|
.getUrl("Trending");
|
|
|
|
KioskInfo info = KioskInfo.getInfo(Constants.YOUTUBE_SERVICE, url);
|
|
|
|
|
|
|
|
info.getRelatedItems().forEach(o -> {
|
|
|
|
StreamInfoItem item = o;
|
|
|
|
relatedStreams.add(new StreamItem(item.getUrl().substring(23), item.getName(),
|
|
|
|
rewriteURL(item.getThumbnailUrl()), item.getUploaderName(), item.getUploaderUrl().substring(23),
|
2021-01-04 05:47:28 +00:00
|
|
|
item.getTextualUploadDate(), item.getDuration(), item.getViewCount()));
|
2020-11-12 21:19:45 +00:00
|
|
|
});
|
|
|
|
|
2021-01-12 08:15:09 +00:00
|
|
|
return Constants.mapper.writeValueAsBytes(relatedStreams);
|
2020-11-12 21:19:45 +00:00
|
|
|
}
|
|
|
|
|
2021-01-12 08:15:09 +00:00
|
|
|
public static final byte[] playlistResponse(String playlistId)
|
2021-01-04 05:47:28 +00:00
|
|
|
throws IOException, ExtractionException, InterruptedException {
|
|
|
|
|
|
|
|
final PlaylistInfo info = PlaylistInfo.getInfo("https://www.youtube.com/playlist?list=" + playlistId);
|
|
|
|
|
|
|
|
final List<StreamItem> relatedStreams = new ObjectArrayList<>();
|
|
|
|
|
|
|
|
info.getRelatedItems().forEach(o -> {
|
|
|
|
StreamInfoItem item = o;
|
|
|
|
relatedStreams.add(new StreamItem(item.getUrl().substring(23), item.getName(),
|
|
|
|
rewriteURL(item.getThumbnailUrl()), item.getUploaderName(), item.getUploaderUrl().substring(23),
|
|
|
|
item.getTextualUploadDate(), item.getDuration(), item.getViewCount()));
|
|
|
|
});
|
|
|
|
|
|
|
|
String nextpage = info.hasNextPage() ? info.getNextPage().getUrl() : null;
|
|
|
|
|
|
|
|
final Playlist playlist = new Playlist(info.getName(), rewriteURL(info.getThumbnailUrl()),
|
|
|
|
rewriteURL(info.getBannerUrl()), nextpage, info.getUploaderName(), info.getUploaderUrl().substring(23),
|
|
|
|
rewriteURL(info.getUploaderAvatarUrl()), (int) info.getStreamCount(), relatedStreams);
|
|
|
|
|
2021-01-12 08:15:09 +00:00
|
|
|
return Constants.mapper.writeValueAsBytes(playlist);
|
2021-01-04 05:47:28 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-01-12 08:15:09 +00:00
|
|
|
public static final byte[] playlistPageResponse(String playlistId, String url)
|
2021-01-04 05:47:28 +00:00
|
|
|
throws IOException, ExtractionException, InterruptedException {
|
|
|
|
|
|
|
|
InfoItemsPage<StreamInfoItem> page = PlaylistInfo.getMoreItems(Constants.YOUTUBE_SERVICE,
|
|
|
|
"https://www.youtube.com/playlist?list=" + playlistId, new Page(url));
|
|
|
|
|
|
|
|
final List<StreamItem> relatedStreams = new ObjectArrayList<>();
|
|
|
|
|
|
|
|
page.getItems().forEach(o -> {
|
|
|
|
StreamInfoItem item = o;
|
|
|
|
relatedStreams.add(new StreamItem(item.getUrl().substring(23), item.getName(),
|
|
|
|
rewriteURL(item.getThumbnailUrl()), item.getUploaderName(), item.getUploaderUrl().substring(23),
|
|
|
|
item.getTextualUploadDate(), item.getDuration(), item.getViewCount()));
|
|
|
|
});
|
|
|
|
|
|
|
|
String nextpage = page.hasNextPage() ? page.getNextPage().getUrl() : null;
|
|
|
|
|
|
|
|
final StreamsPage streamspage = new StreamsPage(nextpage, relatedStreams);
|
|
|
|
|
2021-01-12 08:15:09 +00:00
|
|
|
return Constants.mapper.writeValueAsBytes(streamspage);
|
2021-01-04 05:47:28 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-01-12 08:15:09 +00:00
|
|
|
public static final byte[] suggestionsResponse(String query)
|
2020-11-25 05:26:25 +00:00
|
|
|
throws JsonProcessingException, IOException, ExtractionException {
|
|
|
|
|
|
|
|
return Constants.mapper
|
2021-01-12 08:15:09 +00:00
|
|
|
.writeValueAsBytes(Constants.YOUTUBE_SERVICE.getSuggestionExtractor().suggestionList(query));
|
2020-11-25 05:26:25 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-01-12 08:15:09 +00:00
|
|
|
public static final byte[] searchResponse(String q) throws IOException, ExtractionException, InterruptedException {
|
2020-12-09 13:30:42 +00:00
|
|
|
|
|
|
|
final SearchInfo info = SearchInfo.getInfo(Constants.YOUTUBE_SERVICE,
|
|
|
|
Constants.YOUTUBE_SERVICE.getSearchQHFactory().fromQuery(q));
|
|
|
|
|
|
|
|
ObjectArrayList<SearchItem> items = new ObjectArrayList<>();
|
|
|
|
|
|
|
|
info.getRelatedItems().forEach(item -> {
|
|
|
|
switch (item.getInfoType()) {
|
|
|
|
case STREAM:
|
|
|
|
StreamInfoItem stream = (StreamInfoItem) item;
|
|
|
|
items.add(new SearchStream(item.getName(), rewriteURL(item.getThumbnailUrl()),
|
|
|
|
item.getUrl().substring(23), stream.getViewCount(), stream.getDuration()));
|
|
|
|
break;
|
|
|
|
case CHANNEL:
|
|
|
|
items.add(new SearchItem(item.getName(), rewriteURL(item.getThumbnailUrl()),
|
|
|
|
item.getUrl().substring(23)));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-12-14 07:11:42 +00:00
|
|
|
Page nextpage = info.getNextPage();
|
|
|
|
|
|
|
|
return nextpage != null
|
2021-01-12 08:15:09 +00:00
|
|
|
? Constants.mapper.writeValueAsBytes(new SearchResults(nextpage.getUrl(), nextpage.getId(), items))
|
|
|
|
: Constants.mapper.writeValueAsBytes(new SearchResults(null, null, items));
|
2020-12-14 07:11:42 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-01-12 08:15:09 +00:00
|
|
|
public static final byte[] searchPageResponse(String q, String url, String id)
|
2020-12-14 07:11:42 +00:00
|
|
|
throws IOException, ExtractionException, InterruptedException {
|
|
|
|
|
|
|
|
InfoItemsPage<InfoItem> pages = SearchInfo.getMoreItems(Constants.YOUTUBE_SERVICE,
|
|
|
|
Constants.YOUTUBE_SERVICE.getSearchQHFactory().fromQuery(q), new Page(url, id));
|
|
|
|
|
|
|
|
ObjectArrayList<SearchItem> items = new ObjectArrayList<>();
|
|
|
|
|
|
|
|
pages.getItems().forEach(item -> {
|
|
|
|
switch (item.getInfoType()) {
|
|
|
|
case STREAM:
|
|
|
|
StreamInfoItem stream = (StreamInfoItem) item;
|
|
|
|
items.add(new SearchStream(item.getName(), rewriteURL(item.getThumbnailUrl()),
|
|
|
|
item.getUrl().substring(23), stream.getViewCount(), stream.getDuration()));
|
|
|
|
break;
|
|
|
|
case CHANNEL:
|
|
|
|
items.add(new SearchItem(item.getName(), rewriteURL(item.getThumbnailUrl()),
|
|
|
|
item.getUrl().substring(23)));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
Page nextpage = pages.getNextPage();
|
|
|
|
|
|
|
|
return nextpage != null
|
2021-01-12 08:15:09 +00:00
|
|
|
? Constants.mapper.writeValueAsBytes(new SearchResults(nextpage.getUrl(), nextpage.getId(), items))
|
|
|
|
: Constants.mapper.writeValueAsBytes(new SearchResults(null, null, items));
|
2020-12-09 13:30:42 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-01-12 08:15:09 +00:00
|
|
|
public static final byte[] registerResponse(String user, String pass) throws IOException {
|
2021-01-04 05:47:28 +00:00
|
|
|
|
2021-01-12 08:15:09 +00:00
|
|
|
return Constants.mapper.writeValueAsBytes(null);
|
2021-01-04 05:47:28 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-11-12 21:19:45 +00:00
|
|
|
private static final String getLBRYStreamURL(String videoId) throws IOException, InterruptedException {
|
|
|
|
|
|
|
|
String lbryId = new JSONObject(Constants.h2client.send(HttpRequest
|
|
|
|
.newBuilder(URI.create("https://api.lbry.com/yt/resolve?video_ids=" + URLUtils.silentEncode(videoId)))
|
|
|
|
.setHeader("User-Agent", Constants.USER_AGENT).build(), BodyHandlers.ofString()).body())
|
|
|
|
.getJSONObject("data").getJSONObject("videos").optString(videoId);
|
|
|
|
|
|
|
|
if (!lbryId.isEmpty())
|
|
|
|
return rewriteURL(
|
|
|
|
new JSONObject(
|
|
|
|
Constants.h2client.send(
|
|
|
|
HttpRequest.newBuilder(URI.create("https://api.lbry.tv/api/v1/proxy?m=get"))
|
|
|
|
.POST(BodyPublishers.ofString(String.valueOf(new JSONObject()
|
|
|
|
.put("jsonrpc", "2.0").put("method", "get").put("params",
|
|
|
|
new JSONObject().put("uri", "lbry://" + lbryId)
|
|
|
|
.put("save_file", true)))))
|
|
|
|
.build(),
|
|
|
|
BodyHandlers.ofString()).body()).getJSONObject("result")
|
|
|
|
.getString("streaming_url"));
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private static String rewriteURL(final String old) {
|
|
|
|
|
|
|
|
if (Constants.debug)
|
|
|
|
return old;
|
|
|
|
|
2020-12-09 13:29:12 +00:00
|
|
|
if (old == null || old.isEmpty())
|
|
|
|
return null;
|
|
|
|
|
2020-11-12 21:19:45 +00:00
|
|
|
URL url = null;
|
|
|
|
|
|
|
|
try {
|
|
|
|
url = new URL(old);
|
|
|
|
} catch (MalformedURLException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
|
|
|
|
final String host = url.getHost();
|
|
|
|
|
|
|
|
String query = url.getQuery();
|
|
|
|
|
2020-12-09 13:29:12 +00:00
|
|
|
boolean hasQuery = query != null;
|
2020-11-12 21:19:45 +00:00
|
|
|
|
|
|
|
String path = url.getPath();
|
|
|
|
|
|
|
|
path = path.replace("-rj", "-rw");
|
|
|
|
|
2020-12-09 13:29:12 +00:00
|
|
|
if (path.startsWith("/vi/") && !path.contains("_live")) {
|
|
|
|
path = path.replace("/vi/", "/vi_webp/").replace(".jpg", ".webp").replace("hq720", "mqdefault")
|
|
|
|
.replace("hqdefault", "mqdefault");
|
2020-12-14 07:11:42 +00:00
|
|
|
|
2020-12-09 13:29:12 +00:00
|
|
|
hasQuery = false;
|
|
|
|
}
|
2020-11-12 21:19:45 +00:00
|
|
|
|
2020-11-12 21:40:50 +00:00
|
|
|
return Constants.PROXY_PART + path + (hasQuery ? "?" + query + "&host=" : "?host=")
|
|
|
|
+ URLUtils.silentEncode(host);
|
2020-11-12 21:19:45 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|