From a1698861d4e0c046d60485f2d6bcef5c926dc1c8 Mon Sep 17 00:00:00 2001 From: Andrew DeMaria Date: Tue, 14 Mar 2017 19:58:57 -0600 Subject: [PATCH] Change to server-side pagination for Sibling Albums and Sub Dirs - Only paritial pagination, first X, then showAll - Default is 40 for subDirs and sibling albums each - showAll parameter causes page refresh with entirely new list TODO/Future improvements include: - Finer grain pagination - Pagination done at the database level - Seamless refresh with JS - Unify all pagination uses across the site Signed-off-by: Andrew DeMaria --- .../command/PersonalSettingsCommand.java | 9 +++++ .../player/controller/MainController.java | 40 ++++++++++++++++--- .../PersonalSettingsController.java | 2 + .../org/libresonic/player/dao/UserDao.java | 8 +++- .../player/domain/UserSettings.java | 9 +++++ .../player/service/SettingsService.java | 1 + .../liquibase/6.2/add-user-pagination.xml | 17 ++++++++ .../resources/liquibase/6.2/changelog.xml | 1 + .../player/i18n/ResourceBundle_en.properties | 1 + .../src/main/webapp/WEB-INF/jsp/albumMain.jsp | 11 +++-- .../main/webapp/WEB-INF/jsp/artistMain.jsp | 8 ++-- .../webapp/WEB-INF/jsp/personalSettings.jsp | 4 ++ .../src/main/webapp/WEB-INF/jsp/videoMain.jsp | 7 ++++ .../src/main/webapp/script/util.js | 10 +++++ .../player/dao/UserDaoTestCase.java | 3 ++ 15 files changed, 116 insertions(+), 15 deletions(-) create mode 100644 libresonic-main/src/main/resources/liquibase/6.2/add-user-pagination.xml create mode 100644 libresonic-main/src/main/webapp/script/util.js diff --git a/libresonic-main/src/main/java/org/libresonic/player/command/PersonalSettingsCommand.java b/libresonic-main/src/main/java/org/libresonic/player/command/PersonalSettingsCommand.java index d9b8f8f6..73b00b2f 100644 --- a/libresonic-main/src/main/java/org/libresonic/player/command/PersonalSettingsCommand.java +++ b/libresonic-main/src/main/java/org/libresonic/player/command/PersonalSettingsCommand.java @@ -54,6 +54,7 @@ public class PersonalSettingsCommand { private boolean queueFollowingSongs; private boolean lastFmEnabled; private int listReloadDelay; + private int paginationSize; private String lastFmUsername; private String lastFmPassword; @@ -264,4 +265,12 @@ public class PersonalSettingsCommand { public void setQueueFollowingSongs(boolean queueFollowingSongs) { this.queueFollowingSongs = queueFollowingSongs; } + + public int getPaginationSize() { + return paginationSize; + } + + public void setPaginationSize(int paginationSize) { + this.paginationSize = paginationSize; + } } diff --git a/libresonic-main/src/main/java/org/libresonic/player/controller/MainController.java b/libresonic-main/src/main/java/org/libresonic/player/controller/MainController.java index e815576d..4f38a451 100644 --- a/libresonic-main/src/main/java/org/libresonic/player/controller/MainController.java +++ b/libresonic-main/src/main/java/org/libresonic/player/controller/MainController.java @@ -19,6 +19,7 @@ */ package org.libresonic.player.controller; +import org.apache.commons.lang3.BooleanUtils; import org.libresonic.player.domain.*; import org.libresonic.player.service.*; import org.springframework.beans.factory.annotation.Autowired; @@ -26,6 +27,7 @@ import org.springframework.stereotype.Controller; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.view.RedirectView; @@ -59,7 +61,9 @@ public class MainController { private AdService adService; @RequestMapping(method = RequestMethod.GET) - protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception { + protected ModelAndView handleRequestInternal(@RequestParam(name = "showAll", required = false) Boolean showAll, + HttpServletRequest request, + HttpServletResponse response) throws Exception { Map map = new HashMap<>(); Player player = playerService.getPlayer(request, response); @@ -84,7 +88,12 @@ public class MainController { return new ModelAndView(new RedirectView("accessDenied.view")); } - List children = mediaFiles.size() == 1 ? mediaFileService.getChildrenOf(dir, true, true, true) : getMultiFolderChildren(mediaFiles); + UserSettings userSettings = settingsService.getUserSettings(username); + + List children = mediaFiles.size() == 1 ? mediaFileService.getChildrenOf(dir, + true, + true, + true) : getMultiFolderChildren(mediaFiles); List files = new ArrayList<>(); List subDirs = new ArrayList<>(); for (MediaFile child : children) { @@ -95,7 +104,14 @@ public class MainController { } } - UserSettings userSettings = settingsService.getUserSettings(username); + int userPaginationPreference = userSettings.getPaginationSize(); + + if(userPaginationPreference <= 0) { + showAll = true; + } + + boolean thereIsMoreSubDirs = trimToSize(showAll, subDirs, userPaginationPreference); + boolean thereIsMoreSAlbums = false; mediaFileService.populateStarredDate(dir, username); mediaFileService.populateStarredDate(children, username); @@ -115,7 +131,9 @@ public class MainController { map.put("brand", settingsService.getBrand()); map.put("viewAsList", isViewAsList(request, userSettings)); if (dir.isAlbum()) { - map.put("sieblingAlbums", getSieblingAlbums(dir)); + List sieblingAlbums = getSieblingAlbums(dir); + thereIsMoreSAlbums = trimToSize(showAll, sieblingAlbums, userPaginationPreference); + map.put("sieblingAlbums", sieblingAlbums); map.put("artist", guessArtist(children)); map.put("album", guessAlbum(children)); } @@ -127,6 +145,7 @@ public class MainController { } catch (SecurityException x) { // Happens if Podcast directory is outside music folder. } + map.put("thereIsMore", (thereIsMoreSubDirs || thereIsMoreSAlbums) && !BooleanUtils.isTrue(showAll)); Integer userRating = ratingService.getRatingForUser(username, dir); Double averageRating = ratingService.getAverageRating(dir); @@ -152,7 +171,18 @@ public class MainController { view = "artistMain"; } - return new ModelAndView(view,"model",map); + return new ModelAndView(view, "model", map); +} + + private boolean trimToSize(Boolean showAll, List list, int userPaginationPreference) { + boolean trimmed = false; + if(!BooleanUtils.isTrue(showAll)) { + if(list.size() > userPaginationPreference) { + trimmed = true; + list.subList(userPaginationPreference, list.size()).clear(); + } + } + return trimmed; } private boolean isViewAsList(HttpServletRequest request, UserSettings userSettings) { diff --git a/libresonic-main/src/main/java/org/libresonic/player/controller/PersonalSettingsController.java b/libresonic-main/src/main/java/org/libresonic/player/controller/PersonalSettingsController.java index bd08381f..309378b6 100644 --- a/libresonic-main/src/main/java/org/libresonic/player/controller/PersonalSettingsController.java +++ b/libresonic-main/src/main/java/org/libresonic/player/controller/PersonalSettingsController.java @@ -82,6 +82,7 @@ public class PersonalSettingsController { command.setLastFmEnabled(userSettings.isLastFmEnabled()); command.setLastFmUsername(userSettings.getLastFmUsername()); command.setLastFmPassword(userSettings.getLastFmPassword()); + command.setPaginationSize(userSettings.getPaginationSize()); Locale currentLocale = userSettings.getLocale(); Locale[] locales = settingsService.getAvailableLocales(); @@ -150,6 +151,7 @@ public class PersonalSettingsController { settings.setLastFmUsername(command.getLastFmUsername()); settings.setSystemAvatarId(getSystemAvatarId(command)); settings.setAvatarScheme(getAvatarScheme(command)); + settings.setPaginationSize(command.getPaginationSize()); if (StringUtils.isNotBlank(command.getLastFmPassword())) { settings.setLastFmPassword(command.getLastFmPassword()); diff --git a/libresonic-main/src/main/java/org/libresonic/player/dao/UserDao.java b/libresonic-main/src/main/java/org/libresonic/player/dao/UserDao.java index ce5cd4c4..c4c6ff32 100644 --- a/libresonic-main/src/main/java/org/libresonic/player/dao/UserDao.java +++ b/libresonic-main/src/main/java/org/libresonic/player/dao/UserDao.java @@ -46,7 +46,8 @@ public class UserDao extends AbstractDao { "playlist_year, playlist_bit_rate, playlist_duration, playlist_format, playlist_file_size, " + "last_fm_enabled, last_fm_username, last_fm_password, transcode_scheme, show_now_playing, selected_music_folder_id, " + "party_mode_enabled, now_playing_allowed, avatar_scheme, system_avatar_id, changed, show_artist_info, auto_hide_play_queue, " + - "view_as_list, default_album_list, queue_following_songs, show_side_bar, list_reload_delay, keyboard_shortcuts_enabled"; + "view_as_list, default_album_list, queue_following_songs, show_side_bar, list_reload_delay, " + + "keyboard_shortcuts_enabled, pagination_size"; private static final Integer ROLE_ID_ADMIN = 1; private static final Integer ROLE_ID_DOWNLOAD = 2; @@ -214,7 +215,9 @@ public class UserDao extends AbstractDao { settings.getAvatarScheme().name(), settings.getSystemAvatarId(), settings.getChanged(), settings.isShowArtistInfoEnabled(), settings.isAutoHidePlayQueue(), settings.isViewAsList(), settings.getDefaultAlbumList().getId(), settings.isQueueFollowingSongs(), - settings.isShowSideBar(), settings.getListReloadDelay(), settings.isKeyboardShortcutsEnabled()}); + settings.isShowSideBar(), settings.getListReloadDelay(), settings.isKeyboardShortcutsEnabled(), + settings.getPaginationSize() + }); } private static String encrypt(String s) { @@ -375,6 +378,7 @@ public class UserDao extends AbstractDao { settings.setShowSideBar(rs.getBoolean(col++)); settings.setListReloadDelay((Integer) rs.getObject(col++)); settings.setKeyboardShortcutsEnabled(rs.getBoolean(col++)); + settings.setPaginationSize(rs.getInt(col++)); return settings; } diff --git a/libresonic-main/src/main/java/org/libresonic/player/domain/UserSettings.java b/libresonic-main/src/main/java/org/libresonic/player/domain/UserSettings.java index fadbe16a..6aeaec6f 100644 --- a/libresonic-main/src/main/java/org/libresonic/player/domain/UserSettings.java +++ b/libresonic-main/src/main/java/org/libresonic/player/domain/UserSettings.java @@ -56,6 +56,7 @@ public class UserSettings { private AvatarScheme avatarScheme = AvatarScheme.NONE; private Integer systemAvatarId; private Date changed = new Date(); + private int paginationSize; public UserSettings(String username) { this.username = username; @@ -287,6 +288,14 @@ public class UserSettings { this.queueFollowingSongs = queueFollowingSongs; } + public int getPaginationSize() { + return paginationSize; + } + + public void setPaginationSize(int paginationSize) { + this.paginationSize = paginationSize; + } + /** * Configuration of what information to display about a song. */ diff --git a/libresonic-main/src/main/java/org/libresonic/player/service/SettingsService.java b/libresonic-main/src/main/java/org/libresonic/player/service/SettingsService.java index 16e09833..cbf649c8 100644 --- a/libresonic-main/src/main/java/org/libresonic/player/service/SettingsService.java +++ b/libresonic-main/src/main/java/org/libresonic/player/service/SettingsService.java @@ -1037,6 +1037,7 @@ public class SettingsService { settings.setLastFmUsername(null); settings.setLastFmPassword(null); settings.setChanged(new Date()); + settings.setPaginationSize(40); UserSettings.Visibility playlist = settings.getPlaylistVisibility(); playlist.setArtistVisible(true); diff --git a/libresonic-main/src/main/resources/liquibase/6.2/add-user-pagination.xml b/libresonic-main/src/main/resources/liquibase/6.2/add-user-pagination.xml new file mode 100644 index 00000000..899acd8e --- /dev/null +++ b/libresonic-main/src/main/resources/liquibase/6.2/add-user-pagination.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/libresonic-main/src/main/resources/liquibase/6.2/changelog.xml b/libresonic-main/src/main/resources/liquibase/6.2/changelog.xml index 2a1746e7..986c37d2 100644 --- a/libresonic-main/src/main/resources/liquibase/6.2/changelog.xml +++ b/libresonic-main/src/main/resources/liquibase/6.2/changelog.xml @@ -3,4 +3,5 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> + \ No newline at end of file diff --git a/libresonic-main/src/main/resources/org/libresonic/player/i18n/ResourceBundle_en.properties b/libresonic-main/src/main/resources/org/libresonic/player/i18n/ResourceBundle_en.properties index 5f905389..47e9cf28 100644 --- a/libresonic-main/src/main/resources/org/libresonic/player/i18n/ResourceBundle_en.properties +++ b/libresonic-main/src/main/resources/org/libresonic/player/i18n/ResourceBundle_en.properties @@ -409,6 +409,7 @@ personalsettings.finalversionnotification = Notify me about new versions personalsettings.betaversionnotification = Notify me about new beta versions personalsettings.songnotification = Notify me when new songs are played (not supported by all browsers) personalsettings.listreloaddelay = Album list reload delay (in seconds, 0 disables) +personalsettings.paginationsize = Number of initial related albums/directories to display (0 disables album pagination) personalsettings.lastfmenabled = Register what I'm playing at Last.fm personalsettings.lastfmusername = Last.fm username personalsettings.lastfmpassword = Last.fm password diff --git a/libresonic-main/src/main/webapp/WEB-INF/jsp/albumMain.jsp b/libresonic-main/src/main/webapp/WEB-INF/jsp/albumMain.jsp index 27c8193e..ea4d3afe 100644 --- a/libresonic-main/src/main/webapp/WEB-INF/jsp/albumMain.jsp +++ b/libresonic-main/src/main/webapp/WEB-INF/jsp/albumMain.jsp @@ -12,6 +12,7 @@ + @@ -156,8 +157,7 @@ }); } function showAllAlbums() { - $("#showAllButton").hide(); - $(".albumThumb").show(); + window.location.href = updateQueryStringParameter(window.location.href, "showAll", "1"); } @@ -468,11 +468,14 @@ + + " onclick="showAllAlbums()"> +
-
+
@@ -485,7 +488,7 @@
- + " onclick="showAllAlbums()">
diff --git a/libresonic-main/src/main/webapp/WEB-INF/jsp/artistMain.jsp b/libresonic-main/src/main/webapp/WEB-INF/jsp/artistMain.jsp index 2fbb4fc8..12e8b49d 100644 --- a/libresonic-main/src/main/webapp/WEB-INF/jsp/artistMain.jsp +++ b/libresonic-main/src/main/webapp/WEB-INF/jsp/artistMain.jsp @@ -31,6 +31,7 @@ + @@ -154,8 +155,7 @@ $().toastmessage('showSuccessToast', '') } function showAllAlbums() { - $("#showAllButton").hide(); - $(".albumThumb").show(); + window.location.href = updateQueryStringParameter(window.location.href, "showAll", "1"); } @@ -265,7 +265,7 @@ -
+
@@ -279,7 +279,7 @@
- + " onclick="showAllAlbums()">
diff --git a/libresonic-main/src/main/webapp/WEB-INF/jsp/personalSettings.jsp b/libresonic-main/src/main/webapp/WEB-INF/jsp/personalSettings.jsp index 67b5d2e4..75b2d4bc 100644 --- a/libresonic-main/src/main/webapp/WEB-INF/jsp/personalSettings.jsp +++ b/libresonic-main/src/main/webapp/WEB-INF/jsp/personalSettings.jsp @@ -189,6 +189,10 @@ + + + + diff --git a/libresonic-main/src/main/webapp/WEB-INF/jsp/videoMain.jsp b/libresonic-main/src/main/webapp/WEB-INF/jsp/videoMain.jsp index 70b1b451..c24ad921 100644 --- a/libresonic-main/src/main/webapp/WEB-INF/jsp/videoMain.jsp +++ b/libresonic-main/src/main/webapp/WEB-INF/jsp/videoMain.jsp @@ -23,6 +23,7 @@ <%@ include file="head.jsp" %> <%@ include file="jquery.jsp" %> +