PageRenderTime 51ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

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

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

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