using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Kernel;
using MediaBrowser.Model.DTO;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Net;
using MediaBrowser.UI.Configuration;
using MediaBrowser.UI.Controller;
using MediaBrowser.UI.Playback.InternalPlayer;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace MediaBrowser.UI.Playback
{
///
/// Class PlaybackManager
///
public class PlaybackManager : BaseManager
{
///
/// Initializes a new instance of the class.
///
/// The kernel.
public PlaybackManager(UIKernel kernel)
: base(kernel)
{
}
#region PlaybackStarted Event
///
/// Occurs when [playback started].
///
public event EventHandler PlaybackStarted;
///
/// Called when [playback started].
///
/// The player.
/// The options.
/// The player configuration.
private void OnPlaybackStarted(BaseMediaPlayer player, PlayOptions options, PlayerConfiguration playerConfiguration)
{
EventHelper.QueueEventIfNotNull(PlaybackStarted, this, new PlaybackEventArgs
{
Options = options,
Player = player,
PlayerConfiguration = playerConfiguration
});
}
#endregion
#region PlaybackCompleted Event
///
/// Occurs when [playback completed].
///
public event EventHandler PlaybackCompleted;
///
/// Called when [playback completed].
///
/// The player.
/// The items.
internal void OnPlaybackCompleted(BaseMediaPlayer player, List items)
{
EventHelper.QueueEventIfNotNull(PlaybackCompleted, this, new PlaybackStopEventArgs
{
Items = items,
Player = player
});
}
#endregion
///
/// Gets the active players.
///
/// The active players.
public IEnumerable ActivePlayers
{
get
{
return Kernel.MediaPlayers.Where(m => m.PlayState != PlayState.Idle);
}
}
///
/// Gets the active internal players.
///
/// The active internal players.
public IEnumerable ActiveInternalPlayers
{
get { return ActivePlayers.Where(p => p is BaseInternalMediaPlayer); }
}
///
/// Plays the specified items.
///
/// The options.
/// Task.
///
///
public async Task Play(PlayOptions options)
{
if (options == null)
{
throw new ArgumentNullException("options");
}
if (options.Items == null || options.Items.Count == 0)
{
throw new ArgumentNullException("options");
}
var player = GetPlayer(options.Items);
if (player != null)
{
await StopAllPlayback();
await Play(player.Item1, options, player.Item2);
}
else
{
throw new InvalidOperationException();
}
}
///
/// Plays the specified player.
///
/// The player.
/// The options.
/// The player configuration.
/// Task.
private async Task Play(BaseMediaPlayer player, PlayOptions options, PlayerConfiguration playerConfiguration)
{
if (options.Shuffle)
{
options.Items = options.Items.Shuffle().ToList();
}
var firstItem = options.Items[0];
if (options.StartPositionTicks == 0 && player.SupportsMultiFilePlayback && firstItem.IsVideo && firstItem.LocationType == LocationType.FileSystem)
{
try
{
var intros = await UIKernel.Instance.ApiClient.GetIntrosAsync(firstItem.Id, App.Instance.CurrentUser.Id);
options.Items.InsertRange(0, intros.Select(GetPlayableItem));
}
catch (HttpException ex)
{
Logger.ErrorException("Error retrieving intros", ex);
}
}
await player.Play(options, playerConfiguration);
OnPlaybackStarted(player, options, playerConfiguration);
}
///
/// Gets the playable item.
///
/// The path.
/// DtoBaseItem.
public DtoBaseItem GetPlayableItem(string path)
{
return new DtoBaseItem
{
Path = path,
Name = Path.GetFileName(path),
Type = "Video",
VideoType = VideoType.VideoFile,
IsFolder = false
};
}
///
/// Gets the playable item.
///
/// The URI.
/// The name.
/// DtoBaseItem.
public DtoBaseItem GetPlayableItem(Uri uri, string name)
{
return new DtoBaseItem
{
Path = uri.ToString(),
Name = name,
Type = "Video",
VideoType = VideoType.VideoFile,
IsFolder = false,
LocationType = LocationType.Remote
};
}
///
/// Stops all playback.
///
/// Task.
public async Task StopAllPlayback()
{
var tasks = Kernel.MediaPlayers.Where(p => p.PlayState == PlayState.Playing || p.PlayState == PlayState.Paused).Select(p => p.Stop());
await Task.WhenAll(tasks);
}
///
/// Gets the player.
///
/// The items.
/// BaseMediaPlayer.
private Tuple GetPlayer(List items)
{
var player = GetConfiguredPlayer(items);
if (player != null)
{
return player;
}
// If there's no explicit configuration just find the first matching player
var mediaPlayer = Kernel.MediaPlayers.OfType().FirstOrDefault(p => items.All(p.CanPlay));
if (mediaPlayer != null)
{
return new Tuple(mediaPlayer, null);
}
return null;
}
///
/// Gets the configured player.
///
/// The items.
/// BaseMediaPlayer.
private Tuple GetConfiguredPlayer(List items)
{
if (UIKernel.Instance.Configuration.MediaPlayers == null)
{
return null;
}
return UIKernel.Instance.Configuration.MediaPlayers.Where(p => IsConfiguredToPlay(p, items))
.Select(p => new Tuple(UIKernel.Instance.MediaPlayers.FirstOrDefault(m => m.Name.Equals(p.PlayerName, StringComparison.OrdinalIgnoreCase)), p))
.FirstOrDefault(p => p.Item1 != null);
}
///
/// Determines whether [is configured to play] [the specified configuration].
///
/// The configuration.
/// The items.
/// true if [is configured to play] [the specified configuration]; otherwise, false.
private bool IsConfiguredToPlay(PlayerConfiguration configuration, List items)
{
if (configuration.ItemTypes != null && configuration.ItemTypes.Length > 0)
{
if (items.Any(i => !configuration.ItemTypes.Contains(i.Type, StringComparer.OrdinalIgnoreCase)))
{
return false;
}
}
if (configuration.FileExtensions != null && configuration.FileExtensions.Length > 0)
{
if (items.Any(i => !configuration.FileExtensions.Select(ext => ext.TrimStart('.')).Contains((Path.GetExtension(i.Path) ?? string.Empty).TrimStart('.'), StringComparer.OrdinalIgnoreCase)))
{
return false;
}
}
if (configuration.VideoTypes != null && configuration.VideoTypes.Length > 0)
{
if (items.Any(i => i.VideoType.HasValue && !configuration.VideoTypes.Contains(i.VideoType.Value)))
{
return false;
}
}
if (configuration.VideoFormats != null && configuration.VideoFormats.Length > 0)
{
if (items.Any(i => i.VideoFormat.HasValue && !configuration.VideoFormats.Contains(i.VideoFormat.Value)))
{
return false;
}
}
return true;
}
}
}