PageRenderTime 54ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/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
  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()) {
  930. error(request, response, ErrorCode.NOT_AUTHORIZED, user.getUsername() + " is not authorized to play files.");
  931. return null;
  932. }
  933. streamController.handleRequest(request, response);
  934. return null;
  935. }
  936. public ModelAndView hls(HttpServletRequest request, HttpServletResponse response) throws Exception {
  937. request = wrapRequest(request);
  938. User user = securityService.getCurrentUser(request);
  939. if (!user.isStreamRole()) {
  940. error(request, response, ErrorCode.NOT_AUTHORIZED, user.getUsername() + " is not authorized to play files.");
  941. return null;
  942. }
  943. hlsController.handleRequest(request, response);
  944. return null;
  945. }
  946. public void scrobble(HttpServletRequest request, HttpServletResponse response) throws Exception {
  947. request = wrapRequest(request);
  948. XMLBuilder builder = createXMLBuilder(request, response, true);
  949. Player player = playerService.getPlayer(request, response);
  950. if (!settingsService.getUserSettings(player.getUsername()).isLastFmEnabled()) {
  951. error(request, response, ErrorCode.GENERIC, "Scrobbling is not enabled for " + player.getUsername() + ".");
  952. return;
  953. }
  954. boolean submission = ServletRequestUtils.getBooleanParameter(request, "submission", true);
  955. int[] ids = ServletRequestUtils.getRequiredIntParameters(request, "id");
  956. long[] times = ServletRequestUtils.getLongParameters(request, "time");
  957. if (times.length > 0 && times.length != ids.length) {
  958. error(request, response, ErrorCode.GENERIC, "Wrong number of timestamps: " + times.length);
  959. return;
  960. }
  961. for (int i = 0; i < ids.length; i++) {
  962. int id = ids[i];
  963. MediaFile file = mediaFileService.getMediaFile(id);
  964. if (file == null) {
  965. LOG.warn("File to scrobble not found: " + id);
  966. continue;
  967. }
  968. Date time = times.length == 0 ? null : new Date(times[i]);
  969. audioScrobblerService.register(file, player.getUsername(), submission, time);
  970. }
  971. builder.endAll();
  972. response.getWriter().print(builder);
  973. }
  974. public void star(HttpServletRequest request, HttpServletResponse response) throws Exception {
  975. starOrUnstar(request, response, true);
  976. }
  977. public void unstar(HttpServletRequest request, HttpServletResponse response) throws Exception {
  978. starOrUnstar(request, response, false);
  979. }
  980. private void starOrUnstar(HttpServletRequest request, HttpServletResponse response, boolean star) throws Exception {
  981. request = wrapRequest(request);
  982. XMLBuilder builder = createXMLBuilder(request, response, true);
  983. String username = securityService.getCurrentUser(request).getUsername();
  984. for (int id : ServletRequestUtils.getIntParameters(request, "id")) {
  985. MediaFile mediaFile = mediaFileDao.getMediaFile(id);
  986. if (mediaFile == null) {
  987. error(request, response, ErrorCode.NOT_FOUND, "Media file not found: " + id);
  988. return;
  989. }
  990. if (star) {
  991. mediaFileDao.starMediaFile(id, username);
  992. } else {
  993. mediaFileDao.unstarMediaFile(id, username);
  994. }
  995. }
  996. for (int albumId : ServletRequestUtils.getIntParameters(request, "albumId")) {
  997. Album album = albumDao.getAlbum(albumId);
  998. if (album == null) {
  999. error(request, response, ErrorCode.NOT_FOUND, "Album not found: " + albumId);
  1000. return;
  1001. }
  1002. if (star) {
  1003. albumDao.starAlbum(albumId, username);
  1004. } else {
  1005. albumDao.unstarAlbum(albumId, username);
  1006. }
  1007. }
  1008. for (int artistId : ServletRequestUtils.getIntParameters(request, "artistId")) {
  1009. Artist artist = artistDao.getArtist(artistId);
  1010. if (artist == null) {
  1011. error(request, response, ErrorCode.NOT_FOUND, "Artist not found: " + artistId);
  1012. return;
  1013. }
  1014. if (star) {
  1015. artistDao.starArtist(artistId, username);
  1016. } else {
  1017. artistDao.unstarArtist(artistId, username);
  1018. }
  1019. }
  1020. builder.endAll();
  1021. response.getWriter().print(builder);
  1022. }
  1023. public void getStarred(HttpServletRequest request, HttpServletResponse response) throws Exception {
  1024. request = wrapRequest(request);
  1025. Player player = playerService.getPlayer(request, response);
  1026. String username = securityService.getCurrentUsername(request);
  1027. XMLBuilder builder = createXMLBuilder(request, response, true);
  1028. builder.add("starred", false);
  1029. for (MediaFile artist : mediaFileDao.getStarredDirectories(0, Integer.MAX_VALUE, username)) {
  1030. builder.add("artist", true,
  1031. new Attribute("name", artist.getName()),
  1032. new Attribute("id", artist.getId()));
  1033. }
  1034. for (MediaFile album : mediaFileDao.getStarredAlbums(0, Integer.MAX_VALUE, username)) {
  1035. builder.add("album", createAttributesForMediaFile(player, album, username), true);
  1036. }
  1037. for (MediaFile song : mediaFileDao.getStarredFiles(0, Integer.MAX_VALUE, username)) {
  1038. builder.add("song", createAttributesForMediaFile(player, song, username), true);
  1039. }
  1040. builder.endAll();
  1041. response.getWriter().print(builder);
  1042. }
  1043. public void getStarred2(HttpServletRequest request, HttpServletResponse response) throws Exception {
  1044. request = wrapRequest(request);
  1045. Player player = playerService.getPlayer(request, response);
  1046. String username = securityService.getCurrentUsername(request);
  1047. XMLBuilder builder = createXMLBuilder(request, response, true);
  1048. builder.add("starred2", false);
  1049. for (Artist artist : artistDao.getStarredArtists(0, Integer.MAX_VALUE, username)) {
  1050. builder.add("artist", createAttributesForArtist(artist, username), true);
  1051. }
  1052. for (Album album : albumDao.getStarredAlbums(0, Integer.MAX_VALUE, username)) {
  1053. builder.add("album", createAttributesForAlbum(album, username), true);
  1054. }
  1055. for (MediaFile song : mediaFileDao.getStarredFiles(0, Integer.MAX_VALUE, username)) {
  1056. builder.add("song", createAttributesForMediaFile(player, song, username), true);
  1057. }
  1058. builder.endAll();
  1059. response.getWriter().print(builder);
  1060. }
  1061. public void getPodcasts(HttpServletRequest request, HttpServletResponse response) throws Exception {
  1062. request = wrapRequest(request);
  1063. Player player = playerService.getPlayer(request, response);
  1064. String username = securityService.getCurrentUsername(request);
  1065. XMLBuilder builder = createXMLBuilder(request, response, true);
  1066. builder.add("podcasts", false);
  1067. for (PodcastChannel channel : podcastService.getAllChannels()) {
  1068. AttributeSet channelAttrs = new AttributeSet();
  1069. channelAttrs.add("id", channel.getId());
  1070. channelAttrs.add("url", channel.getUrl());
  1071. channelAttrs.add("status", channel.getStatus().toString().toLowerCase());
  1072. channelAttrs.add("title", channel.getTitle());
  1073. channelAttrs.add("description", channel.getDescription());
  1074. channelAttrs.add("errorMessage", channel.getErrorMessage());
  1075. builder.add("channel", channelAttrs, false);
  1076. List<PodcastEpisode> episodes = podcastService.getEpisodes(channel.getId(), false);
  1077. for (PodcastEpisode episode : episodes) {
  1078. AttributeSet episodeAttrs = new AttributeSet();
  1079. String path = episode.getPath();
  1080. if (path != null) {
  1081. MediaFile mediaFile = mediaFileService.getMediaFile(path);
  1082. episodeAttrs.addAll(createAttributesForMediaFile(player, mediaFile, username));
  1083. episodeAttrs.add("streamId", mediaFile.getId());
  1084. }
  1085. episodeAttrs.add("id", episode.getId()); // Overwrites the previous "id" attribute.
  1086. episodeAttrs.add("status", episode.getStatus().toString().toLowerCase());
  1087. episodeAttrs.add("title", episode.getTitle());
  1088. episodeAttrs.add("description", episode.getDescription());
  1089. episodeAttrs.add("publishDate", episode.getPublishDate());
  1090. builder.add("episode", episodeAttrs, true);
  1091. }
  1092. builder.end(); // <channel>
  1093. }
  1094. builder.endAll();
  1095. response.getWriter().print(builder);
  1096. }
  1097. public void getShares(HttpServletRequest request, HttpServletResponse response) throws Exception {
  1098. request = wrapRequest(request);
  1099. Player player = playerService.getPlayer(request, response);
  1100. String username = securityService.getCurrentUsername(request);
  1101. User user = securityService.getCurrentUser(request);
  1102. XMLBuilder builder = createXMLBuilder(request, response, true);
  1103. builder.add("shares", false);
  1104. for (Share share : shareService.getSharesForUser(user)) {
  1105. builder.add("share", createAttributesForShare(share), false);
  1106. for (MediaFile mediaFile : shareService.getSharedFiles(share.getId())) {
  1107. AttributeSet attributes = createAttributesForMediaFile(player, mediaFile, username);
  1108. builder.add("entry", attributes, true);
  1109. }
  1110. builder.end();
  1111. }
  1112. builder.endAll();
  1113. response.getWriter().print(builder);
  1114. }
  1115. public void createShare(HttpServletRequest request, HttpServletResponse response) throws Exception {
  1116. request = wrapRequest(request);
  1117. Player player = playerService.getPlayer(request, response);
  1118. String username = securityService.getCurrentUsername(request);
  1119. User user = securityService.getCurrentUser(request);
  1120. if (!user.isShareRole()) {
  1121. error(request, response, ErrorCode.NOT_AUTHORIZED, user.getUsername() + " is not authorized to share media.");
  1122. return;
  1123. }
  1124. if (!settingsService.isUrlRedirectionEnabled()) {
  1125. error(request, response, ErrorCode.GENERIC, "Sharing is only supported for *.subsonic.org domain names.");
  1126. return;
  1127. }
  1128. XMLBuilder builder = createXMLBuilder(request, response, true);
  1129. List<MediaFile> files = new ArrayList<MediaFile>();
  1130. for (int id : ServletRequestUtils.getRequiredIntParameters(request, "id")) {
  1131. files.add(mediaFileService.getMediaFile(id));
  1132. }
  1133. // TODO: Update api.jsp
  1134. Share share = shareService.createShare(request, files);
  1135. share.setDescription(request.getParameter("description"));
  1136. long expires = ServletRequestUtils.getLongParameter(request, "expires", 0L);
  1137. if (expires != 0) {
  1138. share.setExpires(new Date(expires));
  1139. }
  1140. shareService.updateShare(share);
  1141. builder.add("shares", false);
  1142. builder.add("share", createAttributesForShare(share), false);
  1143. for (MediaFile mediaFile : shareService.getSharedFiles(share.getId())) {
  1144. AttributeSet attributes = createAttributesForMediaFile(player, mediaFile, username);
  1145. builder.add("entry", attributes, true);
  1146. }
  1147. builder.endAll();
  1148. response.getWriter().print(builder);
  1149. }
  1150. public void deleteShare(HttpServletRequest request, HttpServletResponse response) throws Exception {
  1151. request = wrapRequest(request);
  1152. User user = securityService.getCurrentUser(request);
  1153. int id = ServletRequestUtils.getRequiredIntParameter(request, "id");
  1154. Share share = shareService.getShareById(id);
  1155. if (share == null) {
  1156. error(request, response, ErrorCode.NOT_FOUND, "Shared media not found.");
  1157. return;
  1158. }
  1159. if (!user.isAdminRole() && !share.getUsername().equals(user.getUsername())) {
  1160. error(request, response, ErrorCode.NOT_AUTHORIZED, "Not authorized to delete shared media.");
  1161. return;
  1162. }
  1163. shareService.deleteShare(id);
  1164. XMLBuilder builder = createXMLBuilder(request, response, true).endAll();
  1165. response.getWriter().print(builder);
  1166. }
  1167. public void updateShare(HttpServletRequest request, HttpServletResponse response) throws Exception {
  1168. request = wrapRequest(request);
  1169. User user = securityService.getCurrentUser(request);
  1170. int id = ServletRequestUtils.getRequiredIntParameter(request, "id");
  1171. Share share = shareService.getShareById(id);
  1172. if (share == null) {
  1173. error(request, response, ErrorCode.NOT_FOUND, "Shared media not found.");
  1174. return;
  1175. }
  1176. if (!user.isAdminRole() && !share.getUsername().equals(user.getUsername())) {
  1177. error(request, response, ErrorCode.NOT_AUTHORIZED, "Not authorized to modify shared media.");
  1178. return;
  1179. }
  1180. share.setDescription(request.getParameter("description"));
  1181. String expiresString = request.getParameter("expires");
  1182. if (expiresString != null) {
  1183. long expires = Long.parseLong(expiresString);
  1184. share.setExpires(expires == 0L ? null : new Date(expires));
  1185. }
  1186. shareService.updateShare(share);
  1187. XMLBuilder builder = createXMLBuilder(request, response, true).endAll();
  1188. response.getWriter().print(builder);
  1189. }
  1190. private List<Attribute> createAttributesForShare(Share share) {
  1191. List<Attribute> attributes = new ArrayList<Attribute>();
  1192. attributes.add(new Attribute("id", share.getId()));
  1193. attributes.add(new Attribute("url", shareService.getShareUrl(share)));
  1194. attributes.add(new Attribute("username", share.getUsername()));
  1195. attributes.add(new Attribute("created", StringUtil.toISO8601(share.getCreated())));
  1196. attributes.add(new Attribute("visitCount", share.getVisitCount()));
  1197. attributes.add(new Attribute("description", share.getDescription()));
  1198. attributes.add(new Attribute("expires", StringUtil.toISO8601(share.getExpires())));
  1199. attributes.add(new Attribute("lastVisited", StringUtil.toISO8601(share.getLastVisited())));
  1200. return attributes;
  1201. }
  1202. public ModelAndView videoPlayer(HttpServletRequest request, HttpServletResponse response) throws Exception {
  1203. request = wrapRequest(request);
  1204. Map<String, Object> map = new HashMap<String, Object>();
  1205. int id = ServletRequestUtils.getRequiredIntParameter(request, "id");
  1206. MediaFile file = mediaFileService.getMediaFile(id);
  1207. int timeOffset = ServletRequestUtils.getIntParameter(request, "timeOffset", 0);
  1208. timeOffset = Math.max(0, timeOffset);
  1209. Integer duration = file.getDurationSeconds();
  1210. if (duration != null) {
  1211. map.put("skipOffsets", VideoPlayerController.createSkipOffsets(duration));
  1212. timeOffset = Math.min(duration, timeOffset);
  1213. duration -= timeOffset;
  1214. }
  1215. map.put("id", request.getParameter("id"));
  1216. map.put("u", request.getParameter("u"));
  1217. map.put("p", request.getParameter("p"));
  1218. map.put("c", request.getParameter("c"));
  1219. map.put("v", request.getParameter("v"));
  1220. map.put("video", file);
  1221. map.put("maxBitRate", ServletRequestUtils.getIntParameter(request, "maxBitRate", VideoPlayerController.DEFAULT_BIT_RATE));
  1222. map.put("duration", duration);
  1223. map.put("timeOffset", timeOffset);
  1224. map.put("bitRates", VideoPlayerController.BIT_RATES);
  1225. map.put("autoplay", ServletRequestUtils.getBooleanParameter(request, "autoplay", true));
  1226. ModelAndView result = new ModelAndView("rest/videoPlayer");
  1227. result.addObject("model", map);
  1228. return result;
  1229. }
  1230. public ModelAndView getCoverArt(HttpServletRequest request, HttpServletResponse response) throws Exception {
  1231. request = wrapRequest(request);
  1232. return coverArtController.handleRequest(request, response);
  1233. }
  1234. public ModelAndView getAvatar(HttpServletRequest request, HttpServletResponse response) throws Exception {
  1235. request = wrapRequest(request);
  1236. return avatarController.handleRequest(request, response);
  1237. }
  1238. public void changePassword(HttpServletRequest request, HttpServletResponse response) throws Exception {
  1239. request = wrapRequest(request);
  1240. String username = ServletRequestUtils.getRequiredStringParameter(request, "username");
  1241. String password = decrypt(ServletRequestUtils.getRequiredStringParameter(request, "password"));
  1242. User authUser = securityService.getCurrentUser(request);
  1243. if (!authUser.isAdminRole() && !username.equals(authUser.getUsername())) {
  1244. error(request, response, ErrorCode.NOT_AUTHORIZED, authUser.getUsername() + " is not authorized to change password for " + username);
  1245. return;
  1246. }
  1247. User user = securityService.getUserByName(username);
  1248. user.setPassword(password);
  1249. securityService.updateUser(user);
  1250. XMLBuilder builder = createXMLBuilder(request, response, true).endAll();
  1251. response.getWriter().print(builder);
  1252. }
  1253. public void getUser(HttpServletRequest request, HttpServletResponse response) throws Exception {
  1254. request = wrapRequest(request);
  1255. String username = ServletRequestUtils.getRequiredStringParameter(request, "username");
  1256. User currentUser = securityService.getCurrentUser(request);
  1257. if (!username.equals(currentUser.getUsername()) && !currentUser.isAdminRole()) {
  1258. error(request, response, ErrorCode.NOT_AUTHORIZED, currentUser.getUsername() + " is not authorized to get details for other users.");
  1259. return;
  1260. }
  1261. User requestedUser = securityService.getUserByName(username);
  1262. if (requestedUser == null) {
  1263. error(request, response, ErrorCode.NOT_FOUND, "No such user: " + username);
  1264. return;
  1265. }
  1266. UserSettings userSettings = settingsService.getUserSettings(username);
  1267. XMLBuilder builder = createXMLBuilder(request, response, true);
  1268. List<Attribute> attributes = createAttributesForUser(requestedUser, userSettings);
  1269. builder.add("user", attributes, true);
  1270. builder.endAll();
  1271. response.getWriter().print(builder);
  1272. }
  1273. public void getUsers(HttpServletRequest request, HttpServletResponse response) throws Exception {
  1274. request = wrapRequest(request);
  1275. User currentUser = securityService.getCurrentUser(request);
  1276. if (!currentUser.isAdminRole()) {
  1277. error(request, response, ErrorCode.NOT_AUTHORIZED, currentUser.getUsername() + " is not authorized to get details for other users.");
  1278. return;
  1279. }
  1280. XMLBuilder builder = createXMLBuilder(request, response, true);
  1281. builder.add("users", false);
  1282. for (User user : securityService.getAllUsers()) {
  1283. UserSettings userSettings = settingsService.getUserSettings(user.getUsername());
  1284. List<Attribute> attributes = createAttributesForUser(user, userSettings);
  1285. builder.add("user", attributes, true);
  1286. }
  1287. builder.endAll();
  1288. response.getWriter().print(builder);
  1289. }
  1290. private List<Attribute> createAttributesForUser(User user, UserSettings userSettings) {
  1291. return Arrays.asList(
  1292. new Attribute("username", user.getUsername()),
  1293. new Attribute("email", user.getEmail()),
  1294. new Attribute("scrobblingEnabled", userSettings.isLastFmEnabled()),
  1295. new Attribute("adminRole", user.isAdminRole()),
  1296. new Attribute("settingsRole", user.isSettingsRole()),
  1297. new Attribute("downloadRole", user.isDownloadRole()),
  1298. new Attribute("uploadRole", user.isUploadRole()),
  1299. new Attribute("playlistRole", true), // Since 1.8.0
  1300. new Attribute("coverArtRole", user.isCoverArtRole()),
  1301. new Attribute("commentRole", user.isCommentRole()),
  1302. new Attribute("podcastRole", user.isPodcastRole()),
  1303. new Attribute("streamRole", user.isStreamRole()),
  1304. new Attribute("jukeboxRole", user.isJukeboxRole()),
  1305. new Attribute("shareRole", user.isShareRole())
  1306. );
  1307. }
  1308. public void createUser(HttpServletRequest request, HttpServletResponse response) throws Exception {
  1309. request = wrapRequest(request);
  1310. User user = securityService.getCurrentUser(request);
  1311. if (!user.isAdminRole()) {
  1312. error(request, response, ErrorCode.NOT_AUTHORIZED, user.getUsername() + " is not authorized to create new users.");
  1313. return;
  1314. }
  1315. UserSettingsCommand command = new UserSettingsCommand();
  1316. command.setUsername(ServletRequestUtils.getRequiredStringParameter(request, "username"));
  1317. command.setPassword(decrypt(ServletRequestUtils.getRequiredStringParameter(request, "password")));
  1318. command.setEmail(ServletRequestUtils.getRequiredStringParameter(request, "email"));
  1319. command.setLdapAuthenticated(ServletRequestUtils.getBooleanParameter(request, "ldapAuthenticated", false));
  1320. command.setAdminRole(ServletRequestUtils.getBooleanParameter(request, "adminRole", false));
  1321. command.setCommentRole(ServletRequestUtils.getBooleanParameter(request, "commentRole", false));
  1322. command.setCoverArtRole(ServletRequestUtils.getBooleanParameter(request, "coverArtRole", false));
  1323. command.setDownloadRole(ServletRequestUtils.getBooleanParameter(request, "downloadRole", false));
  1324. command.setStreamRole(ServletRequestUtils.getBooleanParameter(request, "streamRole", true));
  1325. command.setUploadRole(ServletRequestUtils.getBooleanParameter(request, "uploadRole", false));
  1326. command.setJukeboxRole(ServletRequestUtils.getBooleanParameter(request, "jukeboxRole", false));
  1327. command.setPodcastRole(ServletRequestUtils.getBooleanParameter(request, "podcastRole", false));
  1328. command.setSettingsRole(ServletRequestUtils.getBooleanParameter(request, "settingsRole", true));
  1329. command.setTranscodeSchemeName(ServletRequestUtils.getStringParameter(request, "transcodeScheme", TranscodeScheme.OFF.name()));
  1330. command.setShareRole(ServletRequestUtils.getBooleanParameter(request, "shareRole", false));
  1331. userSettingsController.createUser(command);
  1332. XMLBuilder builder = createXMLBuilder(request, response, true).endAll();
  1333. response.getWriter().print(builder);
  1334. }
  1335. public void deleteUser(HttpServletRequest request, HttpServletResponse response) throws Exception {
  1336. request = wrapRequest(request);
  1337. User user = securityService.getCurrentUser(request);
  1338. if (!user.isAdminRole()) {
  1339. error(request, response, ErrorCode.NOT_AUTHORIZED, user.getUsername() + " is not authorized to delete users.");
  1340. return;
  1341. }
  1342. String username = ServletRequestUtils.getRequiredStringParameter(request, "username");
  1343. securityService.deleteUser(username);
  1344. XMLBuilder builder = createXMLBuilder(request, response, true).endAll();
  1345. response.getWriter().print(builder);
  1346. }
  1347. public void getChatMessages(HttpServletRequest request, HttpServletResponse response) throws Exception {
  1348. request = wrapRequest(request);
  1349. XMLBuilder builder = createXMLBuilder(request, response, true);
  1350. long since = ServletRequestUtils.getLongParameter(request, "since", 0L);
  1351. builder.add("chatMessages", false);
  1352. for (ChatService.Message message : chatService.getMessages(0L).getMessages()) {
  1353. long time = message.getDate().getTime();
  1354. if (time > since) {
  1355. builder.add("chatMessage", true, new Attribute("username", message.getUsername()),
  1356. new Attribute("time", time), new Attribute("message", message.getContent()));
  1357. }
  1358. }
  1359. builder.endAll();
  1360. response.getWriter().print(builder);
  1361. }
  1362. public void addChatMessage(HttpServletRequest request, HttpServletResponse response) throws Exception {
  1363. request = wrapRequest(request);
  1364. chatService.doAddMessage(ServletRequestUtils.getRequiredStringParameter(request, "message"), request);
  1365. XMLBuilder builder = createXMLBuilder(request, response, true).endAll();
  1366. response.getWriter().print(builder);
  1367. }
  1368. public void getLyrics(HttpServletRequest request, HttpServletResponse response) throws Exception {
  1369. request = wrapRequest(request);
  1370. String artist = request.getParameter("artist");
  1371. String title = request.getParameter("title");
  1372. LyricsInfo lyrics = lyricsService.getLyrics(artist, title);
  1373. XMLBuilder builder = createXMLBuilder(request, response, true);
  1374. AttributeSet attributes = new AttributeSet();
  1375. attributes.add("artist", lyrics.getArtist());
  1376. attributes.add("title", lyrics.getTitle());
  1377. builder.add("lyrics", attributes, lyrics.getLyrics(), true);
  1378. builder.endAll();
  1379. response.getWriter().print(builder);
  1380. }
  1381. public void setRating(HttpServletRequest request, HttpServletResponse response) throws Exception {
  1382. request = wrapRequest(request);
  1383. Integer rating = ServletRequestUtils.getRequiredIntParameter(request, "rating");
  1384. if (rating == 0) {
  1385. rating = null;
  1386. }
  1387. int id = ServletRequestUtils.getRequiredIntParameter(request, "id");
  1388. MediaFile mediaFile = mediaFileService.getMediaFile(id);
  1389. if (mediaFile == null) {
  1390. error(request, response, ErrorCode.NOT_FOUND, "File not found: " + id);
  1391. return;
  1392. }
  1393. String username = securityService.getCurrentUsername(request);
  1394. ratingService.setRatingForUser(username, mediaFile, rating);
  1395. XMLBuilder builder = createXMLBuilder(request, response, true).endAll();
  1396. response.getWriter().print(builder);
  1397. }
  1398. private HttpServletRequest wrapRequest(HttpServletRequest request) {
  1399. return wrapRequest(request, false);
  1400. }
  1401. private HttpServletRequest wrapRequest(final HttpServletRequest request, boolean jukebox) {
  1402. final String playerId = createPlayerIfNecessary(request, jukebox);
  1403. return new HttpServletRequestWrapper(request) {
  1404. @Override
  1405. public String getParameter(String name) {
  1406. // Returns the correct player to be used in PlayerService.getPlayer()
  1407. if ("player".equals(name)) {
  1408. return playerId;
  1409. }
  1410. // Support old style ID parameters.
  1411. if ("id".equals(name)) {
  1412. return mapId(request.getParameter("id"));
  1413. }
  1414. return super.getParameter(name);
  1415. }
  1416. };
  1417. }
  1418. private String mapId(String id) {
  1419. if (id == null || id.startsWith(CoverArtController.ALBUM_COVERART_PREFIX) ||
  1420. id.startsWith(CoverArtController.ARTIST_COVERART_PREFIX) || StringUtils.isNumeric(id)) {
  1421. return id;
  1422. }
  1423. try {
  1424. String path = StringUtil.utf8HexDecode(id);
  1425. MediaFile mediaFile = mediaFileService.getMediaFile(path);
  1426. return String.valueOf(mediaFile.getId());
  1427. } catch (Exception x) {
  1428. return id;
  1429. }
  1430. }
  1431. public static void error(HttpServletRequest request, HttpServletResponse response, ErrorCode code, String message) throws IOException {
  1432. XMLBuilder builder = createXMLBuilder(request, response, false);
  1433. builder.add("error", true,
  1434. new XMLBuilder.Attribute("code", code.getCode()),
  1435. new XMLBuilder.Attribute("message", message));
  1436. builder.end();
  1437. response.getWriter().print(builder);
  1438. }
  1439. private static XMLBuilder createXMLBuilder(HttpServletRequest request, HttpServletResponse response, boolean ok) throws IOException {
  1440. String format = ServletRequestUtils.getStringParameter(request, "f", "xml");
  1441. boolean json = "json".equals(format);
  1442. boolean jsonp = "jsonp".equals(format);
  1443. XMLBuilder builder;
  1444. response.setCharacterEncoding(StringUtil.ENCODING_UTF8);
  1445. if (json) {
  1446. builder = XMLBuilder.createJSONBuilder();
  1447. response.setContentType("application/json");
  1448. } else if (jsonp) {
  1449. builder = XMLBuilder.createJSONPBuilder(request.getParameter("callback"));
  1450. response.setContentType("text/javascript");
  1451. } else {
  1452. builder = XMLBuilder.createXMLBuilder();
  1453. response.setContentType("text/xml");
  1454. }
  1455. builder.preamble(StringUtil.ENCODING_UTF8);
  1456. builder.add("subsonic-response", false,
  1457. new Attribute("xmlns", "http://subsonic.org/restapi"),
  1458. new Attribute("status", ok ? "ok" : "failed"),
  1459. new Attribute("version", StringUtil.getRESTProtocolVersion()));
  1460. return builder;
  1461. }
  1462. private String createPlayerIfNecessary(HttpServletRequest request, boolean jukebox) {
  1463. String username = request.getRemoteUser();
  1464. String clientId = request.getParameter("c");
  1465. if (jukebox) {
  1466. clientId += "-jukebox";
  1467. }
  1468. List<Player> players = playerService.getPlayersForUserAndClientId(username, clientId);
  1469. // If not found, create it.
  1470. if (players.isEmpty()) {
  1471. Player player = new Player();
  1472. player.setIpAddress(request.getRemoteAddr());
  1473. player.setUsername(username);
  1474. player.setClientId(clientId);
  1475. player.setName(clientId);
  1476. player.setTechnology(jukebox ? PlayerTechnology.JUKEBOX : PlayerTechnology.EXTERNAL_WITH_PLAYLIST);
  1477. playerService.createPlayer(player);
  1478. players = playerService.getPlayersForUserAndClientId(username, clientId);
  1479. }
  1480. // Return the player ID.
  1481. return !players.isEmpty() ? players.get(0).getId() : null;
  1482. }
  1483. public void setSettingsService(SettingsService settingsService) {
  1484. this.settingsService = settingsService;
  1485. }
  1486. public void setSecurityService(SecurityService securityService) {
  1487. this.securityService = securityService;
  1488. }
  1489. public void setPlayerService(PlayerService playerService) {
  1490. this.playerService = playerService;
  1491. }
  1492. public void setTranscodingService(TranscodingService transcodingService) {
  1493. this.transcodingService = transcodingService;
  1494. }
  1495. public void setDownloadController(DownloadController downloadController) {
  1496. this.downloadController = downloadController;
  1497. }
  1498. public void setCoverArtController(CoverArtController coverArtController) {
  1499. this.coverArtController = coverArtController;
  1500. }
  1501. public void setUserSettingsController(UserSettingsController userSettingsController) {
  1502. this.userSettingsController = userSettingsController;
  1503. }
  1504. public void setLeftController(LeftController leftController) {
  1505. this.leftController = leftController;
  1506. }
  1507. public void setStatusService(StatusService statusService) {
  1508. this.statusService = statusService;
  1509. }
  1510. public void setPlaylistService(PlaylistService playlistService) {
  1511. this.playlistService = playlistService;
  1512. }
  1513. public void setStreamController(StreamController streamController) {
  1514. this.streamController = streamController;
  1515. }
  1516. public void setHlsController(HLSController hlsController) {
  1517. this.hlsController = hlsController;
  1518. }
  1519. public void setChatService(ChatService chatService) {
  1520. this.chatService = chatService;
  1521. }
  1522. public void setHomeController(HomeController homeController) {
  1523. this.homeController = homeController;
  1524. }
  1525. public void setLyricsService(LyricsService lyricsService) {
  1526. this.lyricsService = lyricsService;
  1527. }
  1528. public void setPlayQueueService(PlayQueueService playQueueService) {
  1529. this.playQueueService = playQueueService;
  1530. }
  1531. public void setJukeboxService(JukeboxService jukeboxService) {
  1532. this.jukeboxService = jukeboxService;
  1533. }
  1534. public void setAudioScrobblerService(AudioScrobblerService audioScrobblerService) {
  1535. this.audioScrobblerService = audioScrobblerService;
  1536. }
  1537. public void setPodcastService(PodcastService podcastService) {
  1538. this.podcastService = podcastService;
  1539. }
  1540. public void setRatingService(RatingService ratingService) {
  1541. this.ratingService = ratingService;
  1542. }
  1543. public void setSearchService(SearchService searchService) {
  1544. this.searchService = searchService;
  1545. }
  1546. public void setShareService(ShareService shareService) {
  1547. this.shareService = shareService;
  1548. }
  1549. public void setMediaFileService(MediaFileService mediaFileService) {
  1550. this.mediaFileService = mediaFileService;
  1551. }
  1552. public void setAvatarController(AvatarController avatarController) {
  1553. this.avatarController = avatarController;
  1554. }
  1555. public void setArtistDao(ArtistDao artistDao) {
  1556. this.artistDao = artistDao;
  1557. }
  1558. public void setAlbumDao(AlbumDao albumDao) {
  1559. this.albumDao = albumDao;
  1560. }
  1561. public void setMediaFileDao(MediaFileDao mediaFileDao) {
  1562. this.mediaFileDao = mediaFileDao;
  1563. }
  1564. public void setMusicIndexService(MusicIndexService musicIndexService) {
  1565. this.musicIndexService = musicIndexService;
  1566. }
  1567. public static enum ErrorCode {
  1568. GENERIC(0, "A generic error."),
  1569. MISSING_PARAMETER(10, "Required parameter is missing."),
  1570. PROTOCOL_MISMATCH_CLIENT_TOO_OLD(20, "Incompatible Subsonic REST protocol version. Client must upgrade."),
  1571. PROTOCOL_MISMATCH_SERVER_TOO_OLD(30, "Incompatible Subsonic REST protocol version. Server must upgrade."),
  1572. NOT_AUTHENTICATED(40, "Wrong username or password."),
  1573. NOT_AUTHORIZED(50, "User is not authorized for the given operation."),
  1574. NOT_LICENSED(60, "The trial period for the Subsonic server is over. Please donate to get a license key. Visit subsonic.org for details."),
  1575. NOT_FOUND(70, "Requested data was not found.");
  1576. private final int code;
  1577. private final String message;
  1578. ErrorCode(int code, String message) {
  1579. this.code = code;
  1580. this.message = message;
  1581. }
  1582. public int getCode() {
  1583. return code;
  1584. }
  1585. public String getMessage() {
  1586. return message;
  1587. }
  1588. }
  1589. }