diff --git a/build.gradle b/build.gradle index a6349ba..22da90d 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { repositories { maven { url 'https://repo.spring.io/milestone' } - jcenter() + jcenter() maven { url 'https://jitpack.io' } } @@ -17,9 +17,9 @@ dependencies { implementation 'it.unimi.dsi:fastutil:8.4.2' implementation 'commons-codec:commons-codec:1.15' implementation 'org.bouncycastle:bcprov-jdk15on:1.66' - implementation 'org.mongodb:mongo-java-driver:3.12.7' + implementation 'org.mongodb:mongodb-driver-sync:4.1.1' implementation 'io.projectreactor.netty:reactor-netty:1.0.1' - implementation 'com.github.TeamNewPipe:NewPipeExtractor:v0.20.2' + implementation 'com.github.TeamNewPipe:NewPipeExtractor:v0.20.8' implementation 'com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751' implementation 'com.fasterxml.jackson.core:jackson-core:2.6.3' implementation 'com.fasterxml.jackson.core:jackson-annotations:2.6.3' diff --git a/src/main/java/me/kavin/piped/Main.java b/src/main/java/me/kavin/piped/Main.java index aae470c..d891472 100644 --- a/src/main/java/me/kavin/piped/Main.java +++ b/src/main/java/me/kavin/piped/Main.java @@ -109,6 +109,32 @@ public class Main { }); + routes.get("/playlists/{playlistId}", (req, res) -> { + + try { + return writeResponse(res, ResponseHelper.playlistResponse(req.param("playlistId")), 200, + "public, max-age=600"); + } catch (Exception e) { + e.printStackTrace(); + return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private"); + } + + }); + + routes.get("/nextpage/playlists/{playlistId}", (req, res) -> { + + QueryStringDecoder query = new QueryStringDecoder(req.uri()); + + try { + return writeResponse(res, ResponseHelper.playlistPageResponse(req.param("playlistId"), + 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()); diff --git a/src/main/java/me/kavin/piped/utils/ResponseHelper.java b/src/main/java/me/kavin/piped/utils/ResponseHelper.java index 4adde46..057ed30 100644 --- a/src/main/java/me/kavin/piped/utils/ResponseHelper.java +++ b/src/main/java/me/kavin/piped/utils/ResponseHelper.java @@ -22,6 +22,7 @@ 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.playlist.PlaylistInfo; import org.schabi.newpipe.extractor.search.SearchInfo; import org.schabi.newpipe.extractor.stream.Stream; import org.schabi.newpipe.extractor.stream.StreamInfo; @@ -34,11 +35,12 @@ 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.ChannelPage; import me.kavin.piped.utils.obj.PipedStream; +import me.kavin.piped.utils.obj.Playlist; import me.kavin.piped.utils.obj.SearchResults; import me.kavin.piped.utils.obj.StreamItem; import me.kavin.piped.utils.obj.Streams; +import me.kavin.piped.utils.obj.StreamsPage; import me.kavin.piped.utils.obj.Subtitle; import me.kavin.piped.utils.obj.search.SearchItem; import me.kavin.piped.utils.obj.search.SearchStream; @@ -82,7 +84,7 @@ public class ResponseHelper { final String lbryURL = futureLBRY.get(); if (lbryURL != null) - videoStreams.add(new PipedStream(lbryURL, "MP4", "LBRY", "video/mp4")); + videoStreams.add(new PipedStream(lbryURL, "MP4", "LBRY", "video/mp4", false)); String hls = null; boolean livestream = false; @@ -108,14 +110,14 @@ public class ResponseHelper { } 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(), true))); 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(), false))); info.getAudioStreams() .forEach(stream -> audioStreams .add(new PipedStream(rewriteURL(stream.getUrl()), String.valueOf(stream.getFormat()), - stream.getAverageBitrate() + " kbps", stream.getFormat().getMimeType()))); + stream.getAverageBitrate() + " kbps", stream.getFormat().getMimeType(), false))); final List relatedStreams = new ObjectArrayList<>(); @@ -123,7 +125,7 @@ public class ResponseHelper { StreamInfoItem item = (StreamInfoItem) o; relatedStreams.add(new StreamItem(item.getUrl().substring(23), item.getName(), rewriteURL(item.getThumbnailUrl()), item.getUploaderName(), item.getUploaderUrl().substring(23), - item.getDuration(), item.getViewCount())); + item.getTextualUploadDate(), item.getDuration(), item.getViewCount())); }); final Streams streams = new Streams(info.getName(), info.getDescription().getContent(), @@ -147,7 +149,7 @@ public class ResponseHelper { 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())); + item.getTextualUploadDate(), item.getDuration(), item.getViewCount())); }); String nextpage = info.hasNextPage() ? info.getNextPage().getUrl() : null; @@ -171,14 +173,14 @@ public class ResponseHelper { 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())); + item.getTextualUploadDate(), item.getDuration(), item.getViewCount())); }); String nextpage = page.hasNextPage() ? page.getNextPage().getUrl() : null; - final ChannelPage channelpage = new ChannelPage(nextpage, relatedStreams); + final StreamsPage streamspage = new StreamsPage(nextpage, relatedStreams); - return Constants.mapper.writeValueAsString(channelpage); + return Constants.mapper.writeValueAsString(streamspage); } @@ -196,12 +198,59 @@ public class ResponseHelper { 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())); + item.getTextualUploadDate(), item.getDuration(), item.getViewCount())); }); return Constants.mapper.writeValueAsString(relatedStreams); } + public static final String playlistResponse(String playlistId) + throws IOException, ExtractionException, InterruptedException { + + final PlaylistInfo info = PlaylistInfo.getInfo("https://www.youtube.com/playlist?list=" + playlistId); + + final List 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); + + return Constants.mapper.writeValueAsString(playlist); + + } + + public static final String playlistPageResponse(String playlistId, String url) + throws IOException, ExtractionException, InterruptedException { + + InfoItemsPage page = PlaylistInfo.getMoreItems(Constants.YOUTUBE_SERVICE, + "https://www.youtube.com/playlist?list=" + playlistId, new Page(url)); + + final List 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); + + return Constants.mapper.writeValueAsString(streamspage); + + } + public static final String suggestionsResponse(String query) throws JsonProcessingException, IOException, ExtractionException { @@ -273,6 +322,12 @@ public class ResponseHelper { } + public static final String registerResponse(String user, String pass) throws IOException { + + return Constants.mapper.writeValueAsString(null); + + } + private static final String getLBRYStreamURL(String videoId) throws IOException, InterruptedException { String lbryId = new JSONObject(Constants.h2client.send(HttpRequest diff --git a/src/main/java/me/kavin/piped/utils/obj/PipedStream.java b/src/main/java/me/kavin/piped/utils/obj/PipedStream.java index a0dfc44..b7f604a 100644 --- a/src/main/java/me/kavin/piped/utils/obj/PipedStream.java +++ b/src/main/java/me/kavin/piped/utils/obj/PipedStream.java @@ -3,11 +3,13 @@ package me.kavin.piped.utils.obj; public class PipedStream { public String url, format, quality, mimeType; + public boolean videoOnly; - public PipedStream(String url, String format, String quality, String mimeType) { + public PipedStream(String url, String format, String quality, String mimeType, boolean videoOnly) { this.url = url; this.format = format; this.quality = quality; this.mimeType = mimeType; + this.videoOnly = videoOnly; } } diff --git a/src/main/java/me/kavin/piped/utils/obj/Playlist.java b/src/main/java/me/kavin/piped/utils/obj/Playlist.java new file mode 100644 index 0000000..1c7566e --- /dev/null +++ b/src/main/java/me/kavin/piped/utils/obj/Playlist.java @@ -0,0 +1,23 @@ +package me.kavin.piped.utils.obj; + +import java.util.List; + +public class Playlist { + + public String name, thumbnailUrl, bannerUrl, nextpage, uploader, uploaderUrl, uploaderAvatar; + public int videos; + public List relatedStreams; + + public Playlist(String name, String thumbnailUrl, String bannerUrl, String nextpage, String uploader, + String uploaderUrl, String uploaderAvatar, int videos, List relatedStreams) { + this.name = name; + this.thumbnailUrl = thumbnailUrl; + this.bannerUrl = bannerUrl; + this.nextpage = nextpage; + this.videos = videos; + this.uploader = uploader; + this.uploaderUrl = uploaderUrl; + this.uploaderAvatar = uploaderAvatar; + this.relatedStreams = relatedStreams; + } +} diff --git a/src/main/java/me/kavin/piped/utils/obj/StreamItem.java b/src/main/java/me/kavin/piped/utils/obj/StreamItem.java index 0fc0946..39d2a75 100644 --- a/src/main/java/me/kavin/piped/utils/obj/StreamItem.java +++ b/src/main/java/me/kavin/piped/utils/obj/StreamItem.java @@ -2,16 +2,17 @@ package me.kavin.piped.utils.obj; public class StreamItem { - public String url, title, thumbnail, uploaderName, uploaderUrl; + public String url, title, thumbnail, uploaderName, uploaderUrl, uploadedDate; public long duration, views; public StreamItem(String url, String title, String thumbnail, String uploaderName, String uploaderUrl, - long duration, long views) { + String uploadedDate, long duration, long views) { this.url = url; this.title = title; this.thumbnail = thumbnail; this.uploaderName = uploaderName; this.uploaderUrl = uploaderUrl; + this.uploadedDate = uploadedDate; this.duration = duration; this.views = views; } diff --git a/src/main/java/me/kavin/piped/utils/obj/ChannelPage.java b/src/main/java/me/kavin/piped/utils/obj/StreamsPage.java similarity index 67% rename from src/main/java/me/kavin/piped/utils/obj/ChannelPage.java rename to src/main/java/me/kavin/piped/utils/obj/StreamsPage.java index 92eb295..493e717 100644 --- a/src/main/java/me/kavin/piped/utils/obj/ChannelPage.java +++ b/src/main/java/me/kavin/piped/utils/obj/StreamsPage.java @@ -2,12 +2,12 @@ package me.kavin.piped.utils.obj; import java.util.List; -public class ChannelPage { +public class StreamsPage { public String nextpage; public List relatedStreams; - public ChannelPage(String nextpage, List relatedStreams) { + public StreamsPage(String nextpage, List relatedStreams) { this.nextpage = nextpage; this.relatedStreams = relatedStreams; }