/// <summary>
 /// Called when [playback started].
 /// </summary>
 /// <param name="player">The player.</param>
 /// <param name="options">The options.</param>
 /// <param name="playerConfiguration">The player configuration.</param>
 private void OnPlaybackStarted(BaseMediaPlayer player, PlayOptions options, PlayerConfiguration playerConfiguration)
 {
     EventHelper.QueueEventIfNotNull(PlaybackStarted, this, new PlaybackEventArgs
     {
         Options = options,
         Player = player,
         PlayerConfiguration = playerConfiguration
     }, _logger);
 }
        /// <summary>
        /// Plays the specified player.
        /// </summary>
        /// <param name="player">The player.</param>
        /// <param name="options">The options.</param>
        /// <param name="playerConfiguration">The player configuration.</param>
        /// <returns>Task.</returns>
        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 App.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);
        }
        /// <summary>
        /// Plays the specified item.
        /// </summary>
        /// <param name="options">The options.</param>
        /// <param name="playerConfiguration">The player configuration.</param>
        /// <returns>Task.</returns>
        /// <exception cref="System.ArgumentNullException">items</exception>
        internal async Task Play(PlayOptions options, PlayerConfiguration playerConfiguration)
        {
            if (options == null)
            {
                throw new ArgumentNullException("options");
            }

            await PlaySemaphore.WaitAsync();

            PlayState = PlayState.Playing;
            
            lock (Playlist)
            {
                Playlist.Clear();
                Playlist.AddRange(options.Items);
            }

            CurrentPlayerConfiguration = playerConfiguration;
            CurrentPlayOptions = options;

            if (options.Items.Count > 1)
            {
                Logger.Info("Playing {0} items", options.Items.Count);
            }
            else
            {
                Logger.Info("Playing {0}", options.Items[0].Name);
            }

            try
            {
                PlayInternal(options.Items, options, playerConfiguration);
            }
            catch (Exception ex)
            {
                Logger.Info("Error beginning playback", ex);

                CurrentPlayerConfiguration = null;
                CurrentPlayOptions = null;
                Playlist.Clear();

                PlayState = PlayState.Idle;
                PlaySemaphore.Release();

                throw;
            }

            SendPlaybackStartCheckIn(options.Items[0]);

            ReloadProgressUpdateTimer();
        }
        /// <summary>
        /// Plays the specified items.
        /// </summary>
        /// <param name="options">The options.</param>
        /// <returns>Task.</returns>
        /// <exception cref="System.ArgumentException"></exception>
        /// <exception cref="System.InvalidOperationException"></exception>
        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();
            }
        }
 /// <summary>
 /// Plays the internal.
 /// </summary>
 /// <param name="items">The items.</param>
 /// <param name="options">The options.</param>
 /// <param name="playerConfiguration">The player configuration.</param>
 protected abstract void PlayInternal(List<BaseItemDto> items, PlayOptions options, PlayerConfiguration playerConfiguration);