2020package org .airsonic .player .service ;
2121
2222import org .airsonic .player .domain .MediaFile ;
23+ import org .airsonic .player .domain .MusicFolder ;
2324import org .airsonic .player .domain .PlayQueue ;
25+ import org .airsonic .player .domain .Player ;
2426import org .airsonic .player .domain .Playlist ;
2527import org .airsonic .player .domain .PlaylistMediaFile ;
2628import org .airsonic .player .domain .User ;
29+ import org .airsonic .player .repository .PlaylistMediaFileRepository ;
2730import org .airsonic .player .repository .PlaylistRepository ;
2831import org .airsonic .player .repository .UserRepository ;
2932import org .airsonic .player .service .cache .PlaylistCache ;
3033import org .airsonic .player .service .websocket .AsyncWebSocketClient ;
3134import org .airsonic .player .util .LambdaUtils ;
3235import org .slf4j .Logger ;
3336import org .slf4j .LoggerFactory ;
34- import org .springframework .beans .factory .annotation .Autowired ;
3537import org .springframework .data .domain .Sort ;
3638import org .springframework .stereotype .Service ;
3739import org .springframework .transaction .annotation .Transactional ;
4042import jakarta .annotation .Nonnull ;
4143
4244import java .time .Instant ;
45+ import java .time .ZoneId ;
46+ import java .time .format .DateTimeFormatter ;
47+ import java .time .format .FormatStyle ;
4348import java .util .*;
4449import java .util .stream .Collectors ;
4550import java .util .stream .Stream ;
@@ -55,14 +60,34 @@ public class PlaylistService {
5560
5661 private static final Logger LOG = LoggerFactory .getLogger (PlaylistService .class );
5762
58- @ Autowired
59- private UserRepository userRepository ;
60- @ Autowired
61- private PlaylistRepository playlistRepository ;
62- @ Autowired
63- private AsyncWebSocketClient asyncWebSocketClient ;
64- @ Autowired
65- private PlaylistCache playlistCache ;
63+ private final UserRepository userRepository ;
64+ private final PlaylistRepository playlistRepository ;
65+ private final AsyncWebSocketClient asyncWebSocketClient ;
66+ private final PlaylistCache playlistCache ;
67+ private final PlaylistMediaFileRepository playlistMediaFileRepository ;
68+ private final MediaFileService mediaFileService ;
69+ private final MediaFolderService mediaFolderService ;
70+ private final PlayerService playerService ;
71+
72+ public PlaylistService (
73+ UserRepository userRepository ,
74+ PlaylistRepository playlistRepository ,
75+ AsyncWebSocketClient asyncWebSocketClient ,
76+ PlaylistCache playlistCache ,
77+ PlaylistMediaFileRepository playlistMediaFileRepository ,
78+ PlayerService playerService ,
79+ MediaFolderService mediaFolderService ,
80+ MediaFileService mediaFileService
81+ ) {
82+ this .userRepository = userRepository ;
83+ this .playlistRepository = playlistRepository ;
84+ this .asyncWebSocketClient = asyncWebSocketClient ;
85+ this .playlistCache = playlistCache ;
86+ this .playlistMediaFileRepository = playlistMediaFileRepository ;
87+ this .playerService = playerService ;
88+ this .mediaFolderService = mediaFolderService ;
89+ this .mediaFileService = mediaFileService ;
90+ }
6691
6792
6893 /**
@@ -142,25 +167,18 @@ public List<String> getPlaylistUsers(Integer playlistId) {
142167 return result ;
143168 }
144169
170+ @ Transactional (readOnly = true )
145171 public List <MediaFile > getFilesInPlaylist (int id ) {
146172 return getFilesInPlaylist (id , false );
147173 }
148174
149175
150176 @ Transactional (readOnly = true )
151177 public List <MediaFile > getFilesInPlaylist (int id , boolean includeNotPresent ) {
152- return playlistRepository .findById (id ).map (p -> {
153- return p .getPlaylistMediaFiles ().stream ()
154- .map (PlaylistMediaFile ::getMediaFile )
178+ return playlistMediaFileRepository .findMediaFilesByPlaylistId (id ).stream ()
155179 .filter (Objects ::nonNull )
156180 .filter (x -> x .isPresent () || includeNotPresent )
157181 .collect (Collectors .toList ());
158- }).orElseGet (
159- () -> {
160- LOG .warn ("Playlist {} not found" , id );
161- return new ArrayList <>();
162- }
163- );
164182 }
165183
166184 private List <MediaFile > filterNoDurationFiles (List <MediaFile > files ) {
@@ -189,7 +207,6 @@ public Playlist setFilesInPlaylist(int id, List<MediaFile> files) {
189207 });
190208 }
191209
192-
193210 private Playlist setFilesInPlaylist (Playlist playlist , List <MediaFile > files ) {
194211
195212 List <MediaFile > filteredFiles = filterNoDurationFiles (files );
@@ -431,6 +448,48 @@ public void broadcastFileChange(Integer id, boolean isShared, boolean filesChang
431448 });
432449 }
433450
451+ /**
452+ * Creates a new playlist for the specified play queue.
453+ *
454+ * @param playerId the ID of the player
455+ * @param username the username of the user creating the playlist
456+ * @param locale the locale to use for formatting
457+ * @return the ID of the created playlist
458+ */
459+ @ Transactional
460+ public Integer createPlaylistForPlayQueue (@ Nonnull Integer playerId , @ Nonnull String username , Locale locale ) {
461+ DateTimeFormatter dateFormat = DateTimeFormatter .ofLocalizedDateTime (FormatStyle .MEDIUM , FormatStyle .SHORT ).withLocale (locale );
462+ Instant now = Instant .now ();
463+ String name = dateFormat .format (now .atZone (ZoneId .systemDefault ()));
464+
465+ Playlist playlist = createPlaylist (name , false , username );
466+ broadcast (playlist );
467+
468+ Player player = playerService .getPlayerById (playerId );
469+ playlist = setFilesInPlaylist (playlist , player .getPlayQueue ().getFiles ());
470+
471+ playlistRepository .saveAndFlush (playlist );
472+ return playlist .getId ();
473+ }
474+
475+ @ Transactional
476+ public Integer createPlaylistForStarredSongs (@ Nonnull String username , Locale locale ) {
477+
478+ DateTimeFormatter dateFormat = DateTimeFormatter .ofLocalizedDateTime (FormatStyle .MEDIUM , FormatStyle .SHORT ).withLocale (locale );
479+ ResourceBundle bundle = ResourceBundle .getBundle ("org.airsonic.player.i18n.ResourceBundle" , locale );
480+ Instant now = Instant .now ();
481+ String name = bundle .getString ("top.starred" ) + " " + dateFormat .format (now .atZone (ZoneId .systemDefault ()));
482+
483+ Playlist playlist = createPlaylist (name , false , username );
484+ broadcast (playlist );
485+
486+ List <MusicFolder > musicFolders = mediaFolderService .getMusicFoldersForUser (username );
487+ List <MediaFile > musicFiles = mediaFileService .getStarredSongs (0 , Integer .MAX_VALUE , username , musicFolders );
488+ setFilesInPlaylist (playlist , musicFiles );
489+ Integer playlistId = playlist .getId ();
490+ return playlistId ;
491+ }
492+
434493 public static class BroadcastedPlaylist extends Playlist {
435494 private final boolean filesChanged ;
436495
0 commit comments