From fef60221042fd58b01c8154ce6feff716965954b Mon Sep 17 00:00:00 2001 From: frajibe Date: Sat, 7 Jan 2023 11:07:14 +0100 Subject: [PATCH 1/5] feat: ability to clear a playlist from its videos (#1952) --- .../me/kavin/piped/server/ServerLauncher.java | 8 ++++++++ .../handlers/auth/AuthPlaylistHandlers.java | 15 +++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/main/java/me/kavin/piped/server/ServerLauncher.java b/src/main/java/me/kavin/piped/server/ServerLauncher.java index bccba11..c571506 100644 --- a/src/main/java/me/kavin/piped/server/ServerLauncher.java +++ b/src/main/java/me/kavin/piped/server/ServerLauncher.java @@ -412,6 +412,14 @@ public class ServerLauncher extends MultithreadedHttpServerLauncher { } catch (Exception e) { return getErrorResponse(e, request.getPath()); } + })).map(POST, "/user/playlists/clear", AsyncServlet.ofBlocking(executor, request -> { + try { + var json = Constants.mapper.readTree(request.loadBody().getResult().asArray()); + var playlistId = json.get("playlistId").textValue(); + return getJsonResponse(AuthPlaylistHandlers.removeFromPlaylistResponse(request.getHeader(AUTHORIZATION), playlistId, null), "private"); + } catch (Exception e) { + return getErrorResponse(e, request.getPath()); + } })).map(POST, "/user/playlists/rename", AsyncServlet.ofBlocking(executor, request -> { try { var json = Constants.mapper.readTree(request.loadBody().getResult().asArray()); 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 253598d..3bd8942 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 @@ -283,8 +283,7 @@ public class AuthPlaylistHandlers { } } - public static byte[] removeFromPlaylistResponse(String session, String playlistId, int index) throws IOException { - + public static byte[] removeFromPlaylistResponse(String session, String playlistId, Integer index) throws IOException { if (StringUtils.isBlank(session) || StringUtils.isBlank(playlistId)) ExceptionHandler.throwErrorResponse(new InvalidRequestResponse("session and playlistId are required parameters")); @@ -304,11 +303,15 @@ public class AuthPlaylistHandlers { return mapper.writeValueAsBytes(mapper.createObjectNode() .put("error", "You are not the owner this playlist")); - if (index < 0 || index >= playlist.getVideos().size()) - return mapper.writeValueAsBytes(mapper.createObjectNode() - .put("error", "Video Index out of bounds")); + if (index != null) { + if (index < 0 || index >= playlist.getVideos().size()) + return mapper.writeValueAsBytes(mapper.createObjectNode() + .put("error", "Video Index out of bounds")); - playlist.getVideos().remove(index); + playlist.getVideos().remove((int) index); + } else { + playlist.getVideos().clear(); + } var tr = s.beginTransaction(); s.merge(playlist); From a145ad4e77b87229df8afe7b775db17eec303ff6 Mon Sep 17 00:00:00 2001 From: frajibe Date: Sat, 7 Jan 2023 13:01:27 +0100 Subject: [PATCH 2/5] introduce a dedicated method to clear a playlist --- .../me/kavin/piped/server/ServerLauncher.java | 2 +- .../handlers/auth/AuthPlaylistHandlers.java | 44 +++++++++++++++---- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/main/java/me/kavin/piped/server/ServerLauncher.java b/src/main/java/me/kavin/piped/server/ServerLauncher.java index c571506..1963b2b 100644 --- a/src/main/java/me/kavin/piped/server/ServerLauncher.java +++ b/src/main/java/me/kavin/piped/server/ServerLauncher.java @@ -416,7 +416,7 @@ public class ServerLauncher extends MultithreadedHttpServerLauncher { try { var json = Constants.mapper.readTree(request.loadBody().getResult().asArray()); var playlistId = json.get("playlistId").textValue(); - return getJsonResponse(AuthPlaylistHandlers.removeFromPlaylistResponse(request.getHeader(AUTHORIZATION), playlistId, null), "private"); + return getJsonResponse(AuthPlaylistHandlers.clearPlaylistResponse(request.getHeader(AUTHORIZATION), playlistId), "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 3bd8942..7c23ce8 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 @@ -283,7 +283,7 @@ public class AuthPlaylistHandlers { } } - public static byte[] removeFromPlaylistResponse(String session, String playlistId, Integer index) throws IOException { + public static byte[] removeFromPlaylistResponse(String session, String playlistId, int index) throws IOException { if (StringUtils.isBlank(session) || StringUtils.isBlank(playlistId)) ExceptionHandler.throwErrorResponse(new InvalidRequestResponse("session and playlistId are required parameters")); @@ -303,15 +303,41 @@ public class AuthPlaylistHandlers { return mapper.writeValueAsBytes(mapper.createObjectNode() .put("error", "You are not the owner this playlist")); - if (index != null) { - if (index < 0 || index >= playlist.getVideos().size()) - return mapper.writeValueAsBytes(mapper.createObjectNode() - .put("error", "Video Index out of bounds")); + if (index < 0 || index >= playlist.getVideos().size()) + return mapper.writeValueAsBytes(mapper.createObjectNode() + .put("error", "Video Index out of bounds")); - playlist.getVideos().remove((int) index); - } else { - playlist.getVideos().clear(); - } + playlist.getVideos().remove(index); + + var tr = s.beginTransaction(); + s.merge(playlist); + tr.commit(); + + return mapper.writeValueAsBytes(new AcceptedResponse()); + } + } + + public static byte[] clearPlaylistResponse(String session, String playlistId) throws IOException { + if (StringUtils.isBlank(session) || StringUtils.isBlank(playlistId)) + ExceptionHandler.throwErrorResponse(new InvalidRequestResponse("session and playlistId are required parameters")); + + try (Session s = DatabaseSessionFactory.createSession()) { + 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(); + + if (playlist == null) + return mapper.writeValueAsBytes(mapper.createObjectNode() + .put("error", "Playlist not found")); + + if (playlist.getOwner().getId() != DatabaseHelper.getUserFromSession(session).getId()) + return mapper.writeValueAsBytes(mapper.createObjectNode() + .put("error", "You are not the owner this playlist")); + + playlist.getVideos().clear(); var tr = s.beginTransaction(); s.merge(playlist); From 67681d5036b395c8fc3e92194c8219fd1fe64c7f Mon Sep 17 00:00:00 2001 From: frajibe Date: Sat, 7 Jan 2023 15:22:12 +0100 Subject: [PATCH 3/5] add 'playlists/clear' into api-test.sh --- testing/api-test.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/testing/api-test.sh b/testing/api-test.sh index 3f2489c..9568d08 100755 --- a/testing/api-test.sh +++ b/testing/api-test.sh @@ -126,6 +126,9 @@ curl ${CURLOPTS[@]} $HOST/user/playlists/remove -X POST -H "Content-Type: applic # Rename Playlist Test curl ${CURLOPTS[@]} $HOST/user/playlists/delete -X POST -H "Content-Type: application/json" -H "Authorization: $AUTH_TOKEN" -d $(jq -n --compact-output --arg playlistId $PLAYLIST_ID --arg newName $RENAMED_PLAYLIST_NAME '{"playlistId": $playlistId, "newName": $newName}') || exit 1 +# Clear Playlist Test +curl ${CURLOPTS[@]} $HOST/user/playlists/clear -X POST -H "Content-Type: application/json" -H "Authorization: $AUTH_TOKEN" -d $(jq -n --compact-output --arg playlistId $PLAYLIST_ID '{"playlistId": $playlistId}') || exit 1 + # Delete Playlist Test curl ${CURLOPTS[@]} $HOST/user/playlists/delete -X POST -H "Content-Type: application/json" -H "Authorization: $AUTH_TOKEN" -d $(jq -n --compact-output --arg playlistId $PLAYLIST_ID '{"playlistId": $playlistId}') || exit 1 From 27d14f714196e19cf4a410c91ad6f40bfbed3a06 Mon Sep 17 00:00:00 2001 From: frajibe Date: Sat, 7 Jan 2023 15:24:06 +0100 Subject: [PATCH 4/5] minor (put line breaks) --- .../kavin/piped/server/handlers/auth/AuthPlaylistHandlers.java | 2 ++ 1 file changed, 2 insertions(+) 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 7c23ce8..c794215 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 @@ -284,6 +284,7 @@ public class AuthPlaylistHandlers { } public static byte[] removeFromPlaylistResponse(String session, String playlistId, int index) throws IOException { + if (StringUtils.isBlank(session) || StringUtils.isBlank(playlistId)) ExceptionHandler.throwErrorResponse(new InvalidRequestResponse("session and playlistId are required parameters")); @@ -318,6 +319,7 @@ public class AuthPlaylistHandlers { } public static byte[] clearPlaylistResponse(String session, String playlistId) throws IOException { + if (StringUtils.isBlank(session) || StringUtils.isBlank(playlistId)) ExceptionHandler.throwErrorResponse(new InvalidRequestResponse("session and playlistId are required parameters")); From 6c12f58ffbbfc103f9a90a0ac66c3eb36cc60d49 Mon Sep 17 00:00:00 2001 From: Kavin <20838718+FireMasterK@users.noreply.github.com> Date: Sun, 8 Jan 2023 14:44:33 +0000 Subject: [PATCH 5/5] Try removing join and replacing array altogether. --- .../kavin/piped/server/handlers/auth/AuthPlaylistHandlers.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 c794215..f1c6105 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 @@ -327,7 +327,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(); @@ -339,7 +338,7 @@ public class AuthPlaylistHandlers { return mapper.writeValueAsBytes(mapper.createObjectNode() .put("error", "You are not the owner this playlist")); - playlist.getVideos().clear(); + playlist.setVideos(new ObjectArrayList<>()); var tr = s.beginTransaction(); s.merge(playlist);