Support region localization for trending

This commit is contained in:
bopol 2021-07-04 16:24:24 +02:00
parent 1af5754f18
commit 616de20f5b
2 changed files with 98 additions and 105 deletions

View file

@ -1,26 +1,8 @@
package me.kavin.piped; 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.fasterxml.jackson.core.JsonProcessingException;
import com.rometools.rome.feed.synd.SyndFeed; import com.rometools.rome.feed.synd.SyndFeed;
import com.rometools.rome.io.SyndFeedInput; import com.rometools.rome.io.SyndFeedInput;
import io.activej.config.Config; import io.activej.config.Config;
import io.activej.http.AsyncServlet; import io.activej.http.AsyncServlet;
import io.activej.http.HttpMethod; 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.ResponseHelper;
import me.kavin.piped.utils.SponsorBlockUtils; import me.kavin.piped.utils.SponsorBlockUtils;
import me.kavin.piped.utils.resp.ErrorResponse; 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 { public class ServerLauncher extends MultithreadedHttpServerLauncher {
@ -147,7 +145,7 @@ public class ServerLauncher extends MultithreadedHttpServerLauncher {
} }
})).map("/trending", AsyncServlet.ofBlocking(executor, request -> { })).map("/trending", AsyncServlet.ofBlocking(executor, request -> {
try { try {
return getJsonResponse(ResponseHelper.trendingResponse(), "public, max-age=3600"); return getJsonResponse(ResponseHelper.trendingResponse(request.getQueryParameter("region")), "public, max-age=3600");
} catch (Exception e) { } catch (Exception e) {
return getErrorResponse(e); return getErrorResponse(e);
} }

View file

@ -1,5 +1,37 @@
package me.kavin.piped.utils; 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.io.IOException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
@ -12,47 +44,6 @@ import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.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 class ResponseHelper {
public static final LoadingCache<String, CommentsInfo> commentsCache = Caffeine.newBuilder() public static final LoadingCache<String, CommentsInfo> 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<StreamItem> relatedStreams = new ObjectArrayList<>(); final List<StreamItem> relatedStreams = new ObjectArrayList<>();
String url = Constants.YOUTUBE_SERVICE.getKioskList().getListLinkHandlerFactoryByType("Trending") KioskList kioskList = Constants.YOUTUBE_SERVICE.getKioskList();
.getUrl("Trending"); kioskList.forceContentCountry(new ContentCountry(region));
KioskInfo info = KioskInfo.getInfo(Constants.YOUTUBE_SERVICE, url); KioskExtractor extractor = kioskList.getDefaultKioskExtractor();
extractor.fetchPage();
KioskInfo info = KioskInfo.getInfo(extractor);
info.getRelatedItems().forEach(o -> { info.getRelatedItems().forEach(o -> {
StreamInfoItem item = o; StreamInfoItem item = o;
@ -296,26 +291,26 @@ public class ResponseHelper {
info.getRelatedItems().forEach(item -> { info.getRelatedItems().forEach(item -> {
switch (item.getInfoType()) { switch (item.getInfoType()) {
case STREAM: case STREAM:
StreamInfoItem stream = (StreamInfoItem) item; StreamInfoItem stream = (StreamInfoItem) item;
items.add(new SearchStream(item.getName(), rewriteURL(item.getThumbnailUrl()), items.add(new SearchStream(item.getName(), rewriteURL(item.getThumbnailUrl()),
item.getUrl().substring(23), stream.getTextualUploadDate(), stream.getUploaderName(), item.getUrl().substring(23), stream.getTextualUploadDate(), stream.getUploaderName(),
optionalSubstring(stream.getUploaderUrl(), 23), stream.getViewCount(), stream.getDuration(), optionalSubstring(stream.getUploaderUrl(), 23), stream.getViewCount(), stream.getDuration(),
stream.isUploaderVerified())); stream.isUploaderVerified()));
break; break;
case CHANNEL: case CHANNEL:
ChannelInfoItem channel = (ChannelInfoItem) item; ChannelInfoItem channel = (ChannelInfoItem) item;
items.add(new SearchChannel(item.getName(), rewriteURL(item.getThumbnailUrl()), items.add(new SearchChannel(item.getName(), rewriteURL(item.getThumbnailUrl()),
item.getUrl().substring(23), channel.getDescription(), channel.getSubscriberCount(), item.getUrl().substring(23), channel.getDescription(), channel.getSubscriberCount(),
channel.getStreamCount(), channel.isVerified())); channel.getStreamCount(), channel.isVerified()));
break; break;
case PLAYLIST: case PLAYLIST:
PlaylistInfoItem playlist = (PlaylistInfoItem) item; PlaylistInfoItem playlist = (PlaylistInfoItem) item;
items.add(new SearchPlaylist(item.getName(), rewriteURL(item.getThumbnailUrl()), items.add(new SearchPlaylist(item.getName(), rewriteURL(item.getThumbnailUrl()),
item.getUrl().substring(23), playlist.getUploaderName(), playlist.getStreamCount())); item.getUrl().substring(23), playlist.getUploaderName(), playlist.getStreamCount()));
break; break;
default: default:
break; break;
} }
}); });
@ -339,26 +334,26 @@ public class ResponseHelper {
pages.getItems().forEach(item -> { pages.getItems().forEach(item -> {
switch (item.getInfoType()) { switch (item.getInfoType()) {
case STREAM: case STREAM:
StreamInfoItem stream = (StreamInfoItem) item; StreamInfoItem stream = (StreamInfoItem) item;
items.add(new SearchStream(item.getName(), rewriteURL(item.getThumbnailUrl()), items.add(new SearchStream(item.getName(), rewriteURL(item.getThumbnailUrl()),
item.getUrl().substring(23), stream.getTextualUploadDate(), stream.getUploaderName(), item.getUrl().substring(23), stream.getTextualUploadDate(), stream.getUploaderName(),
optionalSubstring(stream.getUploaderUrl(), 23), stream.getViewCount(), stream.getDuration(), optionalSubstring(stream.getUploaderUrl(), 23), stream.getViewCount(), stream.getDuration(),
stream.isUploaderVerified())); stream.isUploaderVerified()));
break; break;
case CHANNEL: case CHANNEL:
ChannelInfoItem channel = (ChannelInfoItem) item; ChannelInfoItem channel = (ChannelInfoItem) item;
items.add(new SearchChannel(item.getName(), rewriteURL(item.getThumbnailUrl()), items.add(new SearchChannel(item.getName(), rewriteURL(item.getThumbnailUrl()),
item.getUrl().substring(23), channel.getDescription(), channel.getSubscriberCount(), item.getUrl().substring(23), channel.getDescription(), channel.getSubscriberCount(),
channel.getStreamCount(), channel.isVerified())); channel.getStreamCount(), channel.isVerified()));
break; break;
case PLAYLIST: case PLAYLIST:
PlaylistInfoItem playlist = (PlaylistInfoItem) item; PlaylistInfoItem playlist = (PlaylistInfoItem) item;
items.add(new SearchPlaylist(item.getName(), rewriteURL(item.getThumbnailUrl()), items.add(new SearchPlaylist(item.getName(), rewriteURL(item.getThumbnailUrl()),
item.getUrl().substring(23), playlist.getUploaderName(), playlist.getStreamCount())); item.getUrl().substring(23), playlist.getUploaderName(), playlist.getStreamCount()));
break; break;
default: default:
break; break;
} }
}); });
@ -430,7 +425,7 @@ public class ResponseHelper {
String lbryId = new JSONObject(Constants.h2client.send(HttpRequest String lbryId = new JSONObject(Constants.h2client.send(HttpRequest
.newBuilder(URI.create("https://api.lbry.com/yt/resolve?video_ids=" + URLUtils.silentEncode(videoId))) .newBuilder(URI.create("https://api.lbry.com/yt/resolve?video_ids=" + URLUtils.silentEncode(videoId)))
.setHeader("User-Agent", Constants.USER_AGENT).build(), BodyHandlers.ofString()).body()) .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()) if (!lbryId.isEmpty())
new JSONObject(Constants.h2client.send(HttpRequest new JSONObject(Constants.h2client.send(HttpRequest