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 { 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"))); // SyndFeed feed = new SyndFeedInput().build(new XmlReader(new FileInputStream("pubsub.xml")));
// //
// feed.getEntries().forEach(entry -> { // 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) -> { routes.get("/trending", (req, res) -> {
try { try {

View file

@ -11,23 +11,29 @@ import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.commons.lang3.exception.ExceptionUtils;
import org.json.JSONObject; 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.channel.ChannelInfo;
import org.schabi.newpipe.extractor.comments.CommentsInfo; import org.schabi.newpipe.extractor.comments.CommentsInfo;
import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.kiosk.KioskInfo; 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.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamInfoItem; 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.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache; import com.github.benmanes.caffeine.cache.LoadingCache;
import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import me.kavin.piped.consts.Constants; import me.kavin.piped.consts.Constants;
import me.kavin.piped.utils.obj.Channel; 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.StreamItem;
import me.kavin.piped.utils.obj.Streams; import me.kavin.piped.utils.obj.Streams;
import me.kavin.piped.utils.obj.Subtitle; import me.kavin.piped.utils.obj.Subtitle;
@ -65,13 +71,13 @@ public class ResponseHelper {
info.getSubtitles().forEach(subtitle -> subtitles info.getSubtitles().forEach(subtitle -> subtitles
.add(new Subtitle(rewriteURL(subtitle.getUrl()), subtitle.getFormat().getMimeType()))); .add(new Subtitle(rewriteURL(subtitle.getUrl()), subtitle.getFormat().getMimeType())));
final List<Stream> videoStreams = new ObjectArrayList<>(); final List<PipedStream> videoStreams = new ObjectArrayList<>();
final List<Stream> audioStreams = new ObjectArrayList<>(); final List<PipedStream> audioStreams = new ObjectArrayList<>();
final String lbryURL = futureLBRY.get(); final String lbryURL = futureLBRY.get();
if (lbryURL != null) if (lbryURL != null)
videoStreams.add(new Stream(lbryURL, "MP4", "LBRY", "video/mp4")); videoStreams.add(new PipedStream(lbryURL, "MP4", "LBRY", "video/mp4"));
String hls = null; String hls = null;
boolean livestream = false; boolean livestream = false;
@ -79,14 +85,32 @@ public class ResponseHelper {
if ((hls = info.getHlsUrl()) != null && !hls.isEmpty()) if ((hls = info.getHlsUrl()) != null && !hls.isEmpty())
livestream = true; 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()))); 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()))); String.valueOf(stream.getFormat()), stream.getResolution(), stream.getFormat().getMimeType())));
info.getAudioStreams().forEach( info.getAudioStreams()
stream -> audioStreams.add(new Stream(rewriteURL(stream.getUrl()), String.valueOf(stream.getFormat()), .forEach(stream -> audioStreams
stream.getAverageBitrate() + " kbps", stream.getFormat().getMimeType()))); .add(new PipedStream(rewriteURL(stream.getUrl()), String.valueOf(stream.getFormat()),
stream.getAverageBitrate() + " kbps", stream.getFormat().getMimeType())));
final List<StreamItem> relatedStreams = new ObjectArrayList<>(); final List<StreamItem> relatedStreams = new ObjectArrayList<>();
@ -121,13 +145,38 @@ public class ResponseHelper {
item.getDuration(), item.getViewCount())); item.getDuration(), item.getViewCount()));
}); });
String nextpage = info.hasNextPage() ? info.getNextPage().getUrl() : null;
final Channel channel = new Channel(info.getName(), info.getAvatarUrl(), info.getBannerUrl(), final Channel channel = new Channel(info.getName(), info.getAvatarUrl(), info.getBannerUrl(),
info.getDescription(), relatedStreams); info.getDescription(), nextpage, relatedStreams);
return Constants.mapper.writeValueAsString(channel); 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<>(); final List<StreamItem> relatedStreams = new ObjectArrayList<>();
public static final String trendingResponse() throws ParsingException, ExtractionException, IOException { public static final String trendingResponse() throws ParsingException, ExtractionException, IOException {
@ -148,6 +197,14 @@ public class ResponseHelper {
return Constants.mapper.writeValueAsString(relatedStreams); 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 { private static final String getLBRYStreamURL(String videoId) throws IOException, InterruptedException {
String lbryId = new JSONObject(Constants.h2client.send(HttpRequest String lbryId = new JSONObject(Constants.h2client.send(HttpRequest

View file

@ -4,14 +4,15 @@ import java.util.List;
public class Channel { public class Channel {
private String name, avatarUrl, bannerUrl, description; private String name, avatarUrl, bannerUrl, description, nextpage;
private List<StreamItem> relatedStreams; 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) { List<StreamItem> relatedStreams) {
this.name = name; this.name = name;
this.avatarUrl = avatarUrl; this.avatarUrl = avatarUrl;
this.description = description; this.description = description;
this.nextpage = nextpage;
this.relatedStreams = relatedStreams; this.relatedStreams = relatedStreams;
} }
@ -31,6 +32,10 @@ public class Channel {
return description; return description;
} }
public String getNextpage() {
return nextpage;
}
public List<StreamItem> getRelatedStreams() { public List<StreamItem> getRelatedStreams() {
return relatedStreams; 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; package me.kavin.piped.utils.obj;
public class Stream { public class PipedStream {
private String url, format, quality, mimeType; 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.url = url;
this.format = format; this.format = format;
this.quality = quality; this.quality = quality;

View file

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