PageRenderTime 69ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/subsonic-main/src/main/java/net/sourceforge/subsonic/controller/RESTController.java

https://github.com/edikabe/subsonic
Java | 1875 lines | 1546 code | 282 blank | 47 comment | 281 complexity | c4351b6ba54363b61d0e6cde6ab97497 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. This file is part of Subsonic.
  3. Subsonic is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. Subsonic is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
  13. Copyright 2009 (C) Sindre Mehus
  14. */
  15. package net.sourceforge.subsonic.controller;
  16. import java.io.File;
  17. import java.io.IOException;
  18. import java.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.Collections;
  21. import java.util.Date;
  22. import java.util.HashMap;
  23. import java.util.List;
  24. import java.util.Map;
  25. import java.util.SortedMap;
  26. import java.util.SortedSet;
  27. import java.util.TreeSet;
  28. import javax.servlet.http.HttpServletRequest;
  29. import javax.servlet.http.HttpServletRequestWrapper;
  30. import javax.servlet.http.HttpServletResponse;
  31. import org.apache.commons.lang.StringUtils;
  32. import org.springframework.web.bind.ServletRequestUtils;
  33. import org.springframework.web.servlet.ModelAndView;
  34. import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
  35. import net.sourceforge.subsonic.Logger;
  36. import net.sourceforge.subsonic.ajax.ChatService;
  37. import net.sourceforge.subsonic.ajax.LyricsInfo;
  38. import net.sourceforge.subsonic.ajax.LyricsService;
  39. import net.sourceforge.subsonic.ajax.PlayQueueService;
  40. import net.sourceforge.subsonic.command.UserSettingsCommand;
  41. import net.sourceforge.subsonic.dao.AlbumDao;
  42. import net.sourceforge.subsonic.dao.ArtistDao;
  43. import net.sourceforge.subsonic.dao.MediaFileDao;
  44. import net.sourceforge.subsonic.domain.Album;
  45. import net.sourceforge.subsonic.domain.Artist;
  46. import net.sourceforge.subsonic.domain.MediaFile;
  47. import net.sourceforge.subsonic.domain.MusicFolder;
  48. import net.sourceforge.subsonic.domain.MusicIndex;
  49. import net.sourceforge.subsonic.domain.PlayQueue;
  50. import net.sourceforge.subsonic.domain.Player;
  51. import net.sourceforge.subsonic.domain.PlayerTechnology;
  52. import net.sourceforge.subsonic.domain.Playlist;
  53. import net.sourceforge.subsonic.domain.PodcastChannel;
  54. import net.sourceforge.subsonic.domain.PodcastEpisode;
  55. import net.sourceforge.subsonic.domain.RandomSearchCriteria;
  56. import net.sourceforge.subsonic.domain.SearchCriteria;
  57. import net.sourceforge.subsonic.domain.SearchResult;
  58. import net.sourceforge.subsonic.domain.Share;
  59. import net.sourceforge.subsonic.domain.TranscodeScheme;
  60. import net.sourceforge.subsonic.domain.TransferStatus;
  61. import net.sourceforge.subsonic.domain.User;
  62. import net.sourceforge.subsonic.domain.UserSettings;
  63. import net.sourceforge.subsonic.service.AudioScrobblerService;
  64. import net.sourceforge.subsonic.service.JukeboxService;
  65. import net.sourceforge.subsonic.service.MediaFileService;
  66. import net.sourceforge.subsonic.service.MusicIndexService;
  67. import net.sourceforge.subsonic.service.PlayerService;
  68. import net.sourceforge.subsonic.service.PlaylistService;
  69. import net.sourceforge.subsonic.service.PodcastService;
  70. import net.sourceforge.subsonic.service.RatingService;
  71. import net.sourceforge.subsonic.service.SearchService;
  72. import net.sourceforge.subsonic.service.SecurityService;
  73. import net.sourceforge.subsonic.service.SettingsService;
  74. import net.sourceforge.subsonic.service.ShareService;
  75. import net.sourceforge.subsonic.service.StatusService;
  76. import net.sourceforge.subsonic.service.TranscodingService;
  77. import net.sourceforge.subsonic.util.StringUtil;
  78. import net.sourceforge.subsonic.util.XMLBuilder;
  79. import static net.sourceforge.subsonic.security.RESTRequestParameterProcessingFilter.decrypt;
  80. import static net.sourceforge.subsonic.util.XMLBuilder.Attribute;
  81. import static net.sourceforge.subsonic.util.XMLBuilder.AttributeSet;
  82. /**
  83. * Multi-controller used for the REST API.
  84. * <p/>
  85. * For documentation, please refer to api.jsp.
  86. * <p/>
  87. * Note: Exceptions thrown from the methods are intercepted by RESTFilter.
  88. *
  89. * @author Sindre Mehus
  90. */
  91. public class RESTController extends MultiActionController {
  92. private static final Logger LOG = Logger.getLogger(RESTController.class);
  93. private SettingsService settingsService;
  94. private SecurityService securityService;
  95. private PlayerService playerService;
  96. private MediaFileService mediaFileService;
  97. private MusicIndexService musicIndexService;
  98. private TranscodingService transcodingService;
  99. private DownloadController downloadController;
  100. private CoverArtController coverArtController;
  101. private AvatarController avatarController;
  102. private UserSettingsController userSettingsController;
  103. private LeftController leftController;
  104. private HomeController homeController;
  105. private StatusService statusService;
  106. private StreamController streamController;
  107. private HLSController hlsController;
  108. private ShareService shareService;
  109. private PlaylistService playlistService;
  110. private ChatService chatService;
  111. private LyricsService lyricsService;
  112. private PlayQueueService playQueueService;
  113. private JukeboxService jukeboxService;
  114. private AudioScrobblerService audioScrobblerService;
  115. private PodcastService podcastService;
  116. private RatingService ratingService;
  117. private SearchService searchService;
  118. private MediaFileDao mediaFileDao;
  119. private ArtistDao artistDao;
  120. private AlbumDao albumDao;
  121. public void ping(HttpServletRequest request, HttpServletResponse response) throws Exception {
  122. XMLBuilder builder = createXMLBuilder(request, response, true).endAll();
  123. response.getWriter().print(builder);
  124. }
  125. public void getLicense(HttpServletRequest request, HttpServletResponse response) throws Exception {
  126. request = wrapRequest(request);
  127. XMLBuilder builder = createXMLBuilder(request, response, true);
  128. String email = settingsService.getLicenseEmail();
  129. String key = settingsService.getLicenseCode();
  130. Date date = settingsService.getLicenseDate();
  131. boolean valid = settingsService.isLicenseValid();
  132. AttributeSet attributes = new AttributeSet();
  133. attributes.add("valid", valid);
  134. if (valid) {
  135. attributes.add("email", email);
  136. attributes.add("key", key);
  137. attributes.add("date", StringUtil.toISO8601(date));
  138. }
  139. builder.add("license", attributes, true);
  140. builder.endAll();
  141. response.getWriter().print(builder);
  142. }
  143. public void getMusicFolders(HttpServletRequest request, HttpServletResponse response) throws Exception {
  144. request = wrapRequest(request);
  145. XMLBuilder builder = createXMLBuilder(request, response, true);
  146. builder.add("musicFolders", false);
  147. for (MusicFolder musicFolder : settingsService.getAllMusicFolders()) {
  148. AttributeSet attributes = new AttributeSet();
  149. attributes.add("id", musicFolder.getId());
  150. attributes.add("name", musicFolder.getName());
  151. builder.add("musicFolder", attributes, true);
  152. }
  153. builder.endAll();
  154. response.getWriter().print(builder);
  155. }
  156. public void getIndexes(HttpServletRequest request, HttpServletResponse response) throws Exception {
  157. request = wrapRequest(request);
  158. XMLBuilder builder = createXMLBuilder(request, response, true);
  159. long ifModifiedSince = ServletRequestUtils.getLongParameter(request, "ifModifiedSince", 0L);
  160. long lastModified = leftController.getLastModified(request);
  161. if (lastModified <= ifModifiedSince) {
  162. builder.endAll();
  163. response.getWriter().print(builder);
  164. return;
  165. }
  166. builder.add("indexes", "lastModified", lastModified, false);
  167. List<MusicFolder> musicFolders = settingsService.getAllMusicFolders();
  168. Integer musicFolderId = ServletRequestUtils.getIntParameter(request, "musicFolderId");
  169. if (musicFolderId != null) {
  170. for (MusicFolder musicFolder : musicFolders) {
  171. if (musicFolderId.equals(musicFolder.getId())) {
  172. musicFolders = Arrays.asList(musicFolder);
  173. break;
  174. }
  175. }
  176. }
  177. List<MediaFile> shortcuts = leftController.getShortcuts(musicFolders, settingsService.getShortcutsAsArray());
  178. for (MediaFile shortcut : shortcuts) {
  179. builder.add("shortcut", true,
  180. new Attribute("name", shortcut.getName()),
  181. new Attribute("id", shortcut.getId()));
  182. }
  183. SortedMap<MusicIndex, SortedSet<MusicIndex.SortableArtistWithMediaFiles>> indexedArtists =
  184. leftController.getMusicFolderContent(musicFolders, false).getIndexedArtists();
  185. for (Map.Entry<MusicIndex, SortedSet<MusicIndex.SortableArtistWithMediaFiles>> entry : indexedArtists.entrySet()) {
  186. builder.add("index", "name", entry.getKey().getIndex(), false);
  187. for (MusicIndex.SortableArtistWithMediaFiles artist : entry.getValue()) {
  188. for (MediaFile mediaFile : artist.getMediaFiles()) {
  189. if (mediaFile.isDirectory()) {
  190. builder.add("artist", true,
  191. new Attribute("name", artist.getName()),
  192. new Attribute("id", mediaFile.getId()));
  193. }
  194. }
  195. }
  196. builder.end();
  197. }
  198. // Add children
  199. Player player = playerService.getPlayer(request, response);
  200. String username = securityService.getCurrentUsername(request);
  201. List<MediaFile> singleSongs = leftController.getSingleSongs(musicFolders, false);
  202. for (MediaFile singleSong : singleSongs) {
  203. builder.add("child", createAttributesForMediaFile(player, singleSong, username), true);
  204. }
  205. builder.endAll();
  206. response.getWriter().print(builder);
  207. }
  208. public void getArtists(HttpServletRequest request, HttpServletResponse response) throws Exception {
  209. request = wrapRequest(request);
  210. XMLBuilder builder = createXMLBuilder(request, response, true);
  211. String username = securityService.getCurrentUsername(request);
  212. builder.add("artists", false);
  213. List<Artist> artists = artistDao.getAlphabetialArtists(0, Integer.MAX_VALUE);
  214. SortedMap<MusicIndex, SortedSet<MusicIndex.SortableArtistWithArtist>> indexedArtists = musicIndexService.getIndexedArtists(artists);
  215. for (Map.Entry<MusicIndex, SortedSet<MusicIndex.SortableArtistWithArtist>> entry : indexedArtists.entrySet()) {
  216. builder.add("index", "name", entry.getKey().getIndex(), false);
  217. for (MusicIndex.SortableArtistWithArtist sortableArtist : entry.getValue()) {
  218. AttributeSet attributes = createAttributesForArtist(sortableArtist.getArtist(), username);
  219. builder.add("artist", attributes, true);
  220. }
  221. builder.end();
  222. }
  223. builder.endAll();
  224. response.getWriter().print(builder);
  225. }
  226. private AttributeSet createAttributesForArtist(Artist artist, String username) {
  227. AttributeSet attributes = new AttributeSet();
  228. attributes.add("id", artist.getId());
  229. attributes.add("name", artist.getName());
  230. if (artist.getCoverArtPath() != null) {
  231. attributes.add("coverArt", CoverArtController.ARTIST_COVERART_PREFIX + artist.getId());
  232. }
  233. attributes.add("albumCount", artist.getAlbumCount());
  234. attributes.add("starred", StringUtil.toISO8601(artistDao.getArtistStarredDate(artist.getId(), username)));
  235. return attributes;
  236. }
  237. public void getArtist(HttpServletRequest request, HttpServletResponse response) throws Exception {
  238. request = wrapRequest(request);
  239. XMLBuilder builder = createXMLBuilder(request, response, true);
  240. String username = securityService.getCurrentUsername(request);
  241. int id = ServletRequestUtils.getRequiredIntParameter(request, "id");
  242. Artist artist = artistDao.getArtist(id);
  243. if (artist == null) {
  244. error(request, response, ErrorCode.NOT_FOUND, "Artist not found.");
  245. return;
  246. }
  247. builder.add("artist", createAttributesForArtist(artist, username), false);
  248. for (Album album : albumDao.getAlbumsForArtist(artist.getName())) {
  249. builder.add("album", createAttributesForAlbum(album, username), true);
  250. }
  251. builder.endAll();
  252. response.getWriter().print(builder);
  253. }
  254. private AttributeSet createAttributesForAlbum(Album album, String username) {
  255. AttributeSet attributes;
  256. attributes = new AttributeSet();
  257. attributes.add("id", album.getId());
  258. attributes.add("name", album.getName());
  259. attributes.add("artist", album.getArtist());
  260. if (album.getArtist() != null) {
  261. Artist artist = artistDao.getArtist(album.getArtist());
  262. if (artist != null) {
  263. attributes.add("artistId", artist.getId());
  264. }
  265. }
  266. if (album.getCoverArtPath() != null) {
  267. attributes.add("coverArt", CoverArtController.ALBUM_COVERART_PREFIX + album.getId());
  268. }
  269. attributes.add("songCount", album.getSongCount());
  270. attributes.add("duration", album.getDurationSeconds());
  271. attributes.add("created", StringUtil.toISO8601(album.getCreated()));
  272. attributes.add("starred", StringUtil.toISO8601(albumDao.getAlbumStarredDate(album.getId(), username)));
  273. return attributes;
  274. }
  275. private AttributeSet createAttributesForPlaylist(Playlist playlist) {
  276. AttributeSet attributes;
  277. attributes = new AttributeSet();
  278. attributes.add("id", playlist.getId());
  279. attributes.add("name", playlist.getName());
  280. attributes.add("comment", playlist.getComment());
  281. attributes.add("owner", playlist.getUsername());
  282. attributes.add("public", playlist.isPublic());
  283. attributes.add("songCount", playlist.getFileCount());
  284. attributes.add("duration", playlist.getDurationSeconds());
  285. attributes.add("created", StringUtil.toISO8601(playlist.getCreated()));
  286. return attributes;
  287. }
  288. public void getAlbum(HttpServletRequest request, HttpServletResponse response) throws Exception {
  289. request = wrapRequest(request);
  290. Player player = playerService.getPlayer(request, response);
  291. String username = securityService.getCurrentUsername(request);
  292. XMLBuilder builder = createXMLBuilder(request, response, true);
  293. int id = ServletRequestUtils.getRequiredIntParameter(request, "id");
  294. Album album = albumDao.getAlbum(id);
  295. if (album == null) {
  296. error(request, response, ErrorCode.NOT_FOUND, "Album not found.");
  297. return;
  298. }
  299. builder.add("album", createAttributesForAlbum(album, username), false);
  300. for (MediaFile mediaFile : mediaFileDao.getSongsForAlbum(album.getArtist(), album.getName())) {
  301. builder.add("song", createAttributesForMediaFile(player, mediaFile, username), true);
  302. }
  303. builder.endAll();
  304. response.getWriter().print(builder);
  305. }
  306. public void getSong(HttpServletRequest request, HttpServletResponse response) throws Exception {
  307. request = wrapRequest(request);
  308. Player player = playerService.getPlayer(request, response);
  309. String username = securityService.getCurrentUsername(request);
  310. XMLBuilder builder = createXMLBuilder(request, response, true);
  311. int id = ServletRequestUtils.getRequiredIntParameter(request, "id");
  312. MediaFile song = mediaFileDao.getMediaFile(id);
  313. if (song == null || song.isDirectory()) {
  314. error(request, response, ErrorCode.NOT_FOUND, "Song not found.");
  315. return;
  316. }
  317. builder.add("song", createAttributesForMediaFile(player, song, username), true);
  318. builder.endAll();
  319. response.getWriter().print(builder);
  320. }
  321. public void getMusicDirectory(HttpServletRequest request, HttpServletResponse response) throws Exception {
  322. request = wrapRequest(request);
  323. Player player = playerService.getPlayer(request, response);
  324. String username = securityService.getCurrentUsername(request);
  325. int id = ServletRequestUtils.getRequiredIntParameter(request, "id");
  326. MediaFile dir = mediaFileService.getMediaFile(id);
  327. if (dir == null) {
  328. error(request, response, ErrorCode.NOT_FOUND, "Directory not found");
  329. return;
  330. }
  331. XMLBuilder builder = createXMLBuilder(request, response, true);
  332. builder.add("directory", false,
  333. new Attribute("id", dir.getId()),
  334. new Attribute("name", dir.getName()));
  335. for (MediaFile child : mediaFileService.getChildrenOf(dir, true, true, true)) {
  336. AttributeSet attributes = createAttributesForMediaFile(player, child, username);
  337. builder.add("child", attributes, true);
  338. }
  339. builder.endAll();
  340. response.getWriter().print(builder);
  341. }
  342. @Deprecated
  343. public void search(HttpServletRequest request, HttpServletResponse response) throws Exception {
  344. request = wrapRequest(request);
  345. XMLBuilder builder = createXMLBuilder(request, response, true);
  346. Player player = playerService.getPlayer(request, response);
  347. String username = securityService.getCurrentUsername(request);
  348. String any = request.getParameter("any");
  349. String artist = request.getParameter("artist");
  350. String album = request.getParameter("album");
  351. String title = request.getParameter("title");
  352. StringBuilder query = new StringBuilder();
  353. if (any != null) {
  354. query.append(any).append(" ");
  355. }
  356. if (artist != null) {
  357. query.append(artist).append(" ");
  358. }
  359. if (album != null) {
  360. query.append(album).append(" ");
  361. }
  362. if (title != null) {
  363. query.append(title);
  364. }
  365. SearchCriteria criteria = new SearchCriteria();
  366. criteria.setQuery(query.toString().trim());
  367. criteria.setCount(ServletRequestUtils.getIntParameter(request, "count", 20));
  368. criteria.setOffset(ServletRequestUtils.getIntParameter(request, "offset", 0));
  369. SearchResult result = searchService.search(criteria, SearchService.IndexType.SONG);
  370. builder.add("searchResult", false,
  371. new Attribute("offset", result.getOffset()),
  372. new Attribute("totalHits", result.getTotalHits()));
  373. for (MediaFile mediaFile : result.getMediaFiles()) {
  374. AttributeSet attributes = createAttributesForMediaFile(player, mediaFile, username);
  375. builder.add("match", attributes, true);
  376. }
  377. builder.endAll();
  378. response.getWriter().print(builder);
  379. }
  380. public void search2(HttpServletRequest request, HttpServletResponse response) throws Exception {
  381. request = wrapRequest(request);
  382. XMLBuilder builder = createXMLBuilder(request, response, true);
  383. Player player = playerService.getPlayer(request, response);
  384. String username = securityService.getCurrentUsername(request);
  385. builder.add("searchResult2", false);
  386. String query = request.getParameter("query");
  387. SearchCriteria criteria = new SearchCriteria();
  388. criteria.setQuery(StringUtils.trimToEmpty(query));
  389. criteria.setCount(ServletRequestUtils.getIntParameter(request, "artistCount", 20));
  390. criteria.setOffset(ServletRequestUtils.getIntParameter(request, "artistOffset", 0));
  391. SearchResult artists = searchService.search(criteria, SearchService.IndexType.ARTIST);
  392. for (MediaFile mediaFile : artists.getMediaFiles()) {
  393. builder.add("artist", true,
  394. new Attribute("name", mediaFile.getName()),
  395. new Attribute("id", mediaFile.getId()));
  396. }
  397. criteria.setCount(ServletRequestUtils.getIntParameter(request, "albumCount", 20));
  398. criteria.setOffset(ServletRequestUtils.getIntParameter(request, "albumOffset", 0));
  399. SearchResult albums = searchService.search(criteria, SearchService.IndexType.ALBUM);
  400. for (MediaFile mediaFile : albums.getMediaFiles()) {
  401. AttributeSet attributes = createAttributesForMediaFile(player, mediaFile, username);
  402. builder.add("album", attributes, true);
  403. }
  404. criteria.setCount(ServletRequestUtils.getIntParameter(request, "songCount", 20));
  405. criteria.setOffset(ServletRequestUtils.getIntParameter(request, "songOffset", 0));
  406. SearchResult songs = searchService.search(criteria, SearchService.IndexType.SONG);
  407. for (MediaFile mediaFile : songs.getMediaFiles()) {
  408. AttributeSet attributes = createAttributesForMediaFile(player, mediaFile, username);
  409. builder.add("song", attributes, true);
  410. }
  411. builder.endAll();
  412. response.getWriter().print(builder);
  413. }
  414. public void search3(HttpServletRequest request, HttpServletResponse response) throws Exception {
  415. request = wrapRequest(request);
  416. XMLBuilder builder = createXMLBuilder(request, response, true);
  417. Player player = playerService.getPlayer(request, response);
  418. String username = securityService.getCurrentUsername(request);
  419. builder.add("searchResult3", false);
  420. String query = request.getParameter("query");
  421. SearchCriteria criteria = new SearchCriteria();
  422. criteria.setQuery(StringUtils.trimToEmpty(query));
  423. criteria.setCount(ServletRequestUtils.getIntParameter(request, "artistCount", 20));
  424. criteria.setOffset(ServletRequestUtils.getIntParameter(request, "artistOffset", 0));
  425. SearchResult searchResult = searchService.search(criteria, SearchService.IndexType.ARTIST_ID3);
  426. for (Artist artist : searchResult.getArtists()) {
  427. builder.add("artist", createAttributesForArtist(artist, username), true);
  428. }
  429. criteria.setCount(ServletRequestUtils.getIntParameter(request, "albumCount", 20));
  430. criteria.setOffset(ServletRequestUtils.getIntParameter(request, "albumOffset", 0));
  431. searchResult = searchService.search(criteria, SearchService.IndexType.ALBUM_ID3);
  432. for (Album album : searchResult.getAlbums()) {
  433. builder.add("album", createAttributesForAlbum(album, username), true);
  434. }
  435. criteria.setCount(ServletRequestUtils.getIntParameter(request, "songCount", 20));
  436. criteria.setOffset(ServletRequestUtils.getIntParameter(request, "songOffset", 0));
  437. searchResult = searchService.search(criteria, SearchService.IndexType.SONG);
  438. for (MediaFile song : searchResult.getMediaFiles()) {
  439. builder.add("song", createAttributesForMediaFile(player, song, username), true);
  440. }
  441. builder.endAll();
  442. response.getWriter().print(builder);
  443. }
  444. public void getPlaylists(HttpServletRequest request, HttpServletResponse response) throws Exception {
  445. request = wrapRequest(request);
  446. XMLBuilder builder = createXMLBuilder(request, response, true);
  447. User user = securityService.getCurrentUser(request);
  448. String authenticatedUsername = user.getUsername();
  449. String requestedUsername = request.getParameter("username");
  450. if (requestedUsername == null) {
  451. requestedUsername = authenticatedUsername;
  452. } else if (!user.isAdminRole()) {
  453. error(request, response, ErrorCode.NOT_AUTHORIZED, authenticatedUsername + " is not authorized to get playlists for " + requestedUsername);
  454. return;
  455. }
  456. builder.add("playlists", false);
  457. for (Playlist playlist : playlistService.getReadablePlaylistsForUser(requestedUsername)) {
  458. List<String> sharedUsers = playlistService.getPlaylistUsers(playlist.getId());
  459. builder.add("playlist", createAttributesForPlaylist(playlist), sharedUsers.isEmpty());
  460. if (!sharedUsers.isEmpty()) {
  461. for (String username : sharedUsers) {
  462. builder.add("allowedUser", (Iterable<Attribute>) null, username, true);
  463. }
  464. builder.end();
  465. }
  466. }
  467. builder.endAll();
  468. response.getWriter().print(builder);
  469. }
  470. public void getPlaylist(HttpServletRequest request, HttpServletResponse response) throws Exception {
  471. request = wrapRequest(request);
  472. Player player = playerService.getPlayer(request, response);
  473. String username = securityService.getCurrentUsername(request);
  474. XMLBuilder builder = createXMLBuilder(request, response, true);
  475. int id = ServletRequestUtils.getRequiredIntParameter(request, "id");
  476. Playlist playlist = playlistService.getPlaylist(id);
  477. if (playlist == null) {
  478. error(request, response, ErrorCode.NOT_FOUND, "Playlist not found: " + id);
  479. return;
  480. }
  481. if (!playlistService.isReadAllowed(playlist, username)) {
  482. error(request, response, ErrorCode.NOT_AUTHORIZED, "Permission denied for playlist " + id);
  483. return;
  484. }
  485. builder.add("playlist", createAttributesForPlaylist(playlist), false);
  486. for (String allowedUser : playlistService.getPlaylistUsers(playlist.getId())) {
  487. builder.add("allowedUser", (Iterable<Attribute>) null, allowedUser, true);
  488. }
  489. for (MediaFile mediaFile : playlistService.getFilesInPlaylist(id)) {
  490. AttributeSet attributes = createAttributesForMediaFile(player, mediaFile, username);
  491. builder.add("entry", attributes, true);
  492. }
  493. builder.endAll();
  494. response.getWriter().print(builder);
  495. }
  496. public void jukeboxControl(HttpServletRequest request, HttpServletResponse response) throws Exception {
  497. request = wrapRequest(request, true);
  498. User user = securityService.getCurrentUser(request);
  499. if (!user.isJukeboxRole()) {
  500. error(request, response, ErrorCode.NOT_AUTHORIZED, user.getUsername() + " is not authorized to use jukebox.");
  501. return;
  502. }
  503. boolean returnPlaylist = false;
  504. String action = ServletRequestUtils.getRequiredStringParameter(request, "action");
  505. if ("start".equals(action)) {
  506. playQueueService.doStart(request, response);
  507. } else if ("stop".equals(action)) {
  508. playQueueService.doStop(request, response);
  509. } else if ("skip".equals(action)) {
  510. int index = ServletRequestUtils.getRequiredIntParameter(request, "index");
  511. int offset = ServletRequestUtils.getIntParameter(request, "offset", 0);
  512. playQueueService.doSkip(request, response, index, offset);
  513. } else if ("add".equals(action)) {
  514. int[] ids = ServletRequestUtils.getIntParameters(request, "id");
  515. playQueueService.doAdd(request, response, ids);
  516. } else if ("set".equals(action)) {
  517. int[] ids = ServletRequestUtils.getIntParameters(request, "id");
  518. playQueueService.doSet(request, response, ids);
  519. } else if ("clear".equals(action)) {
  520. playQueueService.doClear(request, response);
  521. } else if ("remove".equals(action)) {
  522. int index = ServletRequestUtils.getRequiredIntParameter(request, "index");
  523. playQueueService.doRemove(request, response, index);
  524. } else if ("shuffle".equals(action)) {
  525. playQueueService.doShuffle(request, response);
  526. } else if ("setGain".equals(action)) {
  527. float gain = ServletRequestUtils.getRequiredFloatParameter(request, "gain");
  528. jukeboxService.setGain(gain);
  529. } else if ("get".equals(action)) {
  530. returnPlaylist = true;
  531. } else if ("status".equals(action)) {
  532. // No action necessary.
  533. } else {
  534. throw new Exception("Unknown jukebox action: '" + action + "'.");
  535. }
  536. XMLBuilder builder = createXMLBuilder(request, response, true);
  537. Player player = playerService.getPlayer(request, response);
  538. String username = securityService.getCurrentUsername(request);
  539. Player jukeboxPlayer = jukeboxService.getPlayer();
  540. boolean controlsJukebox = jukeboxPlayer != null && jukeboxPlayer.getId().equals(player.getId());
  541. PlayQueue playQueue = player.getPlayQueue();
  542. List<Attribute> attrs = new ArrayList<Attribute>(Arrays.asList(
  543. new Attribute("currentIndex", controlsJukebox && !playQueue.isEmpty() ? playQueue.getIndex() : -1),
  544. new Attribute("playing", controlsJukebox && !playQueue.isEmpty() && playQueue.getStatus() == PlayQueue.Status.PLAYING),
  545. new Attribute("gain", jukeboxService.getGain()),
  546. new Attribute("position", controlsJukebox && !playQueue.isEmpty() ? jukeboxService.getPosition() : 0)));
  547. if (returnPlaylist) {
  548. builder.add("jukeboxPlaylist", attrs, false);
  549. List<MediaFile> result;
  550. synchronized (playQueue) {
  551. result = playQueue.getFiles();
  552. }
  553. for (MediaFile mediaFile : result) {
  554. AttributeSet attributes = createAttributesForMediaFile(player, mediaFile, username);
  555. builder.add("entry", attributes, true);
  556. }
  557. } else {
  558. builder.add("jukeboxStatus", attrs, false);
  559. }
  560. builder.endAll();
  561. response.getWriter().print(builder);
  562. }
  563. public void createPlaylist(HttpServletRequest request, HttpServletResponse response) throws Exception {
  564. request = wrapRequest(request, true);
  565. String username = securityService.getCurrentUsername(request);
  566. Integer playlistId = ServletRequestUtils.getIntParameter(request, "playlistId");
  567. String name = request.getParameter("name");
  568. if (playlistId == null && name == null) {
  569. error(request, response, ErrorCode.MISSING_PARAMETER, "Playlist ID or name must be specified.");
  570. return;
  571. }
  572. Playlist playlist;
  573. if (playlistId != null) {
  574. playlist = playlistService.getPlaylist(playlistId);
  575. if (playlist == null) {
  576. error(request, response, ErrorCode.NOT_FOUND, "Playlist not found: " + playlistId);
  577. return;
  578. }
  579. if (!playlistService.isWriteAllowed(playlist, username)) {
  580. error(request, response, ErrorCode.NOT_AUTHORIZED, "Permission denied for playlist " + playlistId);
  581. return;
  582. }
  583. } else {
  584. playlist = new Playlist();
  585. playlist.setName(name);
  586. playlist.setCreated(new Date());
  587. playlist.setChanged(new Date());
  588. playlist.setPublic(false);
  589. playlist.setUsername(username);
  590. playlistService.createPlaylist(playlist);
  591. }
  592. List<MediaFile> songs = new ArrayList<MediaFile>();
  593. for (int id : ServletRequestUtils.getIntParameters(request, "songId")) {
  594. MediaFile song = mediaFileService.getMediaFile(id);
  595. if (song != null) {
  596. songs.add(song);
  597. }
  598. }
  599. playlistService.setFilesInPlaylist(playlist.getId(), songs);
  600. XMLBuilder builder = createXMLBuilder(request, response, true);
  601. builder.endAll();
  602. response.getWriter().print(builder);
  603. }
  604. public void updatePlaylist(HttpServletRequest request, HttpServletResponse response) throws Exception {
  605. request = wrapRequest(request, true);
  606. String username = securityService.getCurrentUsername(request);
  607. int id = ServletRequestUtils.getRequiredIntParameter(request, "playlistId");
  608. Playlist playlist = playlistService.getPlaylist(id);
  609. if (playlist == null) {
  610. error(request, response, ErrorCode.NOT_FOUND, "Playlist not found: " + id);
  611. return;
  612. }
  613. if (!playlistService.isWriteAllowed(playlist, username)) {
  614. error(request, response, ErrorCode.NOT_AUTHORIZED, "Permission denied for playlist " + id);
  615. return;
  616. }
  617. String name = request.getParameter("name");
  618. if (name != null) {
  619. playlist.setName(name);
  620. }
  621. String comment = request.getParameter("comment");
  622. if (comment != null) {
  623. playlist.setComment(comment);
  624. }
  625. Boolean isPublic = ServletRequestUtils.getBooleanParameter(request, "public");
  626. if (isPublic != null) {
  627. playlist.setPublic(isPublic);
  628. }
  629. playlistService.updatePlaylist(playlist);
  630. // TODO: Add later
  631. // for (String usernameToAdd : ServletRequestUtils.getStringParameters(request, "usernameToAdd")) {
  632. // if (securityService.getUserByName(usernameToAdd) != null) {
  633. // playlistService.addPlaylistUser(id, usernameToAdd);
  634. // }
  635. // }
  636. // for (String usernameToRemove : ServletRequestUtils.getStringParameters(request, "usernameToRemove")) {
  637. // if (securityService.getUserByName(usernameToRemove) != null) {
  638. // playlistService.deletePlaylistUser(id, usernameToRemove);
  639. // }
  640. // }
  641. List<MediaFile> songs = playlistService.getFilesInPlaylist(id);
  642. boolean songsChanged = false;
  643. SortedSet<Integer> tmp = new TreeSet<Integer>();
  644. for (int songIndexToRemove : ServletRequestUtils.getIntParameters(request, "songIndexToRemove")) {
  645. tmp.add(songIndexToRemove);
  646. }
  647. List<Integer> songIndexesToRemove = new ArrayList<Integer>(tmp);
  648. Collections.reverse(songIndexesToRemove);
  649. for (Integer songIndexToRemove : songIndexesToRemove) {
  650. songs.remove(songIndexToRemove.intValue());
  651. songsChanged = true;
  652. }
  653. for (int songToAdd : ServletRequestUtils.getIntParameters(request, "songIdToAdd")) {
  654. MediaFile song = mediaFileService.getMediaFile(songToAdd);
  655. if (song != null) {
  656. songs.add(song);
  657. songsChanged = true;
  658. }
  659. }
  660. if (songsChanged) {
  661. playlistService.setFilesInPlaylist(id, songs);
  662. }
  663. XMLBuilder builder = createXMLBuilder(request, response, true);
  664. builder.endAll();
  665. response.getWriter().print(builder);
  666. }
  667. public void deletePlaylist(HttpServletRequest request, HttpServletResponse response) throws Exception {
  668. request = wrapRequest(request, true);
  669. String username = securityService.getCurrentUsername(request);
  670. int id = ServletRequestUtils.getRequiredIntParameter(request, "id");
  671. Playlist playlist = playlistService.getPlaylist(id);
  672. if (playlist == null) {
  673. error(request, response, ErrorCode.NOT_FOUND, "Playlist not found: " + id);
  674. return;
  675. }
  676. if (!playlistService.isWriteAllowed(playlist, username)) {
  677. error(request, response, ErrorCode.NOT_AUTHORIZED, "Permission denied for playlist " + id);
  678. return;
  679. }
  680. playlistService.deletePlaylist(id);
  681. XMLBuilder builder = createXMLBuilder(request, response, true);
  682. builder.endAll();
  683. response.getWriter().print(builder);
  684. }
  685. public void getAlbumList(HttpServletRequest request, HttpServletResponse response) throws Exception {
  686. request = wrapRequest(request);
  687. Player player = playerService.getPlayer(request, response);
  688. String username = securityService.getCurrentUsername(request);
  689. XMLBuilder builder = createXMLBuilder(request, response, true);
  690. builder.add("albumList", false);
  691. int size = ServletRequestUtils.getIntParameter(request, "size", 10);
  692. int offset = ServletRequestUtils.getIntParameter(request, "offset", 0);
  693. size = Math.max(0, Math.min(size, 500));
  694. String type = ServletRequestUtils.getRequiredStringParameter(request, "type");
  695. List<HomeController.Album> albums;
  696. if ("highest".equals(type)) {
  697. albums = homeController.getHighestRated(offset, size);
  698. } else if ("frequent".equals(type)) {
  699. albums = homeController.getMostFrequent(offset, size);
  700. } else if ("recent".equals(type)) {
  701. albums = homeController.getMostRecent(offset, size);
  702. } else if ("newest".equals(type)) {
  703. albums = homeController.getNewest(offset, size);
  704. } else if ("starred".equals(type)) {
  705. albums = homeController.getStarred(offset, size, username);
  706. } else if ("alphabeticalByArtist".equals(type)) {
  707. albums = homeController.getAlphabetical(offset, size, true);
  708. } else if ("alphabeticalByName".equals(type)) {
  709. albums = homeController.getAlphabetical(offset, size, false);
  710. } else if ("random".equals(type)) {
  711. albums = homeController.getRandom(size);
  712. } else {
  713. throw new Exception("Invalid list type: " + type);
  714. }
  715. for (HomeController.Album album : albums) {
  716. MediaFile mediaFile = mediaFileService.getMediaFile(album.getPath());
  717. AttributeSet attributes = createAttributesForMediaFile(player, mediaFile, username);
  718. builder.add("album", attributes, true);
  719. }
  720. builder.endAll();
  721. response.getWriter().print(builder);
  722. }
  723. public void getAlbumList2(HttpServletRequest request, HttpServletResponse response) throws Exception {
  724. request = wrapRequest(request);
  725. XMLBuilder builder = createXMLBuilder(request, response, true);
  726. builder.add("albumList2", false);
  727. int size = ServletRequestUtils.getIntParameter(request, "size", 10);
  728. int offset = ServletRequestUtils.getIntParameter(request, "offset", 0);
  729. size = Math.max(0, Math.min(size, 500));
  730. String type = ServletRequestUtils.getRequiredStringParameter(request, "type");
  731. String username = securityService.getCurrentUsername(request);
  732. List<Album> albums;
  733. if ("frequent".equals(type)) {
  734. albums = albumDao.getMostFrequentlyPlayedAlbums(offset, size);
  735. } else if ("recent".equals(type)) {
  736. albums = albumDao.getMostRecentlyPlayedAlbums(offset, size);
  737. } else if ("newest".equals(type)) {
  738. albums = albumDao.getNewestAlbums(offset, size);
  739. } else if ("alphabeticalByArtist".equals(type)) {
  740. albums = albumDao.getAlphabetialAlbums(offset, size, true);
  741. } else if ("alphabeticalByName".equals(type)) {
  742. albums = albumDao.getAlphabetialAlbums(offset, size, false);
  743. } else if ("starred".equals(type)) {
  744. albums = albumDao.getStarredAlbums(offset, size, securityService.getCurrentUser(request).getUsername());
  745. } else if ("random".equals(type)) {
  746. albums = searchService.getRandomAlbumsId3(size);
  747. } else {
  748. throw new Exception("Invalid list type: " + type);
  749. }
  750. for (Album album : albums) {
  751. builder.add("album", createAttributesForAlbum(album, username), true);
  752. }
  753. builder.endAll();
  754. response.getWriter().print(builder);
  755. }
  756. public void getRandomSongs(HttpServletRequest request, HttpServletResponse response) throws Exception {
  757. request = wrapRequest(request);
  758. Player player = playerService.getPlayer(request, response);
  759. String username = securityService.getCurrentUsername(request);
  760. XMLBuilder builder = createXMLBuilder(request, response, true);
  761. builder.add("randomSongs", false);
  762. int size = ServletRequestUtils.getIntParameter(request, "size", 10);
  763. size = Math.max(0, Math.min(size, 500));
  764. String genre = ServletRequestUtils.getStringParameter(request, "genre");
  765. Integer fromYear = ServletRequestUtils.getIntParameter(request, "fromYear");
  766. Integer toYear = ServletRequestUtils.getIntParameter(request, "toYear");
  767. Integer musicFolderId = ServletRequestUtils.getIntParameter(request, "musicFolderId");
  768. RandomSearchCriteria criteria = new RandomSearchCriteria(size, genre, fromYear, toYear, musicFolderId);
  769. for (MediaFile mediaFile : searchService.getRandomSongs(criteria)) {
  770. AttributeSet attributes = createAttributesForMediaFile(player, mediaFile, username);
  771. builder.add("song", attributes, true);
  772. }
  773. builder.endAll();
  774. response.getWriter().print(builder);
  775. }
  776. public void getVideos(HttpServletRequest request, HttpServletResponse response) throws Exception {
  777. request = wrapRequest(request);
  778. Player player = playerService.getPlayer(request, response);
  779. String username = securityService.getCurrentUsername(request);
  780. XMLBuilder builder = createXMLBuilder(request, response, true);
  781. builder.add("videos", false);
  782. int size = ServletRequestUtils.getIntParameter(request, "size", Integer.MAX_VALUE);
  783. int offset = ServletRequestUtils.getIntParameter(request, "offset", 0);
  784. for (MediaFile mediaFile : mediaFileDao.getVideos(size, offset)) {
  785. builder.add("video", createAttributesForMediaFile(player, mediaFile, username), true);
  786. }
  787. builder.endAll();
  788. response.getWriter().print(builder);
  789. }
  790. public void getNowPlaying(HttpServletRequest request, HttpServletResponse response) throws Exception {
  791. request = wrapRequest(request);
  792. XMLBuilder builder = createXMLBuilder(request, response, true);
  793. builder.add("nowPlaying", false);
  794. for (TransferStatus status : statusService.getAllStreamStatuses()) {
  795. Player player = status.getPlayer();
  796. File file = status.getFile();
  797. if (player != null && player.getUsername() != null && file != null) {
  798. String username = player.getUsername();
  799. UserSettings userSettings = settingsService.getUserSettings(username);
  800. if (!userSettings.isNowPlayingAllowed()) {
  801. continue;
  802. }
  803. MediaFile mediaFile = mediaFileService.getMediaFile(file);
  804. long minutesAgo = status.getMillisSinceLastUpdate() / 1000L / 60L;
  805. if (minutesAgo < 60) {
  806. AttributeSet attributes = createAttributesForMediaFile(player, mediaFile, username);
  807. attributes.add("username", username);
  808. attributes.add("playerId", player.getId());
  809. attributes.add("playerName", player.getName());
  810. attributes.add("minutesAgo", minutesAgo);
  811. builder.add("entry", attributes, true);
  812. }
  813. }
  814. }
  815. builder.endAll();
  816. response.getWriter().print(builder);
  817. }
  818. private AttributeSet createAttributesForMediaFile(Player player, MediaFile mediaFile, String username) {
  819. MediaFile parent = mediaFileService.getParentOf(mediaFile);
  820. AttributeSet attributes = new AttributeSet();
  821. attributes.add("id", mediaFile.getId());
  822. try {
  823. if (!mediaFileService.isRoot(parent)) {
  824. attributes.add("parent", parent.getId());
  825. }
  826. } catch (SecurityException x) {
  827. // Ignored.
  828. }
  829. attributes.add("title", mediaFile.getName());
  830. attributes.add("album", mediaFile.getAlbumName());
  831. attributes.add("artist", mediaFile.getArtist());
  832. attributes.add("isDir", mediaFile.isDirectory());
  833. attributes.add("coverArt", findCoverArt(mediaFile, parent));
  834. attributes.add("created", StringUtil.toISO8601(mediaFile.getCreated()));
  835. attributes.add("starred", StringUtil.toISO8601(mediaFileDao.getMediaFileStarredDate(mediaFile.getId(), username)));
  836. attributes.add("userRating", ratingService.getRatingForUser(username, mediaFile));
  837. attributes.add("averageRating", ratingService.getAverageRating(mediaFile));
  838. if (mediaFile.isFile()) {
  839. attributes.add("duration", mediaFile.getDurationSeconds());
  840. attributes.add("bitRate", mediaFile.getBitRate());
  841. attributes.add("track", mediaFile.getTrackNumber());
  842. attributes.add("discNumber", mediaFile.getDiscNumber());
  843. attributes.add("year", mediaFile.getYear());
  844. attributes.add("genre", mediaFile.getGenre());
  845. attributes.add("size", mediaFile.getFileSize());
  846. String suffix = mediaFile.getFormat();
  847. attributes.add("suffix", suffix);
  848. attributes.add("contentType", StringUtil.getMimeType(suffix));
  849. attributes.add("isVideo", mediaFile.isVideo());
  850. attributes.add("path", getRelativePath(mediaFile));
  851. if (mediaFile.getArtist() != null && mediaFile.getAlbumName() != null) {
  852. Album album = albumDao.getAlbum(mediaFile.getAlbumArtist(), mediaFile.getAlbumName());
  853. if (album != null) {
  854. attributes.add("albumId", album.getId());
  855. }
  856. }
  857. if (mediaFile.getArtist() != null) {
  858. Artist artist = artistDao.getArtist(mediaFile.getArtist());
  859. if (artist != null) {
  860. attributes.add("artistId", artist.getId());
  861. }
  862. }
  863. switch (mediaFile.getMediaType()) {
  864. case MUSIC:
  865. attributes.add("type", "music");
  866. break;
  867. case PODCAST:
  868. attributes.add("type", "podcast");
  869. break;
  870. case AUDIOBOOK:
  871. attributes.add("type", "audiobook");
  872. break;
  873. default:
  874. break;
  875. }
  876. if (transcodingService.isTranscodingRequired(mediaFile, player)) {
  877. String transcodedSuffix = transcodingService.getSuffix(player, mediaFile, null);
  878. attributes.add("transcodedSuffix", transcodedSuffix);
  879. attributes.add("transcodedContentType", StringUtil.getMimeType(transcodedSuffix));
  880. }
  881. }
  882. return attributes;
  883. }
  884. private Integer findCoverArt(MediaFile mediaFile, MediaFile parent) {
  885. MediaFile dir = mediaFile.isDirectory() ? mediaFile : parent;
  886. if (dir != null && dir.getCoverArtPath() != null) {
  887. return dir.getId();
  888. }
  889. return null;
  890. }
  891. private String getRelativePath(MediaFile musicFile) {
  892. String filePath = musicFile.getPath();
  893. // Convert slashes.
  894. filePath = filePath.replace('\\', '/');
  895. String filePathLower = filePath.toLowerCase();
  896. List<MusicFolder> musicFolders = settingsService.getAllMusicFolders(false, true);
  897. for (MusicFolder musicFolder : musicFolders) {
  898. String folderPath = musicFolder.getPath().getPath();
  899. folderPath = folderPath.replace('\\', '/');
  900. String folderPathLower = folderPath.toLowerCase();
  901. if (filePathLower.startsWith(folderPathLower)) {
  902. String relativePath = filePath.substring(folderPath.length());
  903. return relativePath.startsWith("/") ? relativePath.substring(1) : relativePath;
  904. }
  905. }
  906. return null;
  907. }
  908. public ModelAndView download(HttpServletRequest request, HttpServletResponse response) throws Exception {
  909. request = wrapRequest(request);
  910. User user = securityService.getCurrentUser(request);
  911. if (!user.isDownloadRole()) {
  912. error(request, response, ErrorCode.NOT_AUTHORIZED, user.getUsername() + " is not authorized to download files.");
  913. return null;
  914. }
  915. long ifModifiedSince = request.getDateHeader("If-Modified-Since");
  916. long lastModified = downloadController.getLastModified(request);
  917. if (ifModifiedSince != -1 && lastModified != -1 && lastModified <= ifModifiedSince) {
  918. response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
  919. return null;
  920. }
  921. if (lastModified != -1) {
  922. response.setDateHeader("Last-Modified", lastModified);
  923. }
  924. return downloadController.handleRequest(request, response);
  925. }
  926. public ModelAndView stream(HttpServletRequest request, HttpServletResponse response) throws Exception {
  927. request = wrapRequest(request);
  928. User user = securityService.getCurrentUser(request);
  929. if (!user.isStreamRole

Large files files are truncated, but you can click here to view the full file