content: /*
   This file is part of Airsonic.
  
   Airsonic is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
  
   Airsonic is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
  
   You should have received a copy of the GNU General Public License
   along with Airsonic.  If not, see <http://www.gnu.org/licenses/>.
  
   Copyright 2016 (C) Airsonic Authors
   Based upon Subsonic, Copyright 2009 (C) Sindre Mehus
   */
  package org.airsonic.player.ajax;
  
  import org.airsonic.player.domain.*;
  import org.airsonic.player.service.*;
  import org.airsonic.player.util.StringUtil;
  import org.apache.commons.lang.StringEscapeUtils;
  import org.apache.commons.lang.StringUtils;
  import org.directwebremoting.WebContext;
  import org.directwebremoting.WebContextFactory;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.stereotype.Service;
  
  import javax.servlet.http.HttpServletRequest;
  
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.List;
  
  /**
   * Provides AJAX-enabled services for retrieving the currently playing file and directory.
   * This class is used by the DWR framework (http://getahead.ltd.uk/dwr/).
   *
   * @author Sindre Mehus
   */
  @Service("ajaxNowPlayingService")
  public class NowPlayingService {
  
      private static final Logger LOG = LoggerFactory.getLogger(NowPlayingService.class);
  
      @Autowired
      private PlayerService playerService;
      @Autowired
      private StatusService statusService;
      @Autowired
      private SettingsService settingsService;
      @Autowired
      private MediaScannerService mediaScannerService;
  
      /**
       * Returns details about what the current player is playing.
       *
       * @return Details about what the current player is playing, or <code>null</code> if not playing anything.
       */
      public NowPlayingInfo getNowPlayingForCurrentPlayer() throws Exception {
          WebContext webContext = WebContextFactory.get();
          Player player = playerService.getPlayer(webContext.getHttpServletRequest(), webContext.getHttpServletResponse());
  
          for (NowPlayingInfo info : getNowPlaying()) {
              if (player.getId().equals(info.getPlayerId())) {
                  return info;
              }
          }
          return null;
      }
  
      /**
       * Returns details about what all users are currently playing.
       *
       * @return Details about what all users are currently playing.
       */
      public List<NowPlayingInfo> getNowPlaying() {
          try {
              return convert(statusService.getPlayStatuses());
          } catch (Throwable x) {
              LOG.error("Unexpected error in getNowPlaying: " + x, x);
              return Collections.emptyList();
          }
      }
  
      /**
       * Returns media folder scanning status.
       */
      public ScanInfo getScanningStatus() {
          return new ScanInfo(mediaScannerService.isScanning(), mediaScannerService.getScanCount());
      }
  
      private List<NowPlayingInfo> convert(List<PlayStatus> playStatuses) {
          HttpServletRequest request = WebContextFactory.get().getHttpServletRequest();
          String url = NetworkService.getBaseUrl(request);
          List<NowPlayingInfo> result = new ArrayList<NowPlayingInfo>();
          for (PlayStatus status : playStatuses) {
  
              Player player = status.getPlayer();
              MediaFile mediaFile = status.getMediaFile();
              String username = player.getUsername();
              if (username == null) {
                  continue;
              }
              UserSettings userSettings = settingsService.getUserSettings(username);
              if (!userSettings.isNowPlayingAllowed()) {
                  continue;
              }
  
              String artist = mediaFile.getArtist();
              String title = mediaFile.getTitle();
              String streamUrl = url + "stream?player=" + player.getId() + "&id=" + mediaFile.getId();
              String albumUrl = url + "main.view?id=" + mediaFile.getId();
              String lyricsUrl = null;
              if (!mediaFile.isVideo()) {
                  lyricsUrl = url + "lyrics.view?artistUtf8Hex=" + StringUtil.utf8HexEncode(artist) +
                                                          "&songUtf8Hex=" + StringUtil.utf8HexEncode(title);
              }
              String coverArtUrl = url + "coverArt.view?size=60&id=" + mediaFile.getId();
  
              String avatarUrl = null;
              if (userSettings.getAvatarScheme() == AvatarScheme.SYSTEM) {
                  avatarUrl = url + "avatar.view?id=" + userSettings.getSystemAvatarId();
              } else if (userSettings.getAvatarScheme() == AvatarScheme.CUSTOM && settingsService.getCustomAvatar(username) != null) {
                  avatarUrl = url + "avatar.view?usernameUtf8Hex=" + StringUtil.utf8HexEncode(username);
              }
  
              String tooltip = StringEscapeUtils.escapeHtml(artist) + " &ndash; " + StringEscapeUtils.escapeHtml(title);
  
              if (StringUtils.isNotBlank(player.getName())) {
                  username += "@" + player.getName();
              }
              artist = StringEscapeUtils.escapeHtml(StringUtils.abbreviate(artist, 25));
              title = StringEscapeUtils.escapeHtml(StringUtils.abbreviate(title, 25));
              username = StringEscapeUtils.escapeHtml(StringUtils.abbreviate(username, 25));
  
              long minutesAgo = status.getMinutesAgo();
  
              if (minutesAgo < 60) {
                  result.add(new NowPlayingInfo(player.getId(),username, artist, title, tooltip, streamUrl, albumUrl, lyricsUrl,
                                                coverArtUrl, avatarUrl, (int) minutesAgo));
              }
          }
          return result;
      }
  
      public void setPlayerService(PlayerService playerService) {
          this.playerService = playerService;
      }
  
      public void setStatusService(StatusService statusService) {
          this.statusService = statusService;
      }
  
      public void setSettingsService(SettingsService settingsService) {
          this.settingsService = settingsService;
      }
  
      public void setMediaScannerService(MediaScannerService mediaScannerService) {
          this.mediaScannerService = mediaScannerService;
      }
  }
  