Channel Pages and search suggestions.

This commit is contained in:
FireMasterK 2020-11-25 10:56:25 +05:30
parent f3ab50402c
commit 9527ad4133
No known key found for this signature in database
GPG key ID: 8DFF5DD33E93DB58
6 changed files with 131 additions and 20 deletions

View file

@ -20,8 +20,6 @@ public class Main {
public static void main(String[] args) throws Exception {
System.setProperty("file.encoding", "UTF-8");
// SyndFeed feed = new SyndFeedInput().build(new XmlReader(new FileInputStream("pubsub.xml")));
//
// feed.getEntries().forEach(entry -> {
@ -97,6 +95,35 @@ public class Main {
});
routes.get("/nextpage/channels/{channelId}", (req, res) -> {
QueryStringDecoder query = new QueryStringDecoder(req.uri());
try {
return writeResponse(res, ResponseHelper.channelPageResponse(req.param("channelId"),
query.parameters().get("url").get(0)), 200, "public, max-age=3600");
} catch (Exception e) {
e.printStackTrace();
return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private");
}
});
routes.get("/suggestions", (req, res) -> {
QueryStringDecoder query = new QueryStringDecoder(req.uri());
try {
return writeResponse(res,
ResponseHelper.suggestionsResponse(query.parameters().get("query").get(0)), 200,
"public, max-age=600");
} catch (Exception e) {
e.printStackTrace();
return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private");
}
});
routes.get("/trending", (req, res) -> {
try {

View file

@ -11,23 +11,29 @@ import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.json.JSONObject;
import org.schabi.newpipe.extractor.ListExtractor.InfoItemsPage;
import org.schabi.newpipe.extractor.Page;
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;
import org.schabi.newpipe.extractor.stream.Stream;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import com.fasterxml.jackson.core.JsonProcessingException;
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;
import me.kavin.piped.utils.obj.Stream;
import me.kavin.piped.utils.obj.ChannelPage;
import me.kavin.piped.utils.obj.PipedStream;
import me.kavin.piped.utils.obj.StreamItem;
import me.kavin.piped.utils.obj.Streams;
import me.kavin.piped.utils.obj.Subtitle;
@ -65,13 +71,13 @@ public class ResponseHelper {
info.getSubtitles().forEach(subtitle -> subtitles
.add(new Subtitle(rewriteURL(subtitle.getUrl()), subtitle.getFormat().getMimeType())));
final List<Stream> videoStreams = new ObjectArrayList<>();
final List<Stream> audioStreams = new ObjectArrayList<>();
final List<PipedStream> videoStreams = new ObjectArrayList<>();
final List<PipedStream> audioStreams = new ObjectArrayList<>();
final String lbryURL = futureLBRY.get();
if (lbryURL != null)
videoStreams.add(new Stream(lbryURL, "MP4", "LBRY", "video/mp4"));
videoStreams.add(new PipedStream(lbryURL, "MP4", "LBRY", "video/mp4"));
String hls = null;
boolean livestream = false;
@ -79,14 +85,32 @@ public class ResponseHelper {
if ((hls = info.getHlsUrl()) != null && !hls.isEmpty())
livestream = true;
info.getVideoOnlyStreams().forEach(stream -> videoStreams.add(new Stream(rewriteURL(stream.getUrl()),
long minexpire = Long.MAX_VALUE;
ObjectArrayList<Stream> allStreams = new ObjectArrayList<>();
allStreams.addAll(info.getVideoStreams());
allStreams.addAll(info.getAudioStreams());
allStreams.addAll(info.getVideoOnlyStreams());
for (Stream stream : allStreams) {
long expire = Long.parseLong(StringUtils.substringBetween(stream.getUrl(), "expire=", "&"));
if (expire < minexpire)
minexpire = expire;
}
info.getVideoOnlyStreams().forEach(stream -> videoStreams.add(new PipedStream(rewriteURL(stream.getUrl()),
String.valueOf(stream.getFormat()), stream.getResolution(), stream.getFormat().getMimeType())));
info.getVideoStreams().forEach(stream -> videoStreams.add(new Stream(rewriteURL(stream.getUrl()),
info.getVideoStreams().forEach(stream -> videoStreams.add(new PipedStream(rewriteURL(stream.getUrl()),
String.valueOf(stream.getFormat()), stream.getResolution(), stream.getFormat().getMimeType())));
info.getAudioStreams().forEach(
stream -> audioStreams.add(new Stream(rewriteURL(stream.getUrl()), String.valueOf(stream.getFormat()),
stream.getAverageBitrate() + " kbps", stream.getFormat().getMimeType())));
info.getAudioStreams()
.forEach(stream -> audioStreams
.add(new PipedStream(rewriteURL(stream.getUrl()), String.valueOf(stream.getFormat()),
stream.getAverageBitrate() + " kbps", stream.getFormat().getMimeType())));
final List<StreamItem> relatedStreams = new ObjectArrayList<>();
@ -121,13 +145,38 @@ public class ResponseHelper {
item.getDuration(), item.getViewCount()));
});
String nextpage = info.hasNextPage() ? info.getNextPage().getUrl() : null;
final Channel channel = new Channel(info.getName(), info.getAvatarUrl(), info.getBannerUrl(),
info.getDescription(), relatedStreams);
info.getDescription(), nextpage, relatedStreams);
return Constants.mapper.writeValueAsString(channel);
}
public static final String channelPageResponse(String channelId, String url)
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),
item.getDuration(), item.getViewCount()));
});
String nextpage = page.hasNextPage() ? page.getNextPage().getUrl() : null;
final ChannelPage channelpage = new ChannelPage(nextpage, relatedStreams);
return Constants.mapper.writeValueAsString(channelpage);
}
final List<StreamItem> relatedStreams = new ObjectArrayList<>();
public static final String trendingResponse() throws ParsingException, ExtractionException, IOException {
@ -148,6 +197,14 @@ public class ResponseHelper {
return Constants.mapper.writeValueAsString(relatedStreams);
}
public static final String suggestionsResponse(String query)
throws JsonProcessingException, IOException, ExtractionException {
return Constants.mapper
.writeValueAsString(Constants.YOUTUBE_SERVICE.getSuggestionExtractor().suggestionList(query));
}
private static final String getLBRYStreamURL(String videoId) throws IOException, InterruptedException {
String lbryId = new JSONObject(Constants.h2client.send(HttpRequest

View file

@ -4,14 +4,15 @@ import java.util.List;
public class Channel {
private String name, avatarUrl, bannerUrl, description;
private String name, avatarUrl, bannerUrl, description, nextpage;
private List<StreamItem> relatedStreams;
public Channel(String name, String avatarUrl, String bannerUrl, String description,
public Channel(String name, String avatarUrl, String bannerUrl, String description, String nextpage,
List<StreamItem> relatedStreams) {
this.name = name;
this.avatarUrl = avatarUrl;
this.description = description;
this.nextpage = nextpage;
this.relatedStreams = relatedStreams;
}
@ -31,6 +32,10 @@ public class Channel {
return description;
}
public String getNextpage() {
return nextpage;
}
public List<StreamItem> getRelatedStreams() {
return relatedStreams;
}

View file

@ -0,0 +1,22 @@
package me.kavin.piped.utils.obj;
import java.util.List;
public class ChannelPage {
private String nextpage;
private List<StreamItem> relatedStreams;
public ChannelPage(String nextpage, List<StreamItem> relatedStreams) {
this.nextpage = nextpage;
this.relatedStreams = relatedStreams;
}
public String getNextpage() {
return nextpage;
}
public List<StreamItem> getRelatedStreams() {
return relatedStreams;
}
}

View file

@ -1,10 +1,10 @@
package me.kavin.piped.utils.obj;
public class Stream {
public class PipedStream {
private String url, format, quality, mimeType;
public Stream(String url, String format, String quality, String mimeType) {
public PipedStream(String url, String format, String quality, String mimeType) {
this.url = url;
this.format = format;
this.quality = quality;

View file

@ -8,7 +8,7 @@ public class Streams {
private long duration, views, likes, dislikes;
private List<Stream> audioStreams, videoStreams;
private List<PipedStream> audioStreams, videoStreams;
private List<StreamItem> relatedStreams;
@ -18,7 +18,7 @@ public class Streams {
public Streams(String title, String description, String uploadDate, String uploader, String uploaderUrl,
String uploaderAvatar, String thumbnailUrl, long duration, long views, long likes, long dislikes,
List<Stream> audioStreams, List<Stream> videoStreams, List<StreamItem> relatedStreams,
List<PipedStream> audioStreams, List<PipedStream> videoStreams, List<StreamItem> relatedStreams,
List<Subtitle> subtitles, boolean livestream, String hls) {
this.title = title;
this.description = description;
@ -83,11 +83,11 @@ public class Streams {
return dislikes;
}
public List<Stream> getAudioStreams() {
public List<PipedStream> getAudioStreams() {
return audioStreams;
}
public List<Stream> getVideoStreams() {
public List<PipedStream> getVideoStreams() {
return videoStreams;
}