diff --git a/src/main/java/me/kavin/piped/server/handlers/PlaylistHandlers.java b/src/main/java/me/kavin/piped/server/handlers/PlaylistHandlers.java index 658962a..b1ae76c 100644 --- a/src/main/java/me/kavin/piped/server/handlers/PlaylistHandlers.java +++ b/src/main/java/me/kavin/piped/server/handlers/PlaylistHandlers.java @@ -34,7 +34,7 @@ import static me.kavin.piped.utils.URLUtils.rewriteURL; import static me.kavin.piped.utils.URLUtils.substringYouTube; public class PlaylistHandlers { - public static byte[] playlistResponse(String playlistId) throws ExtractionException, IOException { + public static byte[] playlistResponse(String playlistId) throws Exception { if (StringUtils.isBlank(playlistId)) ExceptionHandler.throwErrorResponse(new InvalidRequestResponse("playlistId is a required parameter")); @@ -98,7 +98,7 @@ public class PlaylistHandlers { } - public static byte[] playlistRSSResponse(String playlistId) throws ExtractionException, IOException, FeedException { + public static byte[] playlistRSSResponse(String playlistId) throws Exception { if (StringUtils.isBlank(playlistId)) ExceptionHandler.throwErrorResponse(new InvalidRequestResponse("playlistId is a required parameter")); diff --git a/src/main/java/me/kavin/piped/server/handlers/auth/AuthPlaylistHandlers.java b/src/main/java/me/kavin/piped/server/handlers/auth/AuthPlaylistHandlers.java index e6272f4..a23ba54 100644 --- a/src/main/java/me/kavin/piped/server/handlers/auth/AuthPlaylistHandlers.java +++ b/src/main/java/me/kavin/piped/server/handlers/auth/AuthPlaylistHandlers.java @@ -5,16 +5,12 @@ import com.rometools.rome.feed.synd.SyndEntry; import com.rometools.rome.feed.synd.SyndEntryImpl; import com.rometools.rome.feed.synd.SyndFeed; import com.rometools.rome.feed.synd.SyndFeedImpl; -import com.rometools.rome.io.FeedException; import com.rometools.rome.io.SyndFeedOutput; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import jakarta.persistence.criteria.JoinType; import me.kavin.piped.consts.Constants; -import me.kavin.piped.utils.DatabaseHelper; -import me.kavin.piped.utils.DatabaseSessionFactory; -import me.kavin.piped.utils.ExceptionHandler; -import me.kavin.piped.utils.URLUtils; +import me.kavin.piped.utils.*; import me.kavin.piped.utils.obj.ContentItem; import me.kavin.piped.utils.obj.Playlist; import me.kavin.piped.utils.obj.StreamItem; @@ -43,21 +39,17 @@ import static me.kavin.piped.utils.URLUtils.rewriteURL; import static me.kavin.piped.utils.URLUtils.substringYouTube; public class AuthPlaylistHandlers { - public static byte[] playlistPipedResponse(String playlistId) throws IOException { + public static byte[] playlistPipedResponse(String playlistId) throws Exception { if (StringUtils.isBlank(playlistId)) ExceptionHandler.throwErrorResponse(new InvalidRequestResponse("playlistId is a required parameter")); try (Session s = DatabaseSessionFactory.createSession()) { - var cb = s.getCriteriaBuilder(); - var cq = cb.createQuery(me.kavin.piped.utils.obj.db.Playlist.class); - var root = cq.from(me.kavin.piped.utils.obj.db.Playlist.class); - root.fetch("videos", JoinType.RIGHT) - .fetch("channel", JoinType.INNER); - cq.select(root); - cq.where(cb.equal(root.get("playlist_id"), UUID.fromString(playlistId))); - var query = s.createQuery(cq); - var pl = query.uniqueResult(); + + var playlistCompletableFuture = Multithreading.supplyAsync(() -> DatabaseHelper.getPlaylistFromId(s, playlistId)); + var playlistVideosCompletableFuture = Multithreading.supplyAsync(() -> DatabaseHelper.getPlaylistVideosFromPlaylistId(playlistId, true)); + + var pl = playlistCompletableFuture.get(); if (pl == null) return mapper.writeValueAsBytes(mapper.createObjectNode() @@ -65,7 +57,7 @@ public class AuthPlaylistHandlers { final List relatedStreams = new ObjectArrayList<>(); - var videos = pl.getVideos(); + var videos = playlistVideosCompletableFuture.get(); for (var video : videos) { var channel = video.getChannel(); @@ -82,21 +74,16 @@ public class AuthPlaylistHandlers { } public static byte[] playlistPipedRSSResponse(String playlistId) - throws FeedException { + throws Exception { if (StringUtils.isBlank(playlistId)) ExceptionHandler.throwErrorResponse(new InvalidRequestResponse("playlistId is required parameter")); try (Session s = DatabaseSessionFactory.createSession()) { - var cb = s.getCriteriaBuilder(); - var cq = cb.createQuery(me.kavin.piped.utils.obj.db.Playlist.class); - var root = cq.from(me.kavin.piped.utils.obj.db.Playlist.class); - root.fetch("videos", JoinType.RIGHT) - .fetch("channel", JoinType.INNER); - cq.select(root); - cq.where(cb.equal(root.get("playlist_id"), UUID.fromString(playlistId))); - var query = s.createQuery(cq); - var pl = query.uniqueResult(); + var playlistCompletableFuture = Multithreading.supplyAsync(() -> DatabaseHelper.getPlaylistFromId(s, playlistId)); + var playlistVideosCompletableFuture = Multithreading.supplyAsync(() -> DatabaseHelper.getPlaylistVideosFromPlaylistId(playlistId, true)); + + var pl = playlistCompletableFuture.get(); final List entries = new ObjectArrayList<>(); @@ -108,7 +95,9 @@ public class AuthPlaylistHandlers { feed.setLink(Constants.FRONTEND_URL + "/playlist?list=" + pl.getPlaylistId()); feed.setPublishedDate(new Date()); - for (var video : pl.getVideos()) { + var videos = playlistVideosCompletableFuture.get(); + + for (var video : videos) { SyndEntry entry = new SyndEntryImpl(); entry.setAuthor(video.getChannel().getUploader()); entry.setLink(Constants.FRONTEND_URL + "/video?id=" + video.getId()); @@ -223,7 +212,6 @@ public class AuthPlaylistHandlers { var cb = s.getCriteriaBuilder(); var query = cb.createQuery(me.kavin.piped.utils.obj.db.Playlist.class); var root = query.from(me.kavin.piped.utils.obj.db.Playlist.class); - root.fetch("videos", JoinType.RIGHT); query.where(cb.equal(root.get("playlist_id"), UUID.fromString(playlistId))); var playlist = s.createQuery(query).uniqueResult(); diff --git a/src/main/java/me/kavin/piped/utils/DatabaseHelper.java b/src/main/java/me/kavin/piped/utils/DatabaseHelper.java index 15cb700..3d5e904 100644 --- a/src/main/java/me/kavin/piped/utils/DatabaseHelper.java +++ b/src/main/java/me/kavin/piped/utils/DatabaseHelper.java @@ -123,6 +123,12 @@ public class DatabaseHelper { return s.createQuery(cr).uniqueResult(); } + public static Playlist getPlaylistFromId(String id) { + try (StatelessSession s = DatabaseSessionFactory.createStatelessSession()) { + return getPlaylistFromId(s, id); + } + } + public static List getPlaylistVideosFromIds(SharedSessionContract s, Collection id) { CriteriaBuilder cb = s.getCriteriaBuilder(); CriteriaQuery cr = cb.createQuery(PlaylistVideo.class); @@ -132,6 +138,29 @@ public class DatabaseHelper { return s.createQuery(cr).list(); } + public static List getPlaylistVideosFromPlaylistId(SharedSessionContract s, String id, boolean fetchChannel) { + CriteriaBuilder cb = s.getCriteriaBuilder(); + CriteriaQuery cr = cb.createQuery(PlaylistVideo.class); + var root = cr.from(PlaylistVideo.class); + root.fetch("channel", JoinType.RIGHT); + cr.select(root); + var sq = cr.subquery(String.class); + { + var sqRoot = sq.from(Playlist.class); + sq.select(sqRoot.get("videos").get("id")) + .where(cb.equal(sqRoot.get("playlist_id"), UUID.fromString(id))); + } + cr.where(cb.equal(root.get("id"), sq)); + + return s.createQuery(cr).list(); + } + + public static List getPlaylistVideosFromPlaylistId(String id, boolean fetchChannel) { + try (StatelessSession s = DatabaseSessionFactory.createStatelessSession()) { + return getPlaylistVideosFromPlaylistId(s, id, fetchChannel); + } + } + public static PubSub getPubSubFromId(SharedSessionContract s, String id) { CriteriaBuilder cb = s.getCriteriaBuilder(); CriteriaQuery cr = cb.createQuery(PubSub.class);