From dd2ee203bbd7d6f9adc3d5eb4fd8569e6c470792 Mon Sep 17 00:00:00 2001 From: FireMasterK <20838718+FireMasterK@users.noreply.github.com> Date: Wed, 24 Feb 2021 15:22:29 +0530 Subject: [PATCH] Commit changes. --- build.gradle | 4 +- src/main/java/me/kavin/piped/Main.java | 349 ++++++------- .../java/me/kavin/piped/consts/Constants.java | 25 +- src/main/java/me/kavin/piped/ipfs/IPFS.java | 20 + .../me/kavin/piped/utils/CookieHandler.java | 6 +- .../me/kavin/piped/utils/DownloaderImpl.java | 40 +- .../me/kavin/piped/utils/Multithreading.java | 19 + .../me/kavin/piped/utils/RegisterRequest.java | 7 + .../me/kavin/piped/utils/ResponseHelper.java | 469 +++++++++--------- .../kavin/piped/utils/SponsorBlockUtils.java | 38 +- .../java/me/kavin/piped/utils/URLUtils.java | 12 +- .../me/kavin/piped/utils/obj/Channel.java | 19 +- .../kavin/piped/utils/obj/ChapterSegment.java | 12 + .../me/kavin/piped/utils/obj/PipedStream.java | 47 +- .../me/kavin/piped/utils/obj/Playlist.java | 20 +- .../kavin/piped/utils/obj/SearchResults.java | 6 +- .../me/kavin/piped/utils/obj/StreamItem.java | 18 +- .../me/kavin/piped/utils/obj/Streams.java | 40 +- .../me/kavin/piped/utils/obj/StreamsPage.java | 4 +- .../me/kavin/piped/utils/obj/Subtitle.java | 4 +- .../piped/utils/obj/search/SearchItem.java | 12 +- .../piped/utils/obj/search/SearchStream.java | 10 +- 22 files changed, 650 insertions(+), 531 deletions(-) create mode 100644 src/main/java/me/kavin/piped/ipfs/IPFS.java create mode 100644 src/main/java/me/kavin/piped/utils/Multithreading.java create mode 100644 src/main/java/me/kavin/piped/utils/RegisterRequest.java create mode 100644 src/main/java/me/kavin/piped/utils/obj/ChapterSegment.java diff --git a/build.gradle b/build.gradle index d68cfff..ae976f0 100644 --- a/build.gradle +++ b/build.gradle @@ -19,7 +19,7 @@ dependencies { implementation 'org.bouncycastle:bcprov-jdk15on:1.67' implementation 'org.mongodb:mongodb-driver-sync:4.2.1' implementation 'io.projectreactor.netty:reactor-netty:1.0.4' - implementation 'com.github.TeamNewPipe:NewPipeExtractor:v0.20.8' + implementation 'com.github.TeamNewPipe:NewPipeExtractor:SNAPSHOT' implementation 'com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751' implementation 'com.fasterxml.jackson.core:jackson-core:2.12.1' implementation 'com.fasterxml.jackson.core:jackson-annotations:2.12.1' @@ -27,6 +27,8 @@ dependencies { implementation 'org.json:json:20201115' implementation 'com.github.ben-manes.caffeine:caffeine:2.8.6' implementation 'com.rometools:rome:1.15.0' + implementation 'com.github.ipfs:java-ipfs-http-client:v1.3.3' + implementation 'net.java.dev.jna:jna-platform:5.7.0' } shadowJar { diff --git a/src/main/java/me/kavin/piped/Main.java b/src/main/java/me/kavin/piped/Main.java index b871b9e..ef80019 100644 --- a/src/main/java/me/kavin/piped/Main.java +++ b/src/main/java/me/kavin/piped/Main.java @@ -1,6 +1,13 @@ package me.kavin.piped; -import io.netty.util.AsciiString; +import static io.netty.handler.codec.http.HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN; +import static io.netty.handler.codec.http.HttpHeaderNames.CACHE_CONTROL; +import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE; +import static io.netty.handler.codec.http.HttpHeaderValues.APPLICATION_JSON; +import static io.netty.handler.codec.http.HttpHeaderValues.TEXT_PLAIN; + +import java.nio.charset.StandardCharsets; + import org.apache.commons.lang3.exception.ExceptionUtils; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.localization.Localization; @@ -11,6 +18,7 @@ import com.rometools.rome.io.XmlReader; import io.netty.buffer.ByteBufAllocator; import io.netty.handler.codec.http.QueryStringDecoder; +import io.netty.util.AsciiString; import me.kavin.piped.consts.Constants; import me.kavin.piped.utils.DownloaderImpl; import me.kavin.piped.utils.ResponseHelper; @@ -22,231 +30,233 @@ import reactor.netty.NettyOutbound; import reactor.netty.http.server.HttpServer; import reactor.netty.http.server.HttpServerResponse; -import java.nio.charset.StandardCharsets; - -import static io.netty.handler.codec.http.HttpHeaderNames.*; -import static io.netty.handler.codec.http.HttpHeaderValues.*; - public class Main { public static void main(String[] args) throws Exception { - NewPipe.init(new DownloaderImpl(), new Localization("en", "US")); + NewPipe.init(new DownloaderImpl(), new Localization("en", "US")); DisposableServer server = HttpServer.create().port(Constants.PORT).route(routes -> { - routes.get("/webhooks/pubsub", (req, res) -> { + routes.get("/webhooks/pubsub", (req, res) -> { - long start = System.nanoTime(); - QueryStringDecoder query = new QueryStringDecoder(req.uri()); + long start = System.nanoTime(); + QueryStringDecoder query = new QueryStringDecoder(req.uri()); - try { - return writeResponse(res, query.parameters().get("hub.challenge").get(0), TEXT_PLAIN, 200, "private", start); + try { + return writeResponse(res, query.parameters().get("hub.challenge").get(0), TEXT_PLAIN, 200, + "private", start); - } catch (Exception e) { - e.printStackTrace(); - return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); - } + } catch (Exception e) { + e.printStackTrace(); + return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); + } - }); + }); - routes.post("/webhooks/pubsub", (req, res) -> { + routes.post("/webhooks/pubsub", (req, res) -> { - long start = System.nanoTime(); + long start = System.nanoTime(); - try { - req.receive().asInputStream().subscribe(in -> { - try { - SyndFeed feed = new SyndFeedInput().build(new XmlReader(in)); + try { + req.receive().asInputStream().subscribe(in -> { + try { + SyndFeed feed = new SyndFeedInput().build(new XmlReader(in)); - feed.getEntries().forEach(entry -> { - System.out.println(entry.getLinks().get(0).getHref()); - System.out.println(entry.getAuthors().get(0).getUri()); - }); + feed.getEntries().forEach(entry -> { + System.out.println(entry.getLinks().get(0).getHref()); + System.out.println(entry.getAuthors().get(0).getUri()); + }); - } catch (Exception e) { - e.printStackTrace(); - } - }); - return writeResponse(res, "ok", TEXT_PLAIN, 200, "private", start); - } catch (Exception e) { - e.printStackTrace(); - return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); - } + } catch (Exception e) { + e.printStackTrace(); + } + }); + return writeResponse(res, "ok", TEXT_PLAIN, 200, "private", start); + } catch (Exception e) { + e.printStackTrace(); + return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); + } - }); + }); - routes.get("/sponsors/{videoId}", (req, res) -> { + routes.get("/sponsors/{videoId}", (req, res) -> { - long start = System.nanoTime(); - QueryStringDecoder query = new QueryStringDecoder(req.uri()); + long start = System.nanoTime(); + QueryStringDecoder query = new QueryStringDecoder(req.uri()); - try { - return writeResponse(res, SponsorBlockUtils.getSponsors(req.param("videoId"), - query.parameters().get("category").get(0)), 200, "public, max-age=3600", start); - } catch (Exception e) { - e.printStackTrace(); - return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); - } + try { + return writeResponse(res, SponsorBlockUtils.getSponsors(req.param("videoId"), + query.parameters().get("category").get(0)), 200, "public, max-age=3600", start); + } catch (Exception e) { + e.printStackTrace(); + return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); + } - }); + }); - routes.get("/streams/{videoId}", (req, res) -> { + routes.get("/streams/{videoId}", (req, res) -> { - long start = System.nanoTime(); - try { - // The stream links are valid for 6 hours. - return writeResponse(res, ResponseHelper.streamsResponse(req.param("videoId")), 200, - "public, s-maxage=21540", start); - } catch (Exception e) { - e.printStackTrace(); - return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); - } + long start = System.nanoTime(); + try { + // The stream links are valid for 6 hours. + return writeResponse(res, ResponseHelper.streamsResponse(req.param("videoId")), 200, + "public, s-maxage=21540", start); + } catch (Exception e) { + e.printStackTrace(); + return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); + } - }); + }); - routes.get("/channels/{channelId}", (req, res) -> { + routes.get("/channels/{channelId}", (req, res) -> { - long start = System.nanoTime(); - try { - return writeResponse(res, ResponseHelper.channelResponse(req.param("channelId")), 200, - "public, max-age=600", start); - } catch (Exception e) { - e.printStackTrace(); - return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); - } + long start = System.nanoTime(); + try { + return writeResponse(res, ResponseHelper.channelResponse(req.param("channelId")), 200, + "public, max-age=600", start); + } catch (Exception e) { + e.printStackTrace(); + return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); + } - }); + }); - routes.get("/nextpage/channels/{channelId}", (req, res) -> { + routes.get("/nextpage/channels/{channelId}", (req, res) -> { - long start = System.nanoTime(); - QueryStringDecoder query = new QueryStringDecoder(req.uri()); + long start = System.nanoTime(); + 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", start); - } catch (Exception e) { - e.printStackTrace(); - return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); - } + try { + return writeResponse(res, ResponseHelper.channelPageResponse(req.param("channelId"), + query.parameters().get("url").get(0)), 200, "public, max-age=3600", start); + } catch (Exception e) { + e.printStackTrace(); + return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); + } - }); + }); - routes.get("/playlists/{playlistId}", (req, res) -> { + routes.get("/playlists/{playlistId}", (req, res) -> { - long start = System.nanoTime(); - try { - return writeResponse(res, ResponseHelper.playlistResponse(req.param("playlistId")), 200, - "public, max-age=600", start); - } catch (Exception e) { - e.printStackTrace(); - return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); - } + long start = System.nanoTime(); + try { + return writeResponse(res, ResponseHelper.playlistResponse(req.param("playlistId")), 200, + "public, max-age=600", start); + } catch (Exception e) { + e.printStackTrace(); + return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); + } - }); + }); - routes.get("/nextpage/playlists/{playlistId}", (req, res) -> { + routes.get("/nextpage/playlists/{playlistId}", (req, res) -> { - long start = System.nanoTime(); - QueryStringDecoder query = new QueryStringDecoder(req.uri()); + long start = System.nanoTime(); + 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", start); - } catch (Exception e) { - e.printStackTrace(); - return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); - } + try { + return writeResponse(res, ResponseHelper.playlistPageResponse(req.param("playlistId"), + query.parameters().get("url").get(0)), 200, "public, max-age=3600", start); + } catch (Exception e) { + e.printStackTrace(); + return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); + } - }); + }); - routes.get("/suggestions", (req, res) -> { + routes.get("/suggestions", (req, res) -> { - long start = System.nanoTime(); - QueryStringDecoder query = new QueryStringDecoder(req.uri()); + long start = System.nanoTime(); + QueryStringDecoder query = new QueryStringDecoder(req.uri()); - try { - return writeResponse(res, - ResponseHelper.suggestionsResponse(query.parameters().get("query").get(0)), 200, - "public, max-age=600", start); - } catch (Exception e) { - e.printStackTrace(); - return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); - } + try { + return writeResponse(res, + ResponseHelper.suggestionsResponse(query.parameters().get("query").get(0)), 200, + "public, max-age=600", start); + } catch (Exception e) { + e.printStackTrace(); + return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); + } - }); + }); - routes.get("/search", (req, res) -> { + routes.get("/search", (req, res) -> { - long start = System.nanoTime(); - QueryStringDecoder query = new QueryStringDecoder(req.uri()); + long start = System.nanoTime(); + QueryStringDecoder query = new QueryStringDecoder(req.uri()); - try { - return writeResponse(res, ResponseHelper.searchResponse(query.parameters().get("q").get(0)), 200, - "public, max-age=600", start); - } catch (Exception e) { - e.printStackTrace(); - return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); - } + try { + return writeResponse(res, ResponseHelper.searchResponse(query.parameters().get("q").get(0)), 200, + "public, max-age=600", start); + } catch (Exception e) { + e.printStackTrace(); + return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); + } - }); + }); - routes.get("/nextpage/search", (req, res) -> { + routes.get("/nextpage/search", (req, res) -> { - long start = System.nanoTime(); - QueryStringDecoder query = new QueryStringDecoder(req.uri()); + long start = System.nanoTime(); + QueryStringDecoder query = new QueryStringDecoder(req.uri()); - try { - return writeResponse(res, - ResponseHelper.searchPageResponse(query.parameters().get("q").get(0), - query.parameters().get("url").get(0), query.parameters().get("id").get(0)), - 200, "public, max-age=3600", start); - } catch (Exception e) { - e.printStackTrace(); - return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); - } + try { + return writeResponse(res, + ResponseHelper.searchPageResponse(query.parameters().get("q").get(0), + query.parameters().get("url").get(0), query.parameters().get("id").get(0)), + 200, "public, max-age=3600", start); + } catch (Exception e) { + e.printStackTrace(); + return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); + } - }); + }); - routes.get("/trending", (req, res) -> { + routes.get("/trending", (req, res) -> { - long start = System.nanoTime(); - try { - return writeResponse(res, ResponseHelper.trendingResponse(), 200, "public, max-age=3600", start); - } catch (Exception e) { - e.printStackTrace(); - return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); - } + long start = System.nanoTime(); + try { + return writeResponse(res, ResponseHelper.trendingResponse(), 200, "public, max-age=3600", start); + } catch (Exception e) { + e.printStackTrace(); + return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start); + } - }); + }); }).compress(true).bindNow(); server.onDispose().block(); } - public static NettyOutbound writeResponse(HttpServerResponse res, String resp, int code, String cache, long time) { - return writeResponse(res, resp, APPLICATION_JSON, code, cache, time); - } + }).bindNow(); - public static NettyOutbound writeResponse(HttpServerResponse res, String resp, AsciiString mimeType, int code, String cache, long time) { - return writeResponse(res, resp, mimeType.toString(), code, cache, time); - } - - public static NettyOutbound writeResponse(HttpServerResponse res, String resp, String mimeType, int code, String cache, long time) { - return writeResponse(res, resp.getBytes(StandardCharsets.UTF_8), mimeType, code, cache, time); - } - - - - public static NettyOutbound writeResponse(HttpServerResponse res, byte[] resp, int code, String cache, long time) { - return writeResponse(res, resp, APPLICATION_JSON, code, cache, time); + Thread.sleep(Long.MAX_VALUE); } - public static NettyOutbound writeResponse(HttpServerResponse res, byte[] resp, AsciiString mimeType, int code, String cache, long time) { - return writeResponse(res, resp, mimeType.toString(), code, cache, time); - } + public static NettyOutbound writeResponse(HttpServerResponse res, String resp, int code, String cache, long time) { + return writeResponse(res, resp, APPLICATION_JSON, code, cache, time); + } + + public static NettyOutbound writeResponse(HttpServerResponse res, String resp, AsciiString mimeType, int code, + String cache, long time) { + return writeResponse(res, resp, mimeType.toString(), code, cache, time); + } + + public static NettyOutbound writeResponse(HttpServerResponse res, String resp, String mimeType, int code, + String cache, long time) { + return writeResponse(res, resp.getBytes(StandardCharsets.UTF_8), mimeType, code, cache, time); + } + + public static NettyOutbound writeResponse(HttpServerResponse res, byte[] resp, int code, String cache, long time) { + return writeResponse(res, resp, APPLICATION_JSON, code, cache, time); + } + + public static NettyOutbound writeResponse(HttpServerResponse res, byte[] resp, AsciiString mimeType, int code, + String cache, long time) { + return writeResponse(res, resp, mimeType.toString(), code, cache, time); + } public static NettyOutbound writeResponse(HttpServerResponse res, byte[] resp, String mimeType, int code, String cache, long time) { return res @@ -258,15 +268,14 @@ public class Main { .sendByteArray(Flux.just(resp)); } - - public static NettyOutbound writeResponse(HttpServerResponse res, Flux resp, int code, String cache) { - return writeResponse(res, resp, APPLICATION_JSON, code, cache); + return writeResponse(res, resp, APPLICATION_JSON, code, cache); } - public static NettyOutbound writeResponse(HttpServerResponse res, Flux resp, AsciiString mimeType, int code, String cache) { - return writeResponse(res, resp, mimeType.toString(), code, cache); - } + public static NettyOutbound writeResponse(HttpServerResponse res, Flux resp, AsciiString mimeType, int code, + String cache) { + return writeResponse(res, resp, mimeType.toString(), code, cache); + } public static NettyOutbound writeResponse(HttpServerResponse res, Flux resp, String mimeType, int code, String cache) { return res diff --git a/src/main/java/me/kavin/piped/consts/Constants.java b/src/main/java/me/kavin/piped/consts/Constants.java index 7981bcf..87b20fb 100644 --- a/src/main/java/me/kavin/piped/consts/Constants.java +++ b/src/main/java/me/kavin/piped/consts/Constants.java @@ -10,6 +10,8 @@ import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.StreamingService; import com.fasterxml.jackson.databind.ObjectMapper; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; public class Constants { @@ -24,21 +26,24 @@ public class Constants { public static final StreamingService YOUTUBE_SERVICE; public static final HttpClient h2client = HttpClient.newBuilder().followRedirects(Redirect.NORMAL) - .version(Version.HTTP_2).build(); + .version(Version.HTTP_2).build(); // public static final HttpClient h3client = Http3ClientBuilder.newBuilder().followRedirects(Redirect.NORMAL).build(); + public static final MongoClient mongoClient; + public static final ObjectMapper mapper = new ObjectMapper(); static { - Properties prop = new Properties(); - try { - YOUTUBE_SERVICE = NewPipe.getService(0); - prop.load(new FileReader("config.properties")); + Properties prop = new Properties(); + try { + YOUTUBE_SERVICE = NewPipe.getService(0); + prop.load(new FileReader("config.properties")); - PORT = Integer.parseInt(prop.getProperty("PORT")); - PROXY_PART = prop.getProperty("PROXY_PART"); - } catch (Exception e) { - throw new RuntimeException(e); - } + PORT = Integer.parseInt(prop.getProperty("PORT")); + PROXY_PART = prop.getProperty("PROXY_PART"); + mongoClient = MongoClients.create(prop.getProperty("MONGO_URI")); + } catch (Exception e) { + throw new RuntimeException(e); + } } } diff --git a/src/main/java/me/kavin/piped/ipfs/IPFS.java b/src/main/java/me/kavin/piped/ipfs/IPFS.java new file mode 100644 index 0000000..bbb3390 --- /dev/null +++ b/src/main/java/me/kavin/piped/ipfs/IPFS.java @@ -0,0 +1,20 @@ +package me.kavin.piped.ipfs; + +import me.kavin.piped.utils.Multithreading; +import me.kavin.piped.utils.obj.Channel; + +public class IPFS { + +// private static final io.ipfs.api.IPFS ipfs = new io.ipfs.api.IPFS(new MultiAddress("/ip4/127.0.0.1/tcp/5001")); + + public static void publishData(final Channel channel) { + Multithreading.runAsync(() -> { + try { +// ipfs.pubsub.pub(URLUtils.silentEncode(channel.id), +// URLUtils.silentEncode(Constants.mapper.writeValueAsString(channel))); + } catch (Exception e) { + e.printStackTrace(); + } + }); + } +} diff --git a/src/main/java/me/kavin/piped/utils/CookieHandler.java b/src/main/java/me/kavin/piped/utils/CookieHandler.java index 12722f5..2153f12 100644 --- a/src/main/java/me/kavin/piped/utils/CookieHandler.java +++ b/src/main/java/me/kavin/piped/utils/CookieHandler.java @@ -9,13 +9,13 @@ public class CookieHandler extends java.net.CookieHandler { @Override public Map> get(URI uri, Map> requestHeaders) throws IOException { - // TODO Auto-generated method stub - return null; + // TODO Auto-generated method stub + return null; } @Override public void put(URI uri, Map> responseHeaders) throws IOException { - // TODO Auto-generated method stub + // TODO Auto-generated method stub } } diff --git a/src/main/java/me/kavin/piped/utils/DownloaderImpl.java b/src/main/java/me/kavin/piped/utils/DownloaderImpl.java index 04b5e0e..e306bc0 100644 --- a/src/main/java/me/kavin/piped/utils/DownloaderImpl.java +++ b/src/main/java/me/kavin/piped/utils/DownloaderImpl.java @@ -23,32 +23,32 @@ public class DownloaderImpl extends Downloader { @Override public Response execute(Request request) throws IOException, ReCaptchaException { - // TODO: HTTP/3 aka QUIC - Builder builder = HttpRequest.newBuilder(URI.create(request.url())); + // TODO: HTTP/3 aka QUIC + Builder builder = HttpRequest.newBuilder(URI.create(request.url())); - byte[] data = request.dataToSend(); - BodyPublisher publisher = data == null ? HttpRequest.BodyPublishers.noBody() - : HttpRequest.BodyPublishers.ofByteArray(data); + byte[] data = request.dataToSend(); + BodyPublisher publisher = data == null ? HttpRequest.BodyPublishers.noBody() + : HttpRequest.BodyPublishers.ofByteArray(data); - builder.method(request.httpMethod(), publisher); - request.headers().forEach((name, values) -> values.forEach(value -> builder.header(name, value))); + builder.method(request.httpMethod(), publisher); + request.headers().forEach((name, values) -> values.forEach(value -> builder.header(name, value))); - builder.setHeader("User-Agent", Constants.USER_AGENT); + builder.setHeader("User-Agent", Constants.USER_AGENT); - HttpResponse response = null; + HttpResponse response = null; - try { - response = Constants.h2client.send(builder.build(), BodyHandlers.ofString()); - } catch (InterruptedException e) { - // ignored - } + try { + response = Constants.h2client.send(builder.build(), BodyHandlers.ofString()); + } catch (InterruptedException e) { + // ignored + } - // TODO: Implement solver - if (response.statusCode() == 429) { - throw new ReCaptchaException("reCaptcha Challenge requested", String.valueOf(response.uri())); - } + // TODO: Implement solver + if (response.statusCode() == 429) { + throw new ReCaptchaException("reCaptcha Challenge requested", String.valueOf(response.uri())); + } - return new Response(response.statusCode(), "UNDEFINED", response.headers().map(), response.body(), - String.valueOf(response.uri())); + return new Response(response.statusCode(), "UNDEFINED", response.headers().map(), response.body(), + String.valueOf(response.uri())); } } diff --git a/src/main/java/me/kavin/piped/utils/Multithreading.java b/src/main/java/me/kavin/piped/utils/Multithreading.java new file mode 100644 index 0000000..3ac2fdd --- /dev/null +++ b/src/main/java/me/kavin/piped/utils/Multithreading.java @@ -0,0 +1,19 @@ +package me.kavin.piped.utils; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class Multithreading { + + private static final ExecutorService es = Executors.newFixedThreadPool(16); + + public static void runAsync(final Runnable runnable) { + es.submit(runnable); + } + + public static void runAsyncTimeout(final Runnable runnable) { + + es.submit(runnable); + + } +} \ No newline at end of file diff --git a/src/main/java/me/kavin/piped/utils/RegisterRequest.java b/src/main/java/me/kavin/piped/utils/RegisterRequest.java new file mode 100644 index 0000000..7d75b25 --- /dev/null +++ b/src/main/java/me/kavin/piped/utils/RegisterRequest.java @@ -0,0 +1,7 @@ +package me.kavin.piped.utils; + +public class RegisterRequest { + + public String username, password; + +} diff --git a/src/main/java/me/kavin/piped/utils/ResponseHelper.java b/src/main/java/me/kavin/piped/utils/ResponseHelper.java index de2b4c4..2bfd4c6 100644 --- a/src/main/java/me/kavin/piped/utils/ResponseHelper.java +++ b/src/main/java/me/kavin/piped/utils/ResponseHelper.java @@ -10,7 +10,6 @@ import java.net.http.HttpResponse.BodyHandlers; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; -import java.util.stream.Stream; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; @@ -34,7 +33,9 @@ import com.github.benmanes.caffeine.cache.LoadingCache; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import me.kavin.piped.consts.Constants; +import me.kavin.piped.ipfs.IPFS; import me.kavin.piped.utils.obj.Channel; +import me.kavin.piped.utils.obj.ChapterSegment; import me.kavin.piped.utils.obj.PipedStream; import me.kavin.piped.utils.obj.Playlist; import me.kavin.piped.utils.obj.SearchResults; @@ -48,353 +49,361 @@ import me.kavin.piped.utils.obj.search.SearchStream; public class ResponseHelper { public static final LoadingCache commentsCache = Caffeine.newBuilder() - .expireAfterWrite(1, TimeUnit.HOURS).maximumSize(1000) - .build(key -> CommentsInfo.getInfo("https://www.youtube.com/watch?v=" + key)); + .expireAfterWrite(1, TimeUnit.HOURS).maximumSize(1000) + .build(key -> CommentsInfo.getInfo("https://www.youtube.com/watch?v=" + key)); public static final byte[] streamsResponse(String videoId) throws Exception { - CompletableFuture futureStream = CompletableFuture.supplyAsync(() -> { - try { - return StreamInfo.getInfo("https://www.youtube.com/watch?v=" + videoId); - } catch (Exception e) { - ExceptionUtils.rethrow(e); - } - return null; - }); + CompletableFuture futureStream = CompletableFuture.supplyAsync(() -> { + try { + return StreamInfo.getInfo("https://www.youtube.com/watch?v=" + videoId); + } catch (Exception e) { + ExceptionUtils.rethrow(e); + } + return null; + }); - CompletableFuture futureLBRY = CompletableFuture.supplyAsync(() -> { - try { - return getLBRYStreamURL(videoId); - } catch (Exception e) { - ExceptionUtils.rethrow(e); - } - return null; - }); + CompletableFuture futureLBRY = CompletableFuture.supplyAsync(() -> { + try { + return getLBRYStreamURL(videoId); + } catch (Exception e) { + ExceptionUtils.rethrow(e); + } + return null; + }); - final List subtitles = new ObjectArrayList<>(); + final List subtitles = new ObjectArrayList<>(); - final StreamInfo info = futureStream.get(); + final StreamInfo info = futureStream.get(); - info.getSubtitles().forEach(subtitle -> subtitles - .add(new Subtitle(rewriteURL(subtitle.getUrl()), subtitle.getFormat().getMimeType()))); +// System.out.println(Constants.mapper.writeValueAsString(info.getStreamSegments())); + info.getSubtitles().forEach(subtitle -> subtitles + .add(new Subtitle(rewriteURL(subtitle.getUrl()), subtitle.getFormat().getMimeType()))); - final List videoStreams = new ObjectArrayList<>(); - final List audioStreams = new ObjectArrayList<>(); + final List videoStreams = new ObjectArrayList<>(); + final List audioStreams = new ObjectArrayList<>(); - final String lbryURL = futureLBRY.get(); + final String lbryURL = futureLBRY.get(); - if (lbryURL != null) - videoStreams.add(new PipedStream(lbryURL, "MP4", "LBRY", "video/mp4", false)); + if (lbryURL != null) + videoStreams.add(new PipedStream(lbryURL, "MP4", "LBRY", "video/mp4", false)); - final String hls; - boolean livestream = false; + final String hls; + boolean livestream = false; - if ((hls = info.getHlsUrl()) != null && !hls.isEmpty()) - livestream = true; + if ((hls = info.getHlsUrl()) != null && !hls.isEmpty()) + livestream = true; - if (hls != null) { + if (hls != null) { - java.util.stream.Stream resp = Constants.h2client - .send(HttpRequest.newBuilder(URI.create(hls)).GET().build(), BodyHandlers.ofLines()).body(); - ObjectArrayList lines = new ObjectArrayList<>(); - resp.forEach(line -> lines.add(line)); + java.util.stream.Stream resp = Constants.h2client + .send(HttpRequest.newBuilder(URI.create(hls)).GET().build(), BodyHandlers.ofLines()).body(); + ObjectArrayList 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)); - } - } - } + 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)); + } + } + } - 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))); + if (!livestream) { + info.getVideoOnlyStreams().forEach(stream -> videoStreams.add(new PipedStream(rewriteURL(stream.getUrl()), + String.valueOf(stream.getFormat()), stream.getResolution(), stream.getFormat().getMimeType(), true, + stream.getBitrate(), stream.getInitStart(), stream.getInitEnd(), stream.getIndexStart(), + stream.getIndexEnd(), stream.getCodec(), stream.getWidth(), stream.getHeight(), 30))); + 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))); - } + info.getAudioStreams() + .forEach(stream -> audioStreams.add(new PipedStream(rewriteURL(stream.getUrl()), + String.valueOf(stream.getFormat()), stream.getAverageBitrate() + " kbps", + stream.getFormat().getMimeType(), false, stream.getBitrate(), stream.getInitStart(), + stream.getInitEnd(), stream.getIndexStart(), stream.getIndexEnd(), stream.getCodec()))); + } - final List relatedStreams = new ObjectArrayList<>(); + final List 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), - item.getTextualUploadDate(), item.getDuration(), item.getViewCount())); - }); + 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), + item.getTextualUploadDate(), item.getDuration(), item.getViewCount())); + }); - 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, - relatedStreams, subtitles, livestream, hls); + List segments = new ObjectArrayList<>(); - return Constants.mapper.writeValueAsBytes(streams); + info.getStreamSegments().forEach( + segment -> segments.add(new ChapterSegment(segment.getTitle(), segment.getStartTimeSeconds()))); + + 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, + relatedStreams, subtitles, livestream, hls); + + return Constants.mapper.writeValueAsBytes(streams); } - public static final byte[] channelResponse(String channelId) - throws IOException, ExtractionException, InterruptedException { + public static final byte[] channelResponse(String channelId) throws Exception { - final ChannelInfo info = ChannelInfo.getInfo("https://youtube.com/channel/" + channelId); + final ChannelInfo info = ChannelInfo.getInfo("https://youtube.com/channel/" + channelId); - final List relatedStreams = new ObjectArrayList<>(); + 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())); - }); + 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; + String nextpage = info.hasNextPage() ? info.getNextPage().getUrl() : null; - final Channel channel = new Channel(info.getName(), rewriteURL(info.getAvatarUrl()), - rewriteURL(info.getBannerUrl()), info.getDescription(), nextpage, relatedStreams); + final Channel channel = new Channel(info.getId(), info.getName(), rewriteURL(info.getAvatarUrl()), + rewriteURL(info.getBannerUrl()), info.getDescription(), nextpage, relatedStreams); - return Constants.mapper.writeValueAsBytes(channel); + IPFS.publishData(channel); + + return Constants.mapper.writeValueAsBytes(channel); } public static final byte[] channelPageResponse(String channelId, String url) - throws IOException, ExtractionException, InterruptedException { + throws IOException, ExtractionException, InterruptedException { - InfoItemsPage page = ChannelInfo.getMoreItems(Constants.YOUTUBE_SERVICE, - "https://youtube.com/channel/" + channelId, new Page(url)); + InfoItemsPage page = ChannelInfo.getMoreItems(Constants.YOUTUBE_SERVICE, + "https://youtube.com/channel/" + channelId, new Page(url)); - final List relatedStreams = new ObjectArrayList<>(); + 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())); - }); + 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; + String nextpage = page.hasNextPage() ? page.getNextPage().getUrl() : null; - final StreamsPage streamspage = new StreamsPage(nextpage, relatedStreams); + final StreamsPage streamspage = new StreamsPage(nextpage, relatedStreams); - return Constants.mapper.writeValueAsBytes(streamspage); + return Constants.mapper.writeValueAsBytes(streamspage); } public static final byte[] trendingResponse() throws ParsingException, ExtractionException, IOException { - final List relatedStreams = new ObjectArrayList<>(); + final List relatedStreams = new ObjectArrayList<>(); - String url = Constants.YOUTUBE_SERVICE.getKioskList().getListLinkHandlerFactoryByType("Trending") - .getUrl("Trending"); - KioskInfo info = KioskInfo.getInfo(Constants.YOUTUBE_SERVICE, url); + 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), - item.getTextualUploadDate(), item.getDuration(), item.getViewCount())); - }); + 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())); + }); - return Constants.mapper.writeValueAsBytes(relatedStreams); + return Constants.mapper.writeValueAsBytes(relatedStreams); } public static final byte[] playlistResponse(String playlistId) - throws IOException, ExtractionException, InterruptedException { + throws IOException, ExtractionException, InterruptedException { - final PlaylistInfo info = PlaylistInfo.getInfo("https://www.youtube.com/playlist?list=" + playlistId); + final PlaylistInfo info = PlaylistInfo.getInfo("https://www.youtube.com/playlist?list=" + playlistId); - final List relatedStreams = new ObjectArrayList<>(); + 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())); - }); + 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; + 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); + 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.writeValueAsBytes(playlist); + return Constants.mapper.writeValueAsBytes(playlist); } public static final byte[] playlistPageResponse(String playlistId, String url) - throws IOException, ExtractionException, InterruptedException { + throws IOException, ExtractionException, InterruptedException { - InfoItemsPage page = PlaylistInfo.getMoreItems(Constants.YOUTUBE_SERVICE, - "https://www.youtube.com/playlist?list=" + playlistId, new Page(url)); + InfoItemsPage page = PlaylistInfo.getMoreItems(Constants.YOUTUBE_SERVICE, + "https://www.youtube.com/playlist?list=" + playlistId, new Page(url)); - final List relatedStreams = new ObjectArrayList<>(); + 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())); - }); + 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; + String nextpage = page.hasNextPage() ? page.getNextPage().getUrl() : null; - final StreamsPage streamspage = new StreamsPage(nextpage, relatedStreams); + final StreamsPage streamspage = new StreamsPage(nextpage, relatedStreams); - return Constants.mapper.writeValueAsBytes(streamspage); + return Constants.mapper.writeValueAsBytes(streamspage); } public static final byte[] suggestionsResponse(String query) - throws JsonProcessingException, IOException, ExtractionException { + throws JsonProcessingException, IOException, ExtractionException { - return Constants.mapper - .writeValueAsBytes(Constants.YOUTUBE_SERVICE.getSuggestionExtractor().suggestionList(query)); + return Constants.mapper + .writeValueAsBytes(Constants.YOUTUBE_SERVICE.getSuggestionExtractor().suggestionList(query)); } public static final byte[] searchResponse(String q) throws IOException, ExtractionException, InterruptedException { - final SearchInfo info = SearchInfo.getInfo(Constants.YOUTUBE_SERVICE, - Constants.YOUTUBE_SERVICE.getSearchQHFactory().fromQuery(q)); + final SearchInfo info = SearchInfo.getInfo(Constants.YOUTUBE_SERVICE, + Constants.YOUTUBE_SERVICE.getSearchQHFactory().fromQuery(q)); - ObjectArrayList items = new ObjectArrayList<>(); + ObjectArrayList 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; - } - }); + 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; + } + }); - Page nextpage = info.getNextPage(); + Page nextpage = info.getNextPage(); - return nextpage != null - ? Constants.mapper.writeValueAsBytes(new SearchResults(nextpage.getUrl(), nextpage.getId(), items)) - : Constants.mapper.writeValueAsBytes(new SearchResults(null, null, items)); + return nextpage != null + ? Constants.mapper.writeValueAsBytes(new SearchResults(nextpage.getUrl(), nextpage.getId(), items)) + : Constants.mapper.writeValueAsBytes(new SearchResults(null, null, items)); } public static final byte[] searchPageResponse(String q, String url, String id) - throws IOException, ExtractionException, InterruptedException { + throws IOException, ExtractionException, InterruptedException { - InfoItemsPage pages = SearchInfo.getMoreItems(Constants.YOUTUBE_SERVICE, - Constants.YOUTUBE_SERVICE.getSearchQHFactory().fromQuery(q), new Page(url, id)); + InfoItemsPage pages = SearchInfo.getMoreItems(Constants.YOUTUBE_SERVICE, + Constants.YOUTUBE_SERVICE.getSearchQHFactory().fromQuery(q), new Page(url, id)); - ObjectArrayList items = new ObjectArrayList<>(); + ObjectArrayList 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; - } - }); + 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(); + Page nextpage = pages.getNextPage(); - return nextpage != null - ? Constants.mapper.writeValueAsBytes(new SearchResults(nextpage.getUrl(), nextpage.getId(), items)) - : Constants.mapper.writeValueAsBytes(new SearchResults(null, null, items)); + return nextpage != null + ? Constants.mapper.writeValueAsBytes(new SearchResults(nextpage.getUrl(), nextpage.getId(), items)) + : Constants.mapper.writeValueAsBytes(new SearchResults(null, null, items)); } public static final byte[] registerResponse(String user, String pass) throws IOException { - return Constants.mapper.writeValueAsBytes(null); + return Constants.mapper.writeValueAsBytes(null); } 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); + 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")); + 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; + return null; } private static String rewriteURL(final String old) { - if (Constants.debug) - return old; + if (Constants.debug) + return old; - if (old == null || old.isEmpty()) - return null; + if (old == null || old.isEmpty()) + return null; - URL url = null; + URL url = null; - try { - url = new URL(old); - } catch (MalformedURLException e) { - e.printStackTrace(); - } + try { + url = new URL(old); + } catch (MalformedURLException e) { + e.printStackTrace(); + } - final String host = url.getHost(); + final String host = url.getHost(); - String query = url.getQuery(); + String query = url.getQuery(); - boolean hasQuery = query != null; + boolean hasQuery = query != null; - String path = url.getPath(); + String path = url.getPath(); - path = path.replace("-rj", "-rw"); + path = path.replace("-rj", "-rw"); - if (path.startsWith("/vi/") && !path.contains("_live")) { - path = path.replace("/vi/", "/vi_webp/").replace(".jpg", ".webp").replace("hq720", "mqdefault") - .replace("hqdefault", "mqdefault"); + if (path.startsWith("/vi/") && !path.contains("_live")) { + path = path.replace("/vi/", "/vi_webp/").replace(".jpg", ".webp").replace("hq720", "mqdefault") + .replace("hqdefault", "mqdefault"); - hasQuery = false; - } + hasQuery = false; + } - return Constants.PROXY_PART + path + (hasQuery ? "?" + query + "&host=" : "?host=") - + URLUtils.silentEncode(host); + return Constants.PROXY_PART + path + (hasQuery ? "?" + query + "&host=" : "?host=") + + URLUtils.silentEncode(host); } } diff --git a/src/main/java/me/kavin/piped/utils/SponsorBlockUtils.java b/src/main/java/me/kavin/piped/utils/SponsorBlockUtils.java index decce22..6bf6f17 100644 --- a/src/main/java/me/kavin/piped/utils/SponsorBlockUtils.java +++ b/src/main/java/me/kavin/piped/utils/SponsorBlockUtils.java @@ -19,36 +19,36 @@ import me.kavin.piped.consts.Constants; public class SponsorBlockUtils { public static final String getSponsors(String id, String categories) - throws IOException, InterruptedException, NoSuchAlgorithmException, JsonParserException { + throws IOException, InterruptedException, NoSuchAlgorithmException, JsonParserException { - String hash = toSha256(id); + String hash = toSha256(id); - URI uri = URI.create("https://sponsor.ajay.app/api/skipSegments/" + URLUtils.silentEncode(hash.substring(0, 4)) - + "?categories=" + URLUtils.silentEncode(categories)); + URI uri = URI.create("https://sponsor.ajay.app/api/skipSegments/" + URLUtils.silentEncode(hash.substring(0, 4)) + + "?categories=" + URLUtils.silentEncode(categories)); - JsonArray jArray = JsonParser.array() - .from(Constants.h2client.send(HttpRequest.newBuilder(uri).build(), BodyHandlers.ofString()).body()); + JsonArray jArray = JsonParser.array() + .from(Constants.h2client.send(HttpRequest.newBuilder(uri).build(), BodyHandlers.ofString()).body()); - jArray.removeIf(jObject -> !((JsonObject) jObject).getString("videoID").equalsIgnoreCase(id)); + jArray.removeIf(jObject -> !((JsonObject) jObject).getString("videoID").equalsIgnoreCase(id)); - return JsonWriter.string(jArray.getObject(0)); + return JsonWriter.string(jArray.getObject(0)); } private static final String toSha256(final String videoId) throws NoSuchAlgorithmException { - final MessageDigest digest = MessageDigest.getInstance("SHA-256"); - final byte[] bytes = digest.digest(videoId.getBytes(StandardCharsets.UTF_8)); - final StringBuilder sb = new StringBuilder(); + final MessageDigest digest = MessageDigest.getInstance("SHA-256"); + final byte[] bytes = digest.digest(videoId.getBytes(StandardCharsets.UTF_8)); + final StringBuilder sb = new StringBuilder(); - for (final byte b : bytes) { - final String hex = Integer.toHexString(0xff & b); + for (final byte b : bytes) { + final String hex = Integer.toHexString(0xff & b); - if (hex.length() == 1) { - sb.append('0'); - } + if (hex.length() == 1) { + sb.append('0'); + } - sb.append(hex); - } + sb.append(hex); + } - return sb.toString(); + return sb.toString(); } } diff --git a/src/main/java/me/kavin/piped/utils/URLUtils.java b/src/main/java/me/kavin/piped/utils/URLUtils.java index 22349a1..4dc5527 100644 --- a/src/main/java/me/kavin/piped/utils/URLUtils.java +++ b/src/main/java/me/kavin/piped/utils/URLUtils.java @@ -5,11 +5,11 @@ import java.net.URLEncoder; public class URLUtils { public static String silentEncode(String s) { - try { - return URLEncoder.encode(s, "UTF-8"); - } catch (Exception e) { - // ignored - } - return s; + try { + return URLEncoder.encode(s, "UTF-8"); + } catch (Exception e) { + // ignored + } + return s; } } diff --git a/src/main/java/me/kavin/piped/utils/obj/Channel.java b/src/main/java/me/kavin/piped/utils/obj/Channel.java index 8923d08..2138bb7 100644 --- a/src/main/java/me/kavin/piped/utils/obj/Channel.java +++ b/src/main/java/me/kavin/piped/utils/obj/Channel.java @@ -4,16 +4,17 @@ import java.util.List; public class Channel { - public String name, avatarUrl, bannerUrl, description, nextpage; + public String id, name, avatarUrl, bannerUrl, description, nextpage; public List relatedStreams; - public Channel(String name, String avatarUrl, String bannerUrl, String description, String nextpage, - List relatedStreams) { - this.name = name; - this.avatarUrl = avatarUrl; - this.bannerUrl = bannerUrl; - this.description = description; - this.nextpage = nextpage; - this.relatedStreams = relatedStreams; + public Channel(String id, String name, String avatarUrl, String bannerUrl, String description, String nextpage, + List relatedStreams) { + this.id = id; + this.name = name; + this.avatarUrl = avatarUrl; + this.bannerUrl = bannerUrl; + this.description = description; + this.nextpage = nextpage; + this.relatedStreams = relatedStreams; } } diff --git a/src/main/java/me/kavin/piped/utils/obj/ChapterSegment.java b/src/main/java/me/kavin/piped/utils/obj/ChapterSegment.java new file mode 100644 index 0000000..5aba771 --- /dev/null +++ b/src/main/java/me/kavin/piped/utils/obj/ChapterSegment.java @@ -0,0 +1,12 @@ +package me.kavin.piped.utils.obj; + +public class ChapterSegment { + + public String title; + public int start; + + public ChapterSegment(String title, int start) { + this.title = title; + this.start = start; + } +} 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 b7f604a..2b52f56 100644 --- a/src/main/java/me/kavin/piped/utils/obj/PipedStream.java +++ b/src/main/java/me/kavin/piped/utils/obj/PipedStream.java @@ -2,14 +2,49 @@ package me.kavin.piped.utils.obj; public class PipedStream { - public String url, format, quality, mimeType; + public String url, format, quality, mimeType, codec; public boolean videoOnly; + public int bitrate, initStart, initEnd, indexStart, indexEnd, width, height, fps; + 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; + this.url = url; + this.format = format; + this.quality = quality; + this.mimeType = mimeType; + this.videoOnly = videoOnly; + } + + public PipedStream(String url, String format, String quality, String mimeType, boolean videoOnly, int bitrate, + int initStart, int initEnd, int indexStart, int indexEnd, String codec) { + this.url = url; + this.format = format; + this.quality = quality; + this.mimeType = mimeType; + this.videoOnly = videoOnly; + this.bitrate = bitrate; + this.initStart = initStart; + this.initEnd = initEnd; + this.indexStart = indexStart; + this.indexEnd = indexEnd; + this.codec = codec; + } + + public PipedStream(String url, String format, String quality, String mimeType, boolean videoOnly, int bitrate, + int initStart, int initEnd, int indexStart, int indexEnd, String codec, int width, int height, int fps) { + this.url = url; + this.format = format; + this.quality = quality; + this.mimeType = mimeType; + this.videoOnly = videoOnly; + this.bitrate = bitrate; + this.initStart = initStart; + this.initEnd = initEnd; + this.indexStart = indexStart; + this.indexEnd = indexEnd; + this.codec = codec; + this.width = width; + this.height = height; + this.fps = fps; } } diff --git a/src/main/java/me/kavin/piped/utils/obj/Playlist.java b/src/main/java/me/kavin/piped/utils/obj/Playlist.java index 1c7566e..7124eb8 100644 --- a/src/main/java/me/kavin/piped/utils/obj/Playlist.java +++ b/src/main/java/me/kavin/piped/utils/obj/Playlist.java @@ -9,15 +9,15 @@ public class Playlist { 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; + 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/SearchResults.java b/src/main/java/me/kavin/piped/utils/obj/SearchResults.java index 97a9816..c698082 100644 --- a/src/main/java/me/kavin/piped/utils/obj/SearchResults.java +++ b/src/main/java/me/kavin/piped/utils/obj/SearchResults.java @@ -9,8 +9,8 @@ public class SearchResults { public ObjectArrayList items; public SearchResults(String nextpage, String id, ObjectArrayList items) { - this.nextpage = nextpage; - this.id = id; - this.items = items; + this.nextpage = nextpage; + this.id = id; + this.items = items; } } 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 39d2a75..e6415c3 100644 --- a/src/main/java/me/kavin/piped/utils/obj/StreamItem.java +++ b/src/main/java/me/kavin/piped/utils/obj/StreamItem.java @@ -6,14 +6,14 @@ public class StreamItem { public long duration, views; public StreamItem(String url, String title, String thumbnail, String uploaderName, String uploaderUrl, - 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; + 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/Streams.java b/src/main/java/me/kavin/piped/utils/obj/Streams.java index 3f4555b..fa7d578 100644 --- a/src/main/java/me/kavin/piped/utils/obj/Streams.java +++ b/src/main/java/me/kavin/piped/utils/obj/Streams.java @@ -17,25 +17,25 @@ public class Streams { public boolean livestream; 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 audioStreams, List videoStreams, List relatedStreams, - List subtitles, boolean livestream, String hls) { - this.title = title; - this.description = description; - this.uploadDate = uploadDate; - this.uploader = uploader; - this.uploaderUrl = uploaderUrl; - this.uploaderAvatar = uploaderAvatar; - this.thumbnailUrl = thumbnailUrl; - this.duration = duration; - this.views = views; - this.likes = likes; - this.dislikes = dislikes; - this.audioStreams = audioStreams; - this.videoStreams = videoStreams; - this.relatedStreams = relatedStreams; - this.subtitles = subtitles; - this.livestream = livestream; - this.hls = hls; + String uploaderAvatar, String thumbnailUrl, long duration, long views, long likes, long dislikes, + List audioStreams, List videoStreams, List relatedStreams, + List subtitles, boolean livestream, String hls) { + this.title = title; + this.description = description; + this.uploadDate = uploadDate; + this.uploader = uploader; + this.uploaderUrl = uploaderUrl; + this.uploaderAvatar = uploaderAvatar; + this.thumbnailUrl = thumbnailUrl; + this.duration = duration; + this.views = views; + this.likes = likes; + this.dislikes = dislikes; + this.audioStreams = audioStreams; + this.videoStreams = videoStreams; + this.relatedStreams = relatedStreams; + this.subtitles = subtitles; + this.livestream = livestream; + this.hls = hls; } } diff --git a/src/main/java/me/kavin/piped/utils/obj/StreamsPage.java b/src/main/java/me/kavin/piped/utils/obj/StreamsPage.java index 493e717..e6d729c 100644 --- a/src/main/java/me/kavin/piped/utils/obj/StreamsPage.java +++ b/src/main/java/me/kavin/piped/utils/obj/StreamsPage.java @@ -8,7 +8,7 @@ public class StreamsPage { public List relatedStreams; public StreamsPage(String nextpage, List relatedStreams) { - this.nextpage = nextpage; - this.relatedStreams = relatedStreams; + this.nextpage = nextpage; + this.relatedStreams = relatedStreams; } } diff --git a/src/main/java/me/kavin/piped/utils/obj/Subtitle.java b/src/main/java/me/kavin/piped/utils/obj/Subtitle.java index ed5f5ca..5118599 100644 --- a/src/main/java/me/kavin/piped/utils/obj/Subtitle.java +++ b/src/main/java/me/kavin/piped/utils/obj/Subtitle.java @@ -5,7 +5,7 @@ public class Subtitle { public final String url, mimeType; public Subtitle(String url, String mimeType) { - this.url = url; - this.mimeType = mimeType; + this.url = url; + this.mimeType = mimeType; }; } diff --git a/src/main/java/me/kavin/piped/utils/obj/search/SearchItem.java b/src/main/java/me/kavin/piped/utils/obj/search/SearchItem.java index d4014f7..9cb0864 100644 --- a/src/main/java/me/kavin/piped/utils/obj/search/SearchItem.java +++ b/src/main/java/me/kavin/piped/utils/obj/search/SearchItem.java @@ -5,20 +5,20 @@ public class SearchItem { private String name, thumbnail, url; public SearchItem(String name, String thumbnail, String url) { - this.name = name; - this.thumbnail = thumbnail; - this.url = url; + this.name = name; + this.thumbnail = thumbnail; + this.url = url; } public String getName() { - return name; + return name; } public String getThumbnail() { - return thumbnail; + return thumbnail; } public String getUrl() { - return url; + return url; } } diff --git a/src/main/java/me/kavin/piped/utils/obj/search/SearchStream.java b/src/main/java/me/kavin/piped/utils/obj/search/SearchStream.java index dd0c768..839d56f 100644 --- a/src/main/java/me/kavin/piped/utils/obj/search/SearchStream.java +++ b/src/main/java/me/kavin/piped/utils/obj/search/SearchStream.java @@ -5,16 +5,16 @@ public class SearchStream extends SearchItem { private long views, duration; public SearchStream(String name, String thumbnail, String url, long views, long duration) { - super(name, thumbnail, url); - this.views = views; - this.duration = duration; + super(name, thumbnail, url); + this.views = views; + this.duration = duration; } public long getViews() { - return views; + return views; } public long getDuration() { - return duration; + return duration; } }