diff --git a/src/main/java/me/kavin/piped/ServerLauncher.java b/src/main/java/me/kavin/piped/ServerLauncher.java index 5614128..41bc670 100644 --- a/src/main/java/me/kavin/piped/ServerLauncher.java +++ b/src/main/java/me/kavin/piped/ServerLauncher.java @@ -1,26 +1,8 @@ package me.kavin.piped; -import static io.activej.config.converter.ConfigConverters.ofInetSocketAddress; -import static io.activej.http.HttpHeaders.CACHE_CONTROL; -import static io.activej.http.HttpHeaders.CONTENT_TYPE; - -import java.io.ByteArrayInputStream; -import java.net.InetSocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; - -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.jetbrains.annotations.NotNull; -import org.schabi.newpipe.extractor.exceptions.AgeRestrictedContentException; -import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException; -import org.xml.sax.InputSource; - import com.fasterxml.jackson.core.JsonProcessingException; import com.rometools.rome.feed.synd.SyndFeed; import com.rometools.rome.io.SyndFeedInput; - import io.activej.config.Config; import io.activej.http.AsyncServlet; import io.activej.http.HttpMethod; @@ -35,6 +17,22 @@ import me.kavin.piped.utils.CustomServletDecorator; import me.kavin.piped.utils.ResponseHelper; import me.kavin.piped.utils.SponsorBlockUtils; import me.kavin.piped.utils.resp.ErrorResponse; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.jetbrains.annotations.NotNull; +import org.schabi.newpipe.extractor.exceptions.AgeRestrictedContentException; +import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException; +import org.xml.sax.InputSource; + +import java.io.ByteArrayInputStream; +import java.net.InetSocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +import static io.activej.config.converter.ConfigConverters.ofInetSocketAddress; +import static io.activej.http.HttpHeaders.CACHE_CONTROL; +import static io.activej.http.HttpHeaders.CONTENT_TYPE; public class ServerLauncher extends MultithreadedHttpServerLauncher { @@ -147,7 +145,7 @@ public class ServerLauncher extends MultithreadedHttpServerLauncher { } })).map("/trending", AsyncServlet.ofBlocking(executor, request -> { try { - return getJsonResponse(ResponseHelper.trendingResponse(), "public, max-age=3600"); + return getJsonResponse(ResponseHelper.trendingResponse(request.getQueryParameter("region")), "public, max-age=3600"); } catch (Exception e) { return getErrorResponse(e); } diff --git a/src/main/java/me/kavin/piped/utils/ResponseHelper.java b/src/main/java/me/kavin/piped/utils/ResponseHelper.java index 77c19bd..017933e 100644 --- a/src/main/java/me/kavin/piped/utils/ResponseHelper.java +++ b/src/main/java/me/kavin/piped/utils/ResponseHelper.java @@ -1,5 +1,37 @@ package me.kavin.piped.utils; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import me.kavin.piped.consts.Constants; +import me.kavin.piped.ipfs.IPFS; +import me.kavin.piped.utils.obj.*; +import me.kavin.piped.utils.obj.search.SearchChannel; +import me.kavin.piped.utils.obj.search.SearchItem; +import me.kavin.piped.utils.obj.search.SearchPlaylist; +import me.kavin.piped.utils.obj.search.SearchStream; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.json.JSONObject; +import org.schabi.newpipe.extractor.InfoItem; +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.ChannelInfoItem; +import org.schabi.newpipe.extractor.comments.CommentsInfo; +import org.schabi.newpipe.extractor.comments.CommentsInfoItem; +import org.schabi.newpipe.extractor.exceptions.ExtractionException; +import org.schabi.newpipe.extractor.exceptions.ParsingException; +import org.schabi.newpipe.extractor.kiosk.KioskExtractor; +import org.schabi.newpipe.extractor.kiosk.KioskInfo; +import org.schabi.newpipe.extractor.kiosk.KioskList; +import org.schabi.newpipe.extractor.localization.ContentCountry; +import org.schabi.newpipe.extractor.playlist.PlaylistInfo; +import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem; +import org.schabi.newpipe.extractor.search.SearchInfo; +import org.schabi.newpipe.extractor.stream.StreamInfo; +import org.schabi.newpipe.extractor.stream.StreamInfoItem; + import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; @@ -12,47 +44,6 @@ import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.json.JSONObject; -import org.schabi.newpipe.extractor.InfoItem; -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.ChannelInfoItem; -import org.schabi.newpipe.extractor.comments.CommentsInfo; -import org.schabi.newpipe.extractor.comments.CommentsInfoItem; -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.playlist.PlaylistInfoItem; -import org.schabi.newpipe.extractor.search.SearchInfo; -import org.schabi.newpipe.extractor.stream.StreamInfo; -import org.schabi.newpipe.extractor.stream.StreamInfoItem; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.github.benmanes.caffeine.cache.Caffeine; -import com.github.benmanes.caffeine.cache.LoadingCache; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import me.kavin.piped.consts.Constants; -import me.kavin.piped.ipfs.IPFS; -import me.kavin.piped.utils.obj.Channel; -import me.kavin.piped.utils.obj.ChapterSegment; -import me.kavin.piped.utils.obj.Comment; -import me.kavin.piped.utils.obj.CommentsPage; -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.SearchChannel; -import me.kavin.piped.utils.obj.search.SearchItem; -import me.kavin.piped.utils.obj.search.SearchPlaylist; -import me.kavin.piped.utils.obj.search.SearchStream; - public class ResponseHelper { public static final LoadingCache commentsCache = Caffeine.newBuilder() @@ -201,13 +192,17 @@ public class ResponseHelper { } - public static final byte[] trendingResponse() throws ParsingException, ExtractionException, IOException { + public static final byte[] trendingResponse(String region) throws ParsingException, ExtractionException, IOException { + + region = (region == null || region.isEmpty()) ? "US" : region; final List relatedStreams = new ObjectArrayList<>(); - String url = Constants.YOUTUBE_SERVICE.getKioskList().getListLinkHandlerFactoryByType("Trending") - .getUrl("Trending"); - KioskInfo info = KioskInfo.getInfo(Constants.YOUTUBE_SERVICE, url); + KioskList kioskList = Constants.YOUTUBE_SERVICE.getKioskList(); + kioskList.forceContentCountry(new ContentCountry(region)); + KioskExtractor extractor = kioskList.getDefaultKioskExtractor(); + extractor.fetchPage(); + KioskInfo info = KioskInfo.getInfo(extractor); info.getRelatedItems().forEach(o -> { StreamInfoItem item = o; @@ -296,26 +291,26 @@ public class ResponseHelper { 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.getTextualUploadDate(), stream.getUploaderName(), - optionalSubstring(stream.getUploaderUrl(), 23), stream.getViewCount(), stream.getDuration(), - stream.isUploaderVerified())); - break; - case CHANNEL: - ChannelInfoItem channel = (ChannelInfoItem) item; - items.add(new SearchChannel(item.getName(), rewriteURL(item.getThumbnailUrl()), - item.getUrl().substring(23), channel.getDescription(), channel.getSubscriberCount(), - channel.getStreamCount(), channel.isVerified())); - break; - case PLAYLIST: - PlaylistInfoItem playlist = (PlaylistInfoItem) item; - items.add(new SearchPlaylist(item.getName(), rewriteURL(item.getThumbnailUrl()), - item.getUrl().substring(23), playlist.getUploaderName(), playlist.getStreamCount())); - break; - default: - break; + case STREAM: + StreamInfoItem stream = (StreamInfoItem) item; + items.add(new SearchStream(item.getName(), rewriteURL(item.getThumbnailUrl()), + item.getUrl().substring(23), stream.getTextualUploadDate(), stream.getUploaderName(), + optionalSubstring(stream.getUploaderUrl(), 23), stream.getViewCount(), stream.getDuration(), + stream.isUploaderVerified())); + break; + case CHANNEL: + ChannelInfoItem channel = (ChannelInfoItem) item; + items.add(new SearchChannel(item.getName(), rewriteURL(item.getThumbnailUrl()), + item.getUrl().substring(23), channel.getDescription(), channel.getSubscriberCount(), + channel.getStreamCount(), channel.isVerified())); + break; + case PLAYLIST: + PlaylistInfoItem playlist = (PlaylistInfoItem) item; + items.add(new SearchPlaylist(item.getName(), rewriteURL(item.getThumbnailUrl()), + item.getUrl().substring(23), playlist.getUploaderName(), playlist.getStreamCount())); + break; + default: + break; } }); @@ -339,26 +334,26 @@ public class ResponseHelper { 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.getTextualUploadDate(), stream.getUploaderName(), - optionalSubstring(stream.getUploaderUrl(), 23), stream.getViewCount(), stream.getDuration(), - stream.isUploaderVerified())); - break; - case CHANNEL: - ChannelInfoItem channel = (ChannelInfoItem) item; - items.add(new SearchChannel(item.getName(), rewriteURL(item.getThumbnailUrl()), - item.getUrl().substring(23), channel.getDescription(), channel.getSubscriberCount(), - channel.getStreamCount(), channel.isVerified())); - break; - case PLAYLIST: - PlaylistInfoItem playlist = (PlaylistInfoItem) item; - items.add(new SearchPlaylist(item.getName(), rewriteURL(item.getThumbnailUrl()), - item.getUrl().substring(23), playlist.getUploaderName(), playlist.getStreamCount())); - break; - default: - break; + case STREAM: + StreamInfoItem stream = (StreamInfoItem) item; + items.add(new SearchStream(item.getName(), rewriteURL(item.getThumbnailUrl()), + item.getUrl().substring(23), stream.getTextualUploadDate(), stream.getUploaderName(), + optionalSubstring(stream.getUploaderUrl(), 23), stream.getViewCount(), stream.getDuration(), + stream.isUploaderVerified())); + break; + case CHANNEL: + ChannelInfoItem channel = (ChannelInfoItem) item; + items.add(new SearchChannel(item.getName(), rewriteURL(item.getThumbnailUrl()), + item.getUrl().substring(23), channel.getDescription(), channel.getSubscriberCount(), + channel.getStreamCount(), channel.isVerified())); + break; + case PLAYLIST: + PlaylistInfoItem playlist = (PlaylistInfoItem) item; + items.add(new SearchPlaylist(item.getName(), rewriteURL(item.getThumbnailUrl()), + item.getUrl().substring(23), playlist.getUploaderName(), playlist.getStreamCount())); + break; + default: + break; } }); @@ -430,7 +425,7 @@ public class ResponseHelper { 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); + .getJSONObject("data").getJSONObject("videos").optString(videoId); if (!lbryId.isEmpty()) new JSONObject(Constants.h2client.send(HttpRequest