Skip to content

Commit

Permalink
Merge pull request #781 from Bnyro/feed-cleanup
Browse files Browse the repository at this point in the history
refactor: simplify FeedHandlers.java by introducing FeedHelpers.java
  • Loading branch information
Bnyro authored Mar 15, 2024
2 parents 25a49ce + b0c6116 commit c70b9dd
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 114 deletions.
132 changes: 18 additions & 114 deletions src/main/java/me/kavin/piped/server/handlers/auth/FeedHandlers.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@
import com.rometools.rome.feed.synd.*;
import com.rometools.rome.io.FeedException;
import com.rometools.rome.io.SyndFeedOutput;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.JoinType;
import me.kavin.piped.consts.Constants;
import me.kavin.piped.utils.*;
import me.kavin.piped.utils.obj.StreamItem;
Expand Down Expand Up @@ -104,24 +101,7 @@ public static byte[] feedResponse(String session) throws IOException {
if (user != null) {
try (StatelessSession s = DatabaseSessionFactory.createStatelessSession()) {

CriteriaBuilder cb = s.getCriteriaBuilder();

// Get all videos from subscribed channels, with channel info
CriteriaQuery<Video> criteria = cb.createQuery(Video.class);
var root = criteria.from(Video.class);
root.fetch("channel", JoinType.RIGHT);
var subquery = criteria.subquery(String.class);
var subroot = subquery.from(User.class);
subquery.select(subroot.get("subscribed_ids"))
.where(cb.equal(subroot.get("id"), user.getId()));

criteria.select(root)
.where(
root.get("channel").get("uploader_id").in(subquery)
)
.orderBy(cb.desc(root.get("uploaded")));

List<StreamItem> feedItems = s.createQuery(criteria).setTimeout(20).stream()
List<StreamItem> feedItems = FeedHelpers.generateAuthenticatedFeed(s, user.getId(), Integer.MAX_VALUE)
.parallel().map(video -> {
var channel = video.getChannel();

Expand All @@ -147,41 +127,13 @@ public static byte[] feedResponseRSS(String session) throws FeedException {
User user = DatabaseHelper.getUserFromSession(session);

if (user != null) {

try (StatelessSession s = DatabaseSessionFactory.createStatelessSession()) {
SyndFeed feed = FeedHelpers.createRssFeed(user.getUsername());

SyndFeed feed = new SyndFeedImpl();
feed.setFeedType("atom_1.0");
feed.setTitle("Piped - Feed");
feed.setDescription(String.format("Piped's RSS subscription feed for %s.", user.getUsername()));
feed.setUri(Constants.FRONTEND_URL + "/feed");
feed.setPublishedDate(new Date());

CriteriaBuilder cb = s.getCriteriaBuilder();

// Get all videos from subscribed channels, with channel info
CriteriaQuery<Video> criteria = cb.createQuery(Video.class);
var root = criteria.from(Video.class);
root.fetch("channel", JoinType.RIGHT);
var subquery = criteria.subquery(String.class);
var subroot = subquery.from(User.class);
subquery.select(subroot.get("subscribed_ids"))
.where(cb.equal(subroot.get("id"), user.getId()));

criteria.select(root)
.where(
root.get("channel").get("uploader_id").in(subquery)
)
.orderBy(cb.desc(root.get("uploaded")));

final List<SyndEntry> entries = s.createQuery(criteria)
.setTimeout(20)
.setMaxResults(100)
.stream()
final List<SyndEntry> entries = FeedHelpers.generateAuthenticatedFeed(s, user.getId(), 100)
.map(video -> {
var channel = video.getChannel();
SyndEntry entry = ChannelHelpers.createEntry(video, channel);
return entry;
return ChannelHelpers.createEntry(video, channel);
}).toList();

feed.setEntries(entries);
Expand All @@ -196,29 +148,15 @@ public static byte[] feedResponseRSS(String session) throws FeedException {

public static byte[] unauthenticatedFeedResponse(String[] channelIds) throws Exception {

Set<String> filtered = Arrays.stream(channelIds)
Set<String> filteredChannels = Arrays.stream(channelIds)
.filter(ChannelHelpers::isValidId)
.collect(Collectors.toUnmodifiableSet());

if (filtered.isEmpty())
if (filteredChannels.isEmpty())
return mapper.writeValueAsBytes(Collections.EMPTY_LIST);

try (StatelessSession s = DatabaseSessionFactory.createStatelessSession()) {

CriteriaBuilder cb = s.getCriteriaBuilder();

// Get all videos from subscribed channels, with channel info
CriteriaQuery<Video> criteria = cb.createQuery(Video.class);
var root = criteria.from(Video.class);
root.fetch("channel", JoinType.RIGHT);

criteria.select(root)
.where(cb.and(
root.get("channel").get("id").in(filtered)
))
.orderBy(cb.desc(root.get("uploaded")));

List<StreamItem> feedItems = s.createQuery(criteria).setTimeout(20).stream()
List<StreamItem> feedItems = FeedHelpers.generateUnauthenticatedFeed(s, filteredChannels, Integer.MAX_VALUE)
.parallel().map(video -> {
var channel = video.getChannel();

Expand All @@ -228,8 +166,8 @@ public static byte[] unauthenticatedFeedResponse(String[] channelIds) throws Exc
video.getUploaded(), channel.isVerified(), video.isShort());
}).toList();

updateSubscribedTime(filtered);
addMissingChannels(filtered);
updateSubscribedTime(filteredChannels);
addMissingChannels(filteredChannels);

return mapper.writeValueAsBytes(feedItems);
}
Expand All @@ -245,39 +183,13 @@ public static byte[] unauthenticatedFeedResponseRSS(String[] channelIds) throws
ExceptionHandler.throwErrorResponse(new InvalidRequestResponse("No valid channel IDs provided"));

try (StatelessSession s = DatabaseSessionFactory.createStatelessSession()) {
List<Video> videos = FeedHelpers.generateUnauthenticatedFeed(s, filteredChannels, 100).toList();

CriteriaBuilder cb = s.getCriteriaBuilder();

// Get all videos from subscribed channels, with channel info
CriteriaQuery<Video> criteria = cb.createQuery(Video.class);
var root = criteria.from(Video.class);
root.fetch("channel", JoinType.RIGHT);
List<SyndEntry> entries = videos.stream()
.map(video -> ChannelHelpers.createEntry(video, video.getChannel()))
.toList();

criteria.select(root)
.where(cb.and(
root.get("channel").get("id").in(filteredChannels)
))
.orderBy(cb.desc(root.get("uploaded")));

List<Video> videos = s.createQuery(criteria)
.setTimeout(20)
.setMaxResults(100)
.list();

SyndFeed feed = new SyndFeedImpl();
feed.setFeedType("atom_1.0");
feed.setTitle("Piped - Feed");
feed.setDescription("Piped's RSS unauthenticated subscription feed.");
feed.setUri(Constants.FRONTEND_URL + "/feed");
feed.setPublishedDate(new Date());

final List<SyndEntry> entries = new ObjectArrayList<>();

for (Video video : videos) {
var channel = video.getChannel();
SyndEntry entry = ChannelHelpers.createEntry(video, channel);
entries.add(entry);
}
SyndFeed feed = FeedHelpers.createRssFeed(null);

if (filteredChannels.size() == 1) {
if (!videos.isEmpty()) {
Expand Down Expand Up @@ -440,12 +352,8 @@ public static byte[] subscriptionsResponse(String session)
query.select(root)
.where(root.get("uploader_id").in(subquery));

List<SubscriptionChannel> subscriptionItems = s.createQuery(query)
.stream().parallel()
.filter(channel -> channel.getUploader() != null)
.sorted(Comparator.comparing(Channel::getUploader, String.CASE_INSENSITIVE_ORDER))
.map(channel -> new SubscriptionChannel("/channel/" + channel.getUploaderId(),
channel.getUploader(), rewriteURL(channel.getUploaderAvatar()), channel.isVerified()))
List<SubscriptionChannel> subscriptionItems = FeedHelpers
.generateSubscriptionsList(s.createQuery(query).stream())
.toList();

return mapper.writeValueAsBytes(subscriptionItems);
Expand Down Expand Up @@ -475,12 +383,8 @@ public static byte[] unauthenticatedSubscriptionsResponse(String[] channelIds)
query.select(root);
query.where(root.get("uploader_id").in(filtered));

List<SubscriptionChannel> subscriptionItems = s.createQuery(query)
.stream().parallel()
.filter(channel -> channel.getUploader() != null)
.sorted(Comparator.comparing(Channel::getUploader, String.CASE_INSENSITIVE_ORDER))
.map(channel -> new SubscriptionChannel("/channel/" + channel.getUploaderId(),
channel.getUploader(), rewriteURL(channel.getUploaderAvatar()), channel.isVerified()))
List<SubscriptionChannel> subscriptionItems = FeedHelpers
.generateSubscriptionsList(s.createQuery(query).stream())
.toList();

return mapper.writeValueAsBytes(subscriptionItems);
Expand Down
89 changes: 89 additions & 0 deletions src/main/java/me/kavin/piped/utils/FeedHelpers.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package me.kavin.piped.utils;

import com.rometools.rome.feed.synd.SyndFeed;
import com.rometools.rome.feed.synd.SyndFeedImpl;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.JoinType;
import me.kavin.piped.consts.Constants;
import me.kavin.piped.utils.obj.SubscriptionChannel;
import me.kavin.piped.utils.obj.db.Channel;
import me.kavin.piped.utils.obj.db.User;
import me.kavin.piped.utils.obj.db.Video;
import org.hibernate.StatelessSession;

import javax.annotation.Nullable;
import java.util.Comparator;
import java.util.Date;
import java.util.Set;
import java.util.stream.Stream;

import static me.kavin.piped.utils.URLUtils.rewriteURL;

public class FeedHelpers {
public static Stream<Video> generateAuthenticatedFeed(StatelessSession s, long userId, int maxResults) {
CriteriaBuilder cb = s.getCriteriaBuilder();

// Get all videos from subscribed channels, with channel info
CriteriaQuery<Video> criteria = cb.createQuery(Video.class);
var root = criteria.from(Video.class);
root.fetch("channel", JoinType.RIGHT);
var subquery = criteria.subquery(String.class);
var subroot = subquery.from(User.class);
subquery.select(subroot.get("subscribed_ids"))
.where(cb.equal(subroot.get("id"), userId));

criteria.select(root)
.where(
root.get("channel").get("uploader_id").in(subquery)
)
.orderBy(cb.desc(root.get("uploaded")));

return s.createQuery(criteria).setTimeout(20).setMaxResults(maxResults).stream();
}

public static Stream<Video> generateUnauthenticatedFeed(StatelessSession s, Set<String> channelIds, int maxResults) {
CriteriaBuilder cb = s.getCriteriaBuilder();

// Get all videos from subscribed channels, with channel info
CriteriaQuery<Video> criteria = cb.createQuery(Video.class);
var root = criteria.from(Video.class);
root.fetch("channel", JoinType.RIGHT);

criteria.select(root)
.where(cb.and(
root.get("channel").get("id").in(channelIds)
))
.orderBy(cb.desc(root.get("uploaded")));

return s.createQuery(criteria)
.setTimeout(20)
.setMaxResults(maxResults)
.stream();
}

public static SyndFeed createRssFeed(@Nullable String username) {
SyndFeed feed = new SyndFeedImpl();
feed.setFeedType("atom_1.0");
feed.setTitle("Piped - Feed");

if (username == null) {
feed.setDescription("Piped's RSS unauthenticated subscription feed.");
} else {
feed.setDescription(String.format("Piped's RSS subscription feed for %s.", username));
}

feed.setUri(Constants.FRONTEND_URL + "/feed");
feed.setPublishedDate(new Date());

return feed;
}

public static Stream<SubscriptionChannel> generateSubscriptionsList(Stream<Channel> channels) {
return channels.parallel()
.filter(channel -> channel.getUploader() != null)
.sorted(Comparator.comparing(Channel::getUploader, String.CASE_INSENSITIVE_ORDER))
.map(channel -> new SubscriptionChannel("/channel/" + channel.getUploaderId(),
channel.getUploader(), rewriteURL(channel.getUploaderAvatar()), channel.isVerified()));
}
}

0 comments on commit c70b9dd

Please sign in to comment.