2020-11-12 21:19:45 +00:00
|
|
|
package me.kavin.piped;
|
|
|
|
|
|
|
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
|
|
|
import org.schabi.newpipe.extractor.NewPipe;
|
|
|
|
import org.schabi.newpipe.extractor.localization.Localization;
|
|
|
|
|
2021-01-12 08:16:49 +00:00
|
|
|
import com.rometools.rome.feed.synd.SyndFeed;
|
|
|
|
import com.rometools.rome.io.SyndFeedInput;
|
|
|
|
import com.rometools.rome.io.XmlReader;
|
|
|
|
|
2020-11-15 08:47:50 +00:00
|
|
|
import io.netty.buffer.ByteBufAllocator;
|
2020-11-12 21:19:45 +00:00
|
|
|
import io.netty.handler.codec.http.QueryStringDecoder;
|
|
|
|
import me.kavin.piped.consts.Constants;
|
|
|
|
import me.kavin.piped.utils.DownloaderImpl;
|
|
|
|
import me.kavin.piped.utils.ResponseHelper;
|
|
|
|
import me.kavin.piped.utils.SponsorBlockUtils;
|
|
|
|
import reactor.core.publisher.Flux;
|
|
|
|
import reactor.netty.ByteBufFlux;
|
2020-11-15 08:47:50 +00:00
|
|
|
import reactor.netty.NettyOutbound;
|
2020-11-12 21:19:45 +00:00
|
|
|
import reactor.netty.http.server.HttpServer;
|
2020-11-15 08:47:50 +00:00
|
|
|
import reactor.netty.http.server.HttpServerResponse;
|
2020-11-12 21:19:45 +00:00
|
|
|
|
2021-02-05 17:22:08 +00:00
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
|
|
|
|
|
import static io.netty.handler.codec.http.HttpHeaderNames.*;
|
|
|
|
|
2020-11-12 21:19:45 +00:00
|
|
|
public class Main {
|
|
|
|
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
|
|
|
|
|
|
NewPipe.init(new DownloaderImpl(), new Localization("en", "US"));
|
|
|
|
|
|
|
|
HttpServer.create().port(Constants.PORT).route(routes -> {
|
|
|
|
|
|
|
|
routes.get("/webhooks/pubsub", (req, res) -> {
|
|
|
|
|
2021-01-30 15:08:52 +00:00
|
|
|
long start = System.nanoTime();
|
2020-11-12 21:19:45 +00:00
|
|
|
QueryStringDecoder query = new QueryStringDecoder(req.uri());
|
|
|
|
|
|
|
|
try {
|
2021-01-30 15:08:52 +00:00
|
|
|
return writeResponse(res, query.parameters().get("hub.challenge").get(0), 200, "private", start);
|
2020-11-12 21:19:45 +00:00
|
|
|
} catch (Exception e) {
|
|
|
|
e.printStackTrace();
|
2021-01-30 15:08:52 +00:00
|
|
|
return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start);
|
2020-11-12 21:19:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
routes.post("/webhooks/pubsub", (req, res) -> {
|
|
|
|
|
2021-01-30 15:08:52 +00:00
|
|
|
long start = System.nanoTime();
|
|
|
|
|
2020-11-12 21:19:45 +00:00
|
|
|
try {
|
2021-01-12 08:15:09 +00:00
|
|
|
req.receive().asInputStream().subscribe(in -> {
|
|
|
|
try {
|
|
|
|
SyndFeed feed = new SyndFeedInput().build(new XmlReader(in));
|
|
|
|
|
2021-01-30 15:08:52 +00:00
|
|
|
feed.getEntries().forEach(entry -> {
|
|
|
|
System.out.println(entry.getLinks().get(0).getHref());
|
|
|
|
System.out.println(entry.getAuthors().get(0).getUri());
|
|
|
|
});
|
2021-01-12 08:15:09 +00:00
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
});
|
2021-01-30 15:08:52 +00:00
|
|
|
return writeResponse(res, "ok", 200, "private", start);
|
2020-11-12 21:19:45 +00:00
|
|
|
} catch (Exception e) {
|
2021-01-30 15:08:52 +00:00
|
|
|
e.printStackTrace();
|
|
|
|
return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start);
|
2020-11-12 21:19:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
routes.get("/sponsors/{videoId}", (req, res) -> {
|
|
|
|
|
2021-01-30 15:08:52 +00:00
|
|
|
long start = System.nanoTime();
|
2020-11-12 21:19:45 +00:00
|
|
|
QueryStringDecoder query = new QueryStringDecoder(req.uri());
|
|
|
|
|
|
|
|
try {
|
2020-11-15 08:47:50 +00:00
|
|
|
return writeResponse(res, SponsorBlockUtils.getSponsors(req.param("videoId"),
|
2021-01-30 15:08:52 +00:00
|
|
|
query.parameters().get("category").get(0)), 200, "public, max-age=3600", start);
|
2020-11-12 21:19:45 +00:00
|
|
|
} catch (Exception e) {
|
|
|
|
e.printStackTrace();
|
2021-01-30 15:08:52 +00:00
|
|
|
return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start);
|
2020-11-12 21:19:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
routes.get("/streams/{videoId}", (req, res) -> {
|
|
|
|
|
2021-01-30 15:08:52 +00:00
|
|
|
long start = System.nanoTime();
|
2020-11-12 21:19:45 +00:00
|
|
|
try {
|
|
|
|
// The stream links are valid for 6 hours.
|
2020-11-15 11:57:04 +00:00
|
|
|
return writeResponse(res, ResponseHelper.streamsResponse(req.param("videoId")), 200,
|
2021-01-30 15:08:52 +00:00
|
|
|
"public, s-maxage=21540", start);
|
2020-11-12 21:19:45 +00:00
|
|
|
} catch (Exception e) {
|
|
|
|
e.printStackTrace();
|
2021-01-30 15:08:52 +00:00
|
|
|
return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start);
|
2020-11-12 21:19:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
routes.get("/channels/{channelId}", (req, res) -> {
|
|
|
|
|
2021-01-30 15:08:52 +00:00
|
|
|
long start = System.nanoTime();
|
2020-11-12 21:19:45 +00:00
|
|
|
try {
|
2020-11-15 08:47:50 +00:00
|
|
|
return writeResponse(res, ResponseHelper.channelResponse(req.param("channelId")), 200,
|
2021-01-30 15:08:52 +00:00
|
|
|
"public, max-age=600", start);
|
2020-11-12 21:19:45 +00:00
|
|
|
} catch (Exception e) {
|
|
|
|
e.printStackTrace();
|
2021-01-30 15:08:52 +00:00
|
|
|
return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start);
|
2020-11-12 21:19:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
2020-11-25 05:26:25 +00:00
|
|
|
routes.get("/nextpage/channels/{channelId}", (req, res) -> {
|
|
|
|
|
2021-01-30 15:08:52 +00:00
|
|
|
long start = System.nanoTime();
|
2020-11-25 05:26:25 +00:00
|
|
|
QueryStringDecoder query = new QueryStringDecoder(req.uri());
|
|
|
|
|
|
|
|
try {
|
|
|
|
return writeResponse(res, ResponseHelper.channelPageResponse(req.param("channelId"),
|
2021-01-30 15:08:52 +00:00
|
|
|
query.parameters().get("url").get(0)), 200, "public, max-age=3600", start);
|
2020-11-25 05:26:25 +00:00
|
|
|
} catch (Exception e) {
|
|
|
|
e.printStackTrace();
|
2021-01-30 15:08:52 +00:00
|
|
|
return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start);
|
2020-11-25 05:26:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
2021-01-04 05:47:28 +00:00
|
|
|
routes.get("/playlists/{playlistId}", (req, res) -> {
|
|
|
|
|
2021-01-30 15:08:52 +00:00
|
|
|
long start = System.nanoTime();
|
2021-01-04 05:47:28 +00:00
|
|
|
try {
|
|
|
|
return writeResponse(res, ResponseHelper.playlistResponse(req.param("playlistId")), 200,
|
2021-01-30 15:08:52 +00:00
|
|
|
"public, max-age=600", start);
|
2021-01-04 05:47:28 +00:00
|
|
|
} catch (Exception e) {
|
|
|
|
e.printStackTrace();
|
2021-01-30 15:08:52 +00:00
|
|
|
return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start);
|
2021-01-04 05:47:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
routes.get("/nextpage/playlists/{playlistId}", (req, res) -> {
|
|
|
|
|
2021-01-30 15:08:52 +00:00
|
|
|
long start = System.nanoTime();
|
2021-01-04 05:47:28 +00:00
|
|
|
QueryStringDecoder query = new QueryStringDecoder(req.uri());
|
|
|
|
|
|
|
|
try {
|
|
|
|
return writeResponse(res, ResponseHelper.playlistPageResponse(req.param("playlistId"),
|
2021-01-30 15:08:52 +00:00
|
|
|
query.parameters().get("url").get(0)), 200, "public, max-age=3600", start);
|
2021-01-04 05:47:28 +00:00
|
|
|
} catch (Exception e) {
|
|
|
|
e.printStackTrace();
|
2021-01-30 15:08:52 +00:00
|
|
|
return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start);
|
2021-01-04 05:47:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
2020-11-25 05:26:25 +00:00
|
|
|
routes.get("/suggestions", (req, res) -> {
|
|
|
|
|
2021-01-30 15:08:52 +00:00
|
|
|
long start = System.nanoTime();
|
2020-11-25 05:26:25 +00:00
|
|
|
QueryStringDecoder query = new QueryStringDecoder(req.uri());
|
|
|
|
|
|
|
|
try {
|
|
|
|
return writeResponse(res,
|
|
|
|
ResponseHelper.suggestionsResponse(query.parameters().get("query").get(0)), 200,
|
2021-01-30 15:08:52 +00:00
|
|
|
"public, max-age=600", start);
|
2020-11-25 05:26:25 +00:00
|
|
|
} catch (Exception e) {
|
|
|
|
e.printStackTrace();
|
2021-01-30 15:08:52 +00:00
|
|
|
return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start);
|
2020-11-25 05:26:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
2020-12-09 13:30:42 +00:00
|
|
|
routes.get("/search", (req, res) -> {
|
|
|
|
|
2021-01-30 15:08:52 +00:00
|
|
|
long start = System.nanoTime();
|
2020-12-09 13:30:42 +00:00
|
|
|
QueryStringDecoder query = new QueryStringDecoder(req.uri());
|
|
|
|
|
|
|
|
try {
|
|
|
|
return writeResponse(res, ResponseHelper.searchResponse(query.parameters().get("q").get(0)), 200,
|
2021-01-30 15:08:52 +00:00
|
|
|
"public, max-age=600", start);
|
2020-12-09 13:30:42 +00:00
|
|
|
} catch (Exception e) {
|
|
|
|
e.printStackTrace();
|
2021-01-30 15:08:52 +00:00
|
|
|
return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start);
|
2020-12-09 13:30:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
2020-12-14 07:11:42 +00:00
|
|
|
routes.get("/nextpage/search", (req, res) -> {
|
|
|
|
|
2021-01-30 15:08:52 +00:00
|
|
|
long start = System.nanoTime();
|
2020-12-14 07:11:42 +00:00
|
|
|
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)),
|
2021-01-30 15:08:52 +00:00
|
|
|
200, "public, max-age=3600", start);
|
2020-12-14 07:11:42 +00:00
|
|
|
} catch (Exception e) {
|
|
|
|
e.printStackTrace();
|
2021-01-30 15:08:52 +00:00
|
|
|
return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start);
|
2020-12-14 07:11:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
2020-11-12 21:19:45 +00:00
|
|
|
routes.get("/trending", (req, res) -> {
|
|
|
|
|
2021-01-30 15:08:52 +00:00
|
|
|
long start = System.nanoTime();
|
2020-11-12 21:19:45 +00:00
|
|
|
try {
|
2021-01-30 15:08:52 +00:00
|
|
|
return writeResponse(res, ResponseHelper.trendingResponse(), 200, "public, max-age=3600", start);
|
2020-11-12 21:19:45 +00:00
|
|
|
} catch (Exception e) {
|
|
|
|
e.printStackTrace();
|
2021-01-30 15:08:52 +00:00
|
|
|
return writeResponse(res, ExceptionUtils.getStackTrace(e), 500, "private", start);
|
2020-11-12 21:19:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}).bindNow();
|
|
|
|
|
|
|
|
Thread.sleep(Long.MAX_VALUE);
|
|
|
|
}
|
2020-11-15 08:47:50 +00:00
|
|
|
|
2021-01-30 15:08:52 +00:00
|
|
|
public static NettyOutbound writeResponse(HttpServerResponse res, String resp, int code, String cache, long time) {
|
2021-02-05 17:22:08 +00:00
|
|
|
return writeResponse(res, resp.getBytes(StandardCharsets.UTF_8), code, cache, time);
|
2020-11-15 08:47:50 +00:00
|
|
|
}
|
2021-01-12 08:15:09 +00:00
|
|
|
|
2021-01-30 15:08:52 +00:00
|
|
|
public static NettyOutbound writeResponse(HttpServerResponse res, byte[] resp, int code, String cache, long time) {
|
2021-02-05 17:53:05 +00:00
|
|
|
return res.compression(true)
|
|
|
|
.status(code)
|
|
|
|
.addHeader(ACCESS_CONTROL_ALLOW_ORIGIN, "*")
|
|
|
|
.addHeader(CACHE_CONTROL, cache)
|
2021-01-30 15:08:52 +00:00
|
|
|
.addHeader("Server-Timing", "app;dur=" + (System.nanoTime() - time) / 1000000.0)
|
2021-01-12 08:15:09 +00:00
|
|
|
.sendByteArray(Flux.just(resp));
|
|
|
|
}
|
|
|
|
|
|
|
|
public static NettyOutbound writeResponse(HttpServerResponse res, Flux<String> resp, int code, String cache) {
|
2021-02-05 17:53:05 +00:00
|
|
|
return res.compression(true)
|
|
|
|
.status(code)
|
|
|
|
.addHeader(ACCESS_CONTROL_ALLOW_ORIGIN, "*")
|
|
|
|
.addHeader(CACHE_CONTROL, cache)
|
2021-01-12 08:15:09 +00:00
|
|
|
.send(ByteBufFlux.fromString(resp, java.nio.charset.StandardCharsets.UTF_8, ByteBufAllocator.DEFAULT));
|
|
|
|
}
|
2020-11-12 21:19:45 +00:00
|
|
|
}
|