/// <summary>
 /// Gets the process start info.
 /// </summary>
 /// <param name="items">The items.</param>
 /// <param name="options">The options.</param>
 /// <param name="playerConfiguration">The player configuration.</param>
 /// <returns>ProcessStartInfo.</returns>
 protected virtual ProcessStartInfo GetProcessStartInfo(List<BaseItemDto> items, PlayOptions options, PlayerConfiguration playerConfiguration)
 {
     return new ProcessStartInfo
     {
         FileName = playerConfiguration.Command,
         Arguments = GetCommandArguments(items, options, playerConfiguration)
     };
 }
 /// <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 internal.
        /// </summary>
        /// <param name="items">The items.</param>
        /// <param name="options">The options.</param>
        /// <param name="playerConfiguration">The player configuration.</param>
        protected override void PlayInternal(List<BaseItemDto> items, PlayOptions options, PlayerConfiguration playerConfiguration)
        {
            App.Instance.ApplicationWindow.Dispatcher.Invoke(() =>
            {
                App.Instance.ApplicationWindow.BackdropContainer.Visibility = Visibility.Collapsed;
                App.Instance.ApplicationWindow.WindowBackgroundContent.SetResourceReference(FrameworkElement.StyleProperty, "WindowBackgroundContentDuringPlayback");
            });

            App.Instance.NavigateToInternalPlayerPage();
        }
        /// <summary>
        /// Determines whether [is configured to play] [the specified configuration].
        /// </summary>
        /// <param name="configuration">The configuration.</param>
        /// <param name="items">The items.</param>
        /// <returns><c>true</c> if [is configured to play] [the specified configuration]; otherwise, <c>false</c>.</returns>
        private bool IsConfiguredToPlay(PlayerConfiguration configuration, List<BaseItemDto> 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;
        }
        /// <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>
        /// Gets the command arguments.
        /// </summary>
        /// <param name="items">The items.</param>
        /// <param name="options">The options.</param>
        /// <param name="playerConfiguration">The player configuration.</param>
        /// <returns>System.String.</returns>
        protected virtual string GetCommandArguments(List<BaseItemDto> items, PlayOptions options, PlayerConfiguration playerConfiguration)
        {
            var args = playerConfiguration.Args;

            if (string.IsNullOrEmpty(args))
            {
                return string.Empty;
            }

            return GetCommandArguments(items, args);
        }
        /// <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 override void PlayInternal(List<BaseItemDto> items, PlayOptions options, PlayerConfiguration playerConfiguration)
        {
            CurrentProcess = new Process
            {
                EnableRaisingEvents = true,
                StartInfo = GetProcessStartInfo(items, options, playerConfiguration)
            };

            Logger.Info("{0} {1}", CurrentProcess.StartInfo.FileName, CurrentProcess.StartInfo.Arguments);

            CurrentProcess.Start();

            OnExternalPlayerLaunched();

            if (!CanCloseAutomatically)
            {
                KeyboardListener.KeyDown += KeyboardListener_KeyDown;
            }

            CurrentProcess.Exited += CurrentProcess_Exited;
        }
        /// <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 override void PlayInternal(List<BaseItemDto> items, PlayOptions options, PlayerConfiguration playerConfiguration)
        {
            EnsureMediaPlayerCreated();

            _currentPlaylistIndex = 0;

            MediaList = MediaPlayerFactory.CreateMediaList<IMediaList>(items.Select(GetPlayablePath));
            VideoPlayer = MediaPlayerFactory.CreateMediaListPlayer<IMediaListPlayer>(MediaList);

            VideoPlayer.InnerPlayer.WindowHandle = WindowsFormsPanel.Handle;

            VideoPlayer.InnerPlayer.Events.PlayerStopped += Events_PlayerStopped;
            VideoPlayer.Play();

            var position = options.StartPositionTicks;

            if (position > 0)
            {
                VideoPlayer.Time = Convert.ToInt64(TimeSpan.FromTicks(position).TotalMilliseconds);
            }

            VideoPlayer.MediaListPlayerEvents.MediaListPlayerNextItemSet += MediaListPlayerEvents_MediaListPlayerNextItemSet;

            base.PlayInternal(items, 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 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);