Skip to content

Commit c70b9dd

Browse files
authored
Merge pull request #781 from Bnyro/feed-cleanup
refactor: simplify FeedHandlers.java by introducing FeedHelpers.java
2 parents 25a49ce + b0c6116 commit c70b9dd

File tree

2 files changed

+107
-114
lines changed

2 files changed

+107
-114
lines changed

src/main/java/me/kavin/piped/server/handlers/auth/FeedHandlers.java

Lines changed: 18 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@
33
import com.rometools.rome.feed.synd.*;
44
import com.rometools.rome.io.FeedException;
55
import com.rometools.rome.io.SyndFeedOutput;
6-
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
76
import jakarta.persistence.criteria.CriteriaBuilder;
8-
import jakarta.persistence.criteria.CriteriaQuery;
9-
import jakarta.persistence.criteria.JoinType;
107
import me.kavin.piped.consts.Constants;
118
import me.kavin.piped.utils.*;
129
import me.kavin.piped.utils.obj.StreamItem;
@@ -104,24 +101,7 @@ public static byte[] feedResponse(String session) throws IOException {
104101
if (user != null) {
105102
try (StatelessSession s = DatabaseSessionFactory.createStatelessSession()) {
106103

107-
CriteriaBuilder cb = s.getCriteriaBuilder();
108-
109-
// Get all videos from subscribed channels, with channel info
110-
CriteriaQuery<Video> criteria = cb.createQuery(Video.class);
111-
var root = criteria.from(Video.class);
112-
root.fetch("channel", JoinType.RIGHT);
113-
var subquery = criteria.subquery(String.class);
114-
var subroot = subquery.from(User.class);
115-
subquery.select(subroot.get("subscribed_ids"))
116-
.where(cb.equal(subroot.get("id"), user.getId()));
117-
118-
criteria.select(root)
119-
.where(
120-
root.get("channel").get("uploader_id").in(subquery)
121-
)
122-
.orderBy(cb.desc(root.get("uploaded")));
123-
124-
List<StreamItem> feedItems = s.createQuery(criteria).setTimeout(20).stream()
104+
List<StreamItem> feedItems = FeedHelpers.generateAuthenticatedFeed(s, user.getId(), Integer.MAX_VALUE)
125105
.parallel().map(video -> {
126106
var channel = video.getChannel();
127107

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

149129
if (user != null) {
150-
151130
try (StatelessSession s = DatabaseSessionFactory.createStatelessSession()) {
131+
SyndFeed feed = FeedHelpers.createRssFeed(user.getUsername());
152132

153-
SyndFeed feed = new SyndFeedImpl();
154-
feed.setFeedType("atom_1.0");
155-
feed.setTitle("Piped - Feed");
156-
feed.setDescription(String.format("Piped's RSS subscription feed for %s.", user.getUsername()));
157-
feed.setUri(Constants.FRONTEND_URL + "/feed");
158-
feed.setPublishedDate(new Date());
159-
160-
CriteriaBuilder cb = s.getCriteriaBuilder();
161-
162-
// Get all videos from subscribed channels, with channel info
163-
CriteriaQuery<Video> criteria = cb.createQuery(Video.class);
164-
var root = criteria.from(Video.class);
165-
root.fetch("channel", JoinType.RIGHT);
166-
var subquery = criteria.subquery(String.class);
167-
var subroot = subquery.from(User.class);
168-
subquery.select(subroot.get("subscribed_ids"))
169-
.where(cb.equal(subroot.get("id"), user.getId()));
170-
171-
criteria.select(root)
172-
.where(
173-
root.get("channel").get("uploader_id").in(subquery)
174-
)
175-
.orderBy(cb.desc(root.get("uploaded")));
176-
177-
final List<SyndEntry> entries = s.createQuery(criteria)
178-
.setTimeout(20)
179-
.setMaxResults(100)
180-
.stream()
133+
final List<SyndEntry> entries = FeedHelpers.generateAuthenticatedFeed(s, user.getId(), 100)
181134
.map(video -> {
182135
var channel = video.getChannel();
183-
SyndEntry entry = ChannelHelpers.createEntry(video, channel);
184-
return entry;
136+
return ChannelHelpers.createEntry(video, channel);
185137
}).toList();
186138

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

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

199-
Set<String> filtered = Arrays.stream(channelIds)
151+
Set<String> filteredChannels = Arrays.stream(channelIds)
200152
.filter(ChannelHelpers::isValidId)
201153
.collect(Collectors.toUnmodifiableSet());
202154

203-
if (filtered.isEmpty())
155+
if (filteredChannels.isEmpty())
204156
return mapper.writeValueAsBytes(Collections.EMPTY_LIST);
205157

206158
try (StatelessSession s = DatabaseSessionFactory.createStatelessSession()) {
207-
208-
CriteriaBuilder cb = s.getCriteriaBuilder();
209-
210-
// Get all videos from subscribed channels, with channel info
211-
CriteriaQuery<Video> criteria = cb.createQuery(Video.class);
212-
var root = criteria.from(Video.class);
213-
root.fetch("channel", JoinType.RIGHT);
214-
215-
criteria.select(root)
216-
.where(cb.and(
217-
root.get("channel").get("id").in(filtered)
218-
))
219-
.orderBy(cb.desc(root.get("uploaded")));
220-
221-
List<StreamItem> feedItems = s.createQuery(criteria).setTimeout(20).stream()
159+
List<StreamItem> feedItems = FeedHelpers.generateUnauthenticatedFeed(s, filteredChannels, Integer.MAX_VALUE)
222160
.parallel().map(video -> {
223161
var channel = video.getChannel();
224162

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

231-
updateSubscribedTime(filtered);
232-
addMissingChannels(filtered);
169+
updateSubscribedTime(filteredChannels);
170+
addMissingChannels(filteredChannels);
233171

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

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

249-
CriteriaBuilder cb = s.getCriteriaBuilder();
250-
251-
// Get all videos from subscribed channels, with channel info
252-
CriteriaQuery<Video> criteria = cb.createQuery(Video.class);
253-
var root = criteria.from(Video.class);
254-
root.fetch("channel", JoinType.RIGHT);
188+
List<SyndEntry> entries = videos.stream()
189+
.map(video -> ChannelHelpers.createEntry(video, video.getChannel()))
190+
.toList();
255191

256-
criteria.select(root)
257-
.where(cb.and(
258-
root.get("channel").get("id").in(filteredChannels)
259-
))
260-
.orderBy(cb.desc(root.get("uploaded")));
261-
262-
List<Video> videos = s.createQuery(criteria)
263-
.setTimeout(20)
264-
.setMaxResults(100)
265-
.list();
266-
267-
SyndFeed feed = new SyndFeedImpl();
268-
feed.setFeedType("atom_1.0");
269-
feed.setTitle("Piped - Feed");
270-
feed.setDescription("Piped's RSS unauthenticated subscription feed.");
271-
feed.setUri(Constants.FRONTEND_URL + "/feed");
272-
feed.setPublishedDate(new Date());
273-
274-
final List<SyndEntry> entries = new ObjectArrayList<>();
275-
276-
for (Video video : videos) {
277-
var channel = video.getChannel();
278-
SyndEntry entry = ChannelHelpers.createEntry(video, channel);
279-
entries.add(entry);
280-
}
192+
SyndFeed feed = FeedHelpers.createRssFeed(null);
281193

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

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

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

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

486390
return mapper.writeValueAsBytes(subscriptionItems);
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package me.kavin.piped.utils;
2+
3+
import com.rometools.rome.feed.synd.SyndFeed;
4+
import com.rometools.rome.feed.synd.SyndFeedImpl;
5+
import jakarta.persistence.criteria.CriteriaBuilder;
6+
import jakarta.persistence.criteria.CriteriaQuery;
7+
import jakarta.persistence.criteria.JoinType;
8+
import me.kavin.piped.consts.Constants;
9+
import me.kavin.piped.utils.obj.SubscriptionChannel;
10+
import me.kavin.piped.utils.obj.db.Channel;
11+
import me.kavin.piped.utils.obj.db.User;
12+
import me.kavin.piped.utils.obj.db.Video;
13+
import org.hibernate.StatelessSession;
14+
15+
import javax.annotation.Nullable;
16+
import java.util.Comparator;
17+
import java.util.Date;
18+
import java.util.Set;
19+
import java.util.stream.Stream;
20+
21+
import static me.kavin.piped.utils.URLUtils.rewriteURL;
22+
23+
public class FeedHelpers {
24+
public static Stream<Video> generateAuthenticatedFeed(StatelessSession s, long userId, int maxResults) {
25+
CriteriaBuilder cb = s.getCriteriaBuilder();
26+
27+
// Get all videos from subscribed channels, with channel info
28+
CriteriaQuery<Video> criteria = cb.createQuery(Video.class);
29+
var root = criteria.from(Video.class);
30+
root.fetch("channel", JoinType.RIGHT);
31+
var subquery = criteria.subquery(String.class);
32+
var subroot = subquery.from(User.class);
33+
subquery.select(subroot.get("subscribed_ids"))
34+
.where(cb.equal(subroot.get("id"), userId));
35+
36+
criteria.select(root)
37+
.where(
38+
root.get("channel").get("uploader_id").in(subquery)
39+
)
40+
.orderBy(cb.desc(root.get("uploaded")));
41+
42+
return s.createQuery(criteria).setTimeout(20).setMaxResults(maxResults).stream();
43+
}
44+
45+
public static Stream<Video> generateUnauthenticatedFeed(StatelessSession s, Set<String> channelIds, int maxResults) {
46+
CriteriaBuilder cb = s.getCriteriaBuilder();
47+
48+
// Get all videos from subscribed channels, with channel info
49+
CriteriaQuery<Video> criteria = cb.createQuery(Video.class);
50+
var root = criteria.from(Video.class);
51+
root.fetch("channel", JoinType.RIGHT);
52+
53+
criteria.select(root)
54+
.where(cb.and(
55+
root.get("channel").get("id").in(channelIds)
56+
))
57+
.orderBy(cb.desc(root.get("uploaded")));
58+
59+
return s.createQuery(criteria)
60+
.setTimeout(20)
61+
.setMaxResults(maxResults)
62+
.stream();
63+
}
64+
65+
public static SyndFeed createRssFeed(@Nullable String username) {
66+
SyndFeed feed = new SyndFeedImpl();
67+
feed.setFeedType("atom_1.0");
68+
feed.setTitle("Piped - Feed");
69+
70+
if (username == null) {
71+
feed.setDescription("Piped's RSS unauthenticated subscription feed.");
72+
} else {
73+
feed.setDescription(String.format("Piped's RSS subscription feed for %s.", username));
74+
}
75+
76+
feed.setUri(Constants.FRONTEND_URL + "/feed");
77+
feed.setPublishedDate(new Date());
78+
79+
return feed;
80+
}
81+
82+
public static Stream<SubscriptionChannel> generateSubscriptionsList(Stream<Channel> channels) {
83+
return channels.parallel()
84+
.filter(channel -> channel.getUploader() != null)
85+
.sorted(Comparator.comparing(Channel::getUploader, String.CASE_INSENSITIVE_ORDER))
86+
.map(channel -> new SubscriptionChannel("/channel/" + channel.getUploaderId(),
87+
channel.getUploader(), rewriteURL(channel.getUploaderAvatar()), channel.isVerified()));
88+
}
89+
}

0 commit comments

Comments
 (0)