From d5054a9fbb70f3e1494ae6e892287824ef96c425 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Tue, 22 Nov 2022 17:24:21 +0100 Subject: [PATCH 1/2] allow adding multiple videos to a playlist at the same time --- .../me/kavin/piped/server/ServerLauncher.java | 19 ++++++++- .../handlers/auth/AuthPlaylistHandlers.java | 40 +++++++++---------- 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/src/main/java/me/kavin/piped/server/ServerLauncher.java b/src/main/java/me/kavin/piped/server/ServerLauncher.java index 07a9b9b..10a8d3d 100644 --- a/src/main/java/me/kavin/piped/server/ServerLauncher.java +++ b/src/main/java/me/kavin/piped/server/ServerLauncher.java @@ -1,6 +1,7 @@ package me.kavin.piped.server; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; import com.rometools.rome.feed.synd.SyndFeed; import com.rometools.rome.io.SyndFeedInput; import io.activej.config.Config; @@ -31,6 +32,8 @@ import org.xml.sax.InputSource; import java.io.ByteArrayInputStream; import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Objects; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; @@ -377,8 +380,20 @@ public class ServerLauncher extends MultithreadedHttpServerLauncher { try { var json = Constants.mapper.readTree(request.loadBody().getResult().asArray()); var playlistId = json.get("playlistId").textValue(); - var videoId = json.get("videoId").textValue(); - return getJsonResponse(AuthPlaylistHandlers.addToPlaylistResponse(request.getHeader(AUTHORIZATION), playlistId, videoId), "private"); + var videoIds = new ArrayList(); + // backwards compatibility + var videoIdField = json.get("videoId"); + if (videoIdField != null) { + videoIds.add(videoIdField.textValue()); + } + var videoIdsField = json.get("videoIds"); + if (videoIdsField != null) { + for (JsonNode node : videoIdsField) { + videoIds.add(node.asText()); + } + } + + return getJsonResponse(AuthPlaylistHandlers.addToPlaylistResponse(request.getHeader(AUTHORIZATION), playlistId, videoIds), "private"); } catch (Exception e) { return getErrorResponse(e, request.getPath()); } 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 a23ba54..f04b695 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 @@ -198,9 +198,9 @@ public class AuthPlaylistHandlers { return mapper.writeValueAsBytes(new AcceptedResponse()); } - public static byte[] addToPlaylistResponse(String session, String playlistId, String videoId) throws IOException, ExtractionException { + public static byte[] addToPlaylistResponse(String session, String playlistId, ArrayList videoIds) throws IOException, ExtractionException { - if (StringUtils.isBlank(session) || StringUtils.isBlank(playlistId) || StringUtils.isBlank(videoId)) + if (StringUtils.isBlank(session) || StringUtils.isBlank(playlistId)) ExceptionHandler.throwErrorResponse(new InvalidRequestResponse("session, playlistId and videoId are required parameters")); var user = DatabaseHelper.getUserFromSession(session); @@ -223,33 +223,33 @@ public class AuthPlaylistHandlers { return mapper.writeValueAsBytes(mapper.createObjectNode() .put("error", "You are not the owner this playlist")); - var video = DatabaseHelper.getPlaylistVideoFromId(s, videoId); + var tr = s.beginTransaction(); + for (String videoId : videoIds) { + if (StringUtils.isEmpty(videoId)) continue; - if (video == null) { - StreamInfo info = StreamInfo.getInfo("https://www.youtube.com/watch?v=" + videoId); + var video = DatabaseHelper.getPlaylistVideoFromId(s, videoId); - String channelId = StringUtils.substringAfter(info.getUploaderUrl(), "/channel/"); + if (video == null) { + StreamInfo info = StreamInfo.getInfo("https://www.youtube.com/watch?v=" + videoId); - var channel = DatabaseHelper.getChannelFromId(s, channelId); + String channelId = StringUtils.substringAfter(info.getUploaderUrl(), "/channel/"); - if (channel == null) { - channel = DatabaseHelper.saveChannel(channelId); + var channel = DatabaseHelper.getChannelFromId(s, channelId); + + if (channel == null) { + channel = DatabaseHelper.saveChannel(channelId); + } + + video = new PlaylistVideo(videoId, info.getName(), info.getThumbnailUrl(), info.getDuration(), channel); + + s.persist(video); } - video = new PlaylistVideo(videoId, info.getName(), info.getThumbnailUrl(), info.getDuration(), channel); - - var tr = s.beginTransaction(); - s.persist(video); - tr.commit(); + if (playlist.getVideos().isEmpty()) playlist.setThumbnail(video.getThumbnail()); + playlist.getVideos().add(video); } - if (playlist.getVideos().isEmpty()) - playlist.setThumbnail(video.getThumbnail()); - - playlist.getVideos().add(video); - - var tr = s.beginTransaction(); s.merge(playlist); tr.commit(); From d0fd4e0da6e58b866df56f0f689202626480f894 Mon Sep 17 00:00:00 2001 From: Kavin <20838718+FireMasterK@users.noreply.github.com> Date: Sat, 26 Nov 2022 19:45:31 +0000 Subject: [PATCH 2/2] Optimize playlist adding queries. --- .../me/kavin/piped/server/ServerLauncher.java | 7 +++--- .../handlers/auth/AuthPlaylistHandlers.java | 25 +++++++++++++------ 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/main/java/me/kavin/piped/server/ServerLauncher.java b/src/main/java/me/kavin/piped/server/ServerLauncher.java index 10a8d3d..35c8540 100644 --- a/src/main/java/me/kavin/piped/server/ServerLauncher.java +++ b/src/main/java/me/kavin/piped/server/ServerLauncher.java @@ -13,6 +13,7 @@ import io.activej.inject.annotation.Provides; import io.activej.inject.module.AbstractModule; import io.activej.inject.module.Module; import io.activej.launchers.http.MultithreadedHttpServerLauncher; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; import me.kavin.piped.consts.Constants; import me.kavin.piped.server.handlers.*; import me.kavin.piped.server.handlers.auth.AuthPlaylistHandlers; @@ -32,8 +33,6 @@ import org.xml.sax.InputSource; import java.io.ByteArrayInputStream; import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Objects; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; @@ -380,7 +379,7 @@ public class ServerLauncher extends MultithreadedHttpServerLauncher { try { var json = Constants.mapper.readTree(request.loadBody().getResult().asArray()); var playlistId = json.get("playlistId").textValue(); - var videoIds = new ArrayList(); + var videoIds = new ObjectArrayList(); // backwards compatibility var videoIdField = json.get("videoId"); if (videoIdField != null) { @@ -389,7 +388,7 @@ public class ServerLauncher extends MultithreadedHttpServerLauncher { var videoIdsField = json.get("videoIds"); if (videoIdsField != null) { for (JsonNode node : videoIdsField) { - videoIds.add(node.asText()); + videoIds.add(node.textValue()); } } 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 f04b695..042df97 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 @@ -8,6 +8,7 @@ import com.rometools.rome.feed.synd.SyndFeedImpl; import com.rometools.rome.io.SyndFeedOutput; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import jakarta.persistence.criteria.JoinType; import me.kavin.piped.consts.Constants; import me.kavin.piped.utils.*; @@ -198,10 +199,14 @@ public class AuthPlaylistHandlers { return mapper.writeValueAsBytes(new AcceptedResponse()); } - public static byte[] addToPlaylistResponse(String session, String playlistId, ArrayList videoIds) throws IOException, ExtractionException { + public static byte[] addToPlaylistResponse(String session, String playlistId, List videoIds) throws IOException, ExtractionException { - if (StringUtils.isBlank(session) || StringUtils.isBlank(playlistId)) - ExceptionHandler.throwErrorResponse(new InvalidRequestResponse("session, playlistId and videoId are required parameters")); + videoIds = videoIds.stream() + .filter(StringUtils::isNotBlank) + .collect(Collectors.toList()); + + if (StringUtils.isBlank(session) || StringUtils.isBlank(playlistId) || videoIds.isEmpty()) + ExceptionHandler.throwErrorResponse(new InvalidRequestResponse("session, playlistId and videoId(s) are required parameters")); var user = DatabaseHelper.getUserFromSession(session); @@ -223,11 +228,16 @@ public class AuthPlaylistHandlers { return mapper.writeValueAsBytes(mapper.createObjectNode() .put("error", "You are not the owner this playlist")); - var tr = s.beginTransaction(); + var playlistVideos = DatabaseHelper.getPlaylistVideosFromIds(s, new ObjectOpenHashSet<>(videoIds)); + + var videos = playlist.getVideos(); + for (String videoId : videoIds) { if (StringUtils.isEmpty(videoId)) continue; - var video = DatabaseHelper.getPlaylistVideoFromId(s, videoId); + var video = playlistVideos.stream().filter(v -> v.getId().equals(videoId)) + .findFirst() + .orElse(null); if (video == null) { StreamInfo info = StreamInfo.getInfo("https://www.youtube.com/watch?v=" + videoId); @@ -245,11 +255,12 @@ public class AuthPlaylistHandlers { s.persist(video); } - if (playlist.getVideos().isEmpty()) playlist.setThumbnail(video.getThumbnail()); + if (playlist.getVideos().isEmpty()) playlist.setThumbnail(video.getThumbnail()); - playlist.getVideos().add(video); + videos.add(video); } + var tr = s.beginTransaction(); s.merge(playlist); tr.commit();