Ver Fonte

Merge pull request #2584 from MediaBrowser/dev

Dev
Luke há 8 anos atrás
pai
commit
f0f3ca8c18

+ 1 - 2
Emby.Dlna/PlayTo/PlayToController.cs

@@ -318,8 +318,7 @@ namespace Emby.Dlna.PlayTo
 
                 CanSeek = info.MediaSource == null ? _device.Duration.HasValue : info.MediaSource.RunTimeTicks.HasValue,
 
-                PlayMethod = info.IsDirectStream ? PlayMethod.DirectStream : PlayMethod.Transcode,
-                QueueableMediaTypes = new List<string> { mediaInfo.MediaType }
+                PlayMethod = info.IsDirectStream ? PlayMethod.DirectStream : PlayMethod.Transcode
             };
         }
 

+ 1 - 97
Emby.Server.Implementations/Library/MediaSourceManager.cs

@@ -9,13 +9,10 @@ using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.MediaInfo;
 using MediaBrowser.Model.Serialization;
 using System;
-using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.IO;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Threading;
@@ -365,12 +362,10 @@ namespace Emby.Server.Implementations.Library
         private readonly Dictionary<string, LiveStreamInfo> _openStreams = new Dictionary<string, LiveStreamInfo>(StringComparer.OrdinalIgnoreCase);
         private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1);
 
-        public async Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, bool enableAutoClose, CancellationToken cancellationToken)
+        public async Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, CancellationToken cancellationToken)
         {
             await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
 
-            enableAutoClose = false;
-
             try
             {
                 var tuple = GetProvider(request.OpenToken);
@@ -389,8 +384,6 @@ namespace Emby.Server.Implementations.Library
 
                 var info = new LiveStreamInfo
                 {
-                    Date = DateTime.UtcNow,
-                    EnableCloseTimer = enableAutoClose,
                     Id = mediaSource.LiveStreamId,
                     MediaSource = mediaSource,
                     DirectStreamProvider = mediaSourceTuple.Item2
@@ -398,11 +391,6 @@ namespace Emby.Server.Implementations.Library
 
                 _openStreams[mediaSource.LiveStreamId] = info;
 
-                if (enableAutoClose)
-                {
-                    StartCloseTimer();
-                }
-
                 var json = _jsonSerializer.SerializeToString(mediaSource);
                 _logger.Debug("Live stream opened: " + json);
                 var clone = _jsonSerializer.DeserializeFromString<MediaSourceInfo>(json);
@@ -462,28 +450,6 @@ namespace Emby.Server.Implementations.Library
             return result.Item1;
         }
 
-        public async Task PingLiveStream(string id, CancellationToken cancellationToken)
-        {
-            await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
-
-            try
-            {
-                LiveStreamInfo info;
-                if (_openStreams.TryGetValue(id, out info))
-                {
-                    info.Date = DateTime.UtcNow;
-                }
-                else
-                {
-                    _logger.Error("Failed to ping live stream {0}", id);
-                }
-            }
-            finally
-            {
-                _liveStreamSemaphore.Release();
-            }
-        }
-
         private async Task CloseLiveStreamWithProvider(IMediaSourceProvider provider, string streamId)
         {
             _logger.Info("Closing live stream {0} with provider {1}", streamId, provider.GetType().Name);
@@ -525,11 +491,6 @@ namespace Emby.Server.Implementations.Library
 
                         await CloseLiveStreamWithProvider(tuple.Item1, tuple.Item2).ConfigureAwait(false);
                     }
-
-                    if (_openStreams.Count == 0)
-                    {
-                        StopCloseTimer();
-                    }
                 }
             }
             finally
@@ -558,66 +519,11 @@ namespace Emby.Server.Implementations.Library
             return new Tuple<IMediaSourceProvider, string>(provider, keyId);
         }
 
-        private ITimer _closeTimer;
-        private readonly TimeSpan _openStreamMaxAge = TimeSpan.FromSeconds(180);
-
-        private void StartCloseTimer()
-        {
-            StopCloseTimer();
-
-            _closeTimer = _timerFactory.Create(CloseTimerCallback, null, _openStreamMaxAge, _openStreamMaxAge);
-        }
-
-        private void StopCloseTimer()
-        {
-            var timer = _closeTimer;
-
-            if (timer != null)
-            {
-                _closeTimer = null;
-                timer.Dispose();
-            }
-        }
-
-        private async void CloseTimerCallback(object state)
-        {
-            List<LiveStreamInfo> infos;
-            await _liveStreamSemaphore.WaitAsync().ConfigureAwait(false);
-
-            try
-            {
-               infos = _openStreams
-                    .Values
-                    .Where(i => i.EnableCloseTimer && DateTime.UtcNow - i.Date > _openStreamMaxAge)
-                    .ToList();
-            }
-            finally
-            {
-                _liveStreamSemaphore.Release();
-            }
-
-            foreach (var info in infos)
-            {
-                if (!info.Closed)
-                {
-                    try
-                    {
-                        await CloseLiveStream(info.Id).ConfigureAwait(false);
-                    }
-                    catch (Exception ex)
-                    {
-                        _logger.ErrorException("Error closing media source", ex);
-                    }
-                }
-            }
-        }
-
         /// <summary>
         /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
         /// </summary>
         public void Dispose()
         {
-            StopCloseTimer();
             Dispose(true);
         }
 
@@ -644,8 +550,6 @@ namespace Emby.Server.Implementations.Library
 
         private class LiveStreamInfo
         {
-            public DateTime Date;
-            public bool EnableCloseTimer;
             public string Id;
             public bool Closed;
             public MediaSourceInfo MediaSource;

+ 1 - 1
Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs

@@ -190,7 +190,7 @@ namespace Emby.Server.Implementations.LiveTv
 
                     else if (width >= 1260)
                     {
-                        videoStream.BitRate = 3000000;
+                        videoStream.BitRate = 4000000;
                     }
 
                     else if (width >= 700)

+ 27 - 39
Emby.Server.Implementations/Session/SessionManager.cs

@@ -197,6 +197,8 @@ namespace Emby.Server.Implementations.Session
                     _logger.ErrorException("Error disposing session controller", ex);
                 }
             }
+
+            info.Dispose();
         }
 
         /// <summary>
@@ -308,10 +310,7 @@ namespace Emby.Server.Implementations.Session
         /// <summary>
         /// Updates the now playing item id.
         /// </summary>
-        /// <param name="session">The session.</param>
-        /// <param name="info">The information.</param>
-        /// <param name="libraryItem">The library item.</param>
-        private async Task UpdateNowPlayingItem(SessionInfo session, PlaybackProgressInfo info, BaseItem libraryItem)
+        private async Task UpdateNowPlayingItem(SessionInfo session, PlaybackProgressInfo info, BaseItem libraryItem, bool updateLastCheckInTime)
         {
             if (string.IsNullOrWhiteSpace(info.MediaSourceId))
             {
@@ -350,7 +349,11 @@ namespace Emby.Server.Implementations.Session
 
             session.NowPlayingItem = info.Item;
             session.LastActivityDate = DateTime.UtcNow;
-            session.LastPlaybackCheckIn = DateTime.UtcNow;
+
+            if (updateLastCheckInTime)
+            {
+                session.LastPlaybackCheckIn = DateTime.UtcNow;
+            }
 
             session.PlayState.IsPaused = info.IsPaused;
             session.PlayState.PositionTicks = info.PositionTicks;
@@ -415,7 +418,7 @@ namespace Emby.Server.Implementations.Session
 
                 if (!_activeConnections.TryGetValue(key, out sessionInfo))
                 {
-                    sessionInfo = new SessionInfo
+                    sessionInfo = new SessionInfo(this, _logger)
                     {
                         Client = appName,
                         DeviceId = deviceId,
@@ -602,14 +605,14 @@ namespace Emby.Server.Implementations.Session
                 ? null
                 : GetNowPlayingItem(session, info.ItemId);
 
-            await UpdateNowPlayingItem(session, info, libraryItem).ConfigureAwait(false);
+            await UpdateNowPlayingItem(session, info, libraryItem, true).ConfigureAwait(false);
 
             if (!string.IsNullOrEmpty(session.DeviceId) && info.PlayMethod != PlayMethod.Transcode)
             {
                 ClearTranscodingInfo(session.DeviceId);
             }
 
-            session.QueueableMediaTypes = info.QueueableMediaTypes;
+            session.StartAutomaticProgress(_timerFactory, info);
 
             var users = GetUsers(session);
 
@@ -668,14 +671,15 @@ namespace Emby.Server.Implementations.Session
             await _userDataManager.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackStart, CancellationToken.None).ConfigureAwait(false);
         }
 
+        public Task OnPlaybackProgress(PlaybackProgressInfo info)
+        {
+            return OnPlaybackProgress(info, false);
+        }
+
         /// <summary>
         /// Used to report playback progress for an item
         /// </summary>
-        /// <param name="info">The info.</param>
-        /// <returns>Task.</returns>
-        /// <exception cref="System.ArgumentNullException"></exception>
-        /// <exception cref="System.ArgumentOutOfRangeException">positionTicks</exception>
-        public async Task OnPlaybackProgress(PlaybackProgressInfo info)
+        public async Task OnPlaybackProgress(PlaybackProgressInfo info, bool isAutomated)
         {
             if (info == null)
             {
@@ -688,7 +692,7 @@ namespace Emby.Server.Implementations.Session
                 ? null
                 : GetNowPlayingItem(session, info.ItemId);
 
-            await UpdateNowPlayingItem(session, info, libraryItem).ConfigureAwait(false);
+            await UpdateNowPlayingItem(session, info, libraryItem, !isAutomated).ConfigureAwait(false);
 
             var users = GetUsers(session);
 
@@ -700,18 +704,6 @@ namespace Emby.Server.Implementations.Session
                 }
             }
 
-            if (!string.IsNullOrWhiteSpace(info.LiveStreamId))
-            {
-                try
-                {
-                    await _mediaSourceManager.PingLiveStream(info.LiveStreamId, CancellationToken.None).ConfigureAwait(false);
-                }
-                catch (Exception ex)
-                {
-                    _logger.ErrorException("Error closing live stream", ex);
-                }
-            }
-
             EventHelper.FireEventIfNotNull(PlaybackProgress, this, new PlaybackProgressEventArgs
             {
                 Item = libraryItem,
@@ -727,6 +719,11 @@ namespace Emby.Server.Implementations.Session
 
             }, _logger);
 
+            if (!isAutomated)
+            {
+                session.StartAutomaticProgress(_timerFactory, info);
+            }
+
             StartIdleCheckTimer();
         }
 
@@ -788,6 +785,8 @@ namespace Emby.Server.Implementations.Session
 
             var session = GetSession(info.SessionId);
 
+            session.StopAutomaticProgress();
+
             var libraryItem = string.IsNullOrWhiteSpace(info.ItemId)
                 ? null
                 : GetNowPlayingItem(session, info.ItemId);
@@ -1009,19 +1008,9 @@ namespace Emby.Server.Implementations.Session
                 }
             }
 
-            if (command.PlayCommand != PlayCommand.PlayNow)
-            {
-                if (items.Any(i => !session.QueueableMediaTypes.Contains(i.MediaType, StringComparer.OrdinalIgnoreCase)))
-                {
-                    throw new ArgumentException(string.Format("{0} is unable to queue the requested media type.", session.DeviceName ?? session.Id));
-                }
-            }
-            else
+            if (items.Any(i => !session.PlayableMediaTypes.Contains(i.MediaType, StringComparer.OrdinalIgnoreCase)))
             {
-                if (items.Any(i => !session.PlayableMediaTypes.Contains(i.MediaType, StringComparer.OrdinalIgnoreCase)))
-                {
-                    throw new ArgumentException(string.Format("{0} is unable to play the requested media type.", session.DeviceName ?? session.Id));
-                }
+                throw new ArgumentException(string.Format("{0} is unable to play the requested media type.", session.DeviceName ?? session.Id));
             }
 
             if (user != null && command.ItemIds.Length == 1 && user.Configuration.EnableNextEpisodeAutoPlay)
@@ -1601,7 +1590,6 @@ namespace Emby.Server.Implementations.Session
                 LastActivityDate = session.LastActivityDate,
                 NowViewingItem = session.NowViewingItem,
                 ApplicationVersion = session.ApplicationVersion,
-                QueueableMediaTypes = session.QueueableMediaTypes,
                 PlayableMediaTypes = session.PlayableMediaTypes,
                 AdditionalUsers = session.AdditionalUsers,
                 SupportedCommands = session.SupportedCommands,

+ 2 - 4
Emby.Server.Implementations/Session/SessionWebSocketListener.cs

@@ -289,7 +289,6 @@ namespace Emby.Server.Implementations.Session
 
                 var itemId = vals[0];
 
-                var queueableMediaTypes = string.Empty;
                 var canSeek = true;
 
                 if (vals.Length > 1)
@@ -298,15 +297,14 @@ namespace Emby.Server.Implementations.Session
                 }
                 if (vals.Length > 2)
                 {
-                    queueableMediaTypes = vals[2];
+                    // vals[2] used to be QueueableMediaTypes
                 }
 
                 var info = new PlaybackStartInfo
                 {
                     CanSeek = canSeek,
                     ItemId = itemId,
-                    SessionId = session.Id,
-                    QueueableMediaTypes = queueableMediaTypes.Split(',').ToList()
+                    SessionId = session.Id
                 };
 
                 if (vals.Length > 3)

+ 0 - 12
MediaBrowser.Api/ApiEntryPoint.cs

@@ -426,18 +426,6 @@ namespace MediaBrowser.Api
             {
                 job.ChangeKillTimerIfStarted();
             }
-
-            if (!string.IsNullOrWhiteSpace(job.LiveStreamId))
-            {
-                try
-                {
-                    await _mediaSourceManager.PingLiveStream(job.LiveStreamId, CancellationToken.None).ConfigureAwait(false);
-                }
-                catch (Exception ex)
-                {
-                    Logger.ErrorException("Error closing live stream", ex);
-                }
-            }
         }
 
         /// <summary>

+ 1 - 1
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -169,7 +169,7 @@ namespace MediaBrowser.Api.Playback
                 {
                     OpenToken = state.MediaSource.OpenToken
 
-                }, false, cancellationTokenSource.Token).ConfigureAwait(false);
+                }, cancellationTokenSource.Token).ConfigureAwait(false);
 
                 EncodingHelper.AttachMediaSourceInfo(state, liveStreamResponse.MediaSource, state.RequestedUrl);
 

+ 1 - 1
MediaBrowser.Api/Playback/MediaInfoService.cs

@@ -109,7 +109,7 @@ namespace MediaBrowser.Api.Playback
         {
             var authInfo = _authContext.GetAuthorizationInfo(Request);
 
-            var result = await _mediaSourceManager.OpenLiveStream(request, true, CancellationToken.None).ConfigureAwait(false);
+            var result = await _mediaSourceManager.OpenLiveStream(request, CancellationToken.None).ConfigureAwait(false);
 
             var profile = request.DeviceProfile;
             if (profile == null)

+ 1 - 34
MediaBrowser.Api/SuggestionsService.cs

@@ -12,7 +12,6 @@ using MediaBrowser.Controller.Library;
 namespace MediaBrowser.Api
 {
     [Route("/Users/{UserId}/Suggestions", "GET", Summary = "Gets items based on a query.")]
-    [Route("/Users/{UserId}/Suggestions", "POST", Summary = "Gets items based on a query.")]
     public class GetSuggestedItems : IReturn<QueryResult<BaseItem>>
     {
         public string MediaType { get; set; }
@@ -21,7 +20,6 @@ namespace MediaBrowser.Api
         public bool EnableTotalRecordCount { get; set; }
         public int? StartIndex { get; set; }
         public int? Limit { get; set; }
-        public string Name { get; set; }
 
         public string[] GetMediaTypes()
         {
@@ -56,13 +54,6 @@ namespace MediaBrowser.Api
             return ToOptimizedResult(result);
         }
 
-        public async Task<object> Post(GetSuggestedItems request)
-        {
-            var result = await GetResultItems(request).ConfigureAwait(false);
-
-            return ToOptimizedResult(result);
-        }
-
         private async Task<QueryResult<BaseItemDto>> GetResultItems(GetSuggestedItems request)
         {
             var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
@@ -86,29 +77,6 @@ namespace MediaBrowser.Api
 
         private QueryResult<BaseItem> GetItems(GetSuggestedItems request, User user, DtoOptions dtoOptions)
         {
-            BaseItem similarToItem = null;
-
-            if (!string.IsNullOrWhiteSpace(request.Name))
-            {
-                // get item by name, then get similar items from that
-                similarToItem = _libraryManager.GetItemList(new InternalItemsQuery(user)
-                {
-                    SortBy = new string[] {ItemSortBy.Random},
-                    MediaTypes = request.GetMediaTypes(),
-                    IncludeItemTypes = request.GetIncludeItemTypes(),
-                    IsVirtualItem = false,
-                    Name = request.Name,
-                    Recursive = true,
-                    Limit = 1
-
-                }).FirstOrDefault();
-
-                if (similarToItem == null)
-                {
-                    return new QueryResult<BaseItem>();
-                }
-            }
-
             return _libraryManager.GetItemsResult(new InternalItemsQuery(user)
             {
                 SortBy = new string[] { ItemSortBy.Random },
@@ -119,8 +87,7 @@ namespace MediaBrowser.Api
                 Limit = request.Limit,
                 DtoOptions = dtoOptions,
                 EnableTotalRecordCount = request.EnableTotalRecordCount,
-                Recursive = true,
-                SimilarTo = similarToItem
+                Recursive = true
             });
         }
     }

+ 4 - 30
MediaBrowser.Api/TvShowsService.cs

@@ -137,7 +137,6 @@ namespace MediaBrowser.Api
     }
 
     [Route("/Shows/{Id}/Episodes", "GET", Summary = "Gets episodes for a tv season")]
-    [Route("/Shows/Episodes", "POST", Summary = "Gets episodes for a tv season")]
     public class GetEpisodes : IReturn<ItemsResult>, IHasItemFields, IHasDtoOptions
     {
         /// <summary>
@@ -200,12 +199,9 @@ namespace MediaBrowser.Api
 
         [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
         public bool? EnableUserData { get; set; }
-
-        public string SeriesName { get; set; }
     }
 
     [Route("/Shows/{Id}/Seasons", "GET", Summary = "Gets seasons for a tv series")]
-    [Route("/Shows/Seasons", "POST", Summary = "Gets seasons for a tv series")]
     public class GetSeasons : IReturn<ItemsResult>, IHasItemFields, IHasDtoOptions
     {
         /// <summary>
@@ -248,8 +244,6 @@ namespace MediaBrowser.Api
 
         [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
         public bool? EnableUserData { get; set; }
-
-        public string SeriesName { get; set; }
     }
 
     /// <summary>
@@ -431,7 +425,7 @@ namespace MediaBrowser.Api
         {
             var user = _userManager.GetUserById(request.UserId);
 
-            var series = GetSeries(request.Id, request.SeriesName, user);
+            var series = GetSeries(request.Id, user);
 
             if (series == null)
             {
@@ -459,33 +453,13 @@ namespace MediaBrowser.Api
             };
         }
 
-        public Task<object> Post(GetSeasons request)
-        {
-            return Get(request);
-        }
-
-        public Task<object> Post(GetEpisodes request)
-        {
-            return Get(request);
-        }
-
-        private Series GetSeries(string seriesId, string seriesName, User user)
+        private Series GetSeries(string seriesId, User user)
         {
             if (!string.IsNullOrWhiteSpace(seriesId))
             {
                 return _libraryManager.GetItemById(seriesId) as Series;
             }
 
-            if (!string.IsNullOrWhiteSpace(seriesName))
-            {
-                return _libraryManager.GetItemList(new InternalItemsQuery(user)
-                {
-                    Name = seriesName,
-                    IncludeItemTypes = new string[] { typeof(Series).Name }
-
-                }).OfType<Series>().FirstOrDefault();
-            }
-
             return null;
         }
 
@@ -508,7 +482,7 @@ namespace MediaBrowser.Api
             }
             else if (request.Season.HasValue)
             {
-                var series = GetSeries(request.Id, request.SeriesName, user);
+                var series = GetSeries(request.Id, user);
 
                 if (series == null)
                 {
@@ -528,7 +502,7 @@ namespace MediaBrowser.Api
             }
             else
             {
-                var series = GetSeries(request.Id, request.SeriesName, user);
+                var series = GetSeries(request.Id, user);
 
                 if (series == null)
                 {

+ 0 - 10
MediaBrowser.Api/UserLibrary/PlaystateService.cs

@@ -109,13 +109,6 @@ namespace MediaBrowser.Api.UserLibrary
         [ApiMember(Name = "CanSeek", Description = "Indicates if the client can seek", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")]
         public bool CanSeek { get; set; }
 
-        /// <summary>
-        /// Gets or sets the id.
-        /// </summary>
-        /// <value>The id.</value>
-        [ApiMember(Name = "QueueableMediaTypes", Description = "A list of media types that can be queued from this item, comma delimited. Audio,Video,Book,Game", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST", AllowMultiple = true)]
-        public string QueueableMediaTypes { get; set; }
-
         [ApiMember(Name = "AudioStreamIndex", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")]
         public int? AudioStreamIndex { get; set; }
 
@@ -292,13 +285,10 @@ namespace MediaBrowser.Api.UserLibrary
         /// <param name="request">The request.</param>
         public void Post(OnPlaybackStart request)
         {
-            var queueableMediaTypes = request.QueueableMediaTypes ?? string.Empty;
-
             Post(new ReportPlaybackStart
             {
                 CanSeek = request.CanSeek,
                 ItemId = request.Id,
-                QueueableMediaTypes = queueableMediaTypes.Split(',').ToList(),
                 MediaSourceId = request.MediaSourceId,
                 AudioStreamIndex = request.AudioStreamIndex,
                 SubtitleStreamIndex = request.SubtitleStreamIndex,

+ 1 - 10
MediaBrowser.Controller/Library/IMediaSourceManager.cs

@@ -68,10 +68,9 @@ namespace MediaBrowser.Controller.Library
         /// Opens the media source.
         /// </summary>
         /// <param name="request">The request.</param>
-        /// <param name="enableAutoClose">if set to <c>true</c> [enable automatic close].</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task&lt;MediaSourceInfo&gt;.</returns>
-        Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, bool enableAutoClose, CancellationToken cancellationToken);
+        Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, CancellationToken cancellationToken);
 
         /// <summary>
         /// Gets the live stream.
@@ -82,14 +81,6 @@ namespace MediaBrowser.Controller.Library
         Task<MediaSourceInfo> GetLiveStream(string id, CancellationToken cancellationToken);
 
         Task<Tuple<MediaSourceInfo, IDirectStreamProvider>> GetLiveStreamWithDirectStreamProvider(string id, CancellationToken cancellationToken);
-        
-        /// <summary>
-        /// Pings the media source.
-        /// </summary>
-        /// <param name="id">The live stream identifier.</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task.</returns>
-        Task PingLiveStream(string id, CancellationToken cancellationToken);
 
         /// <summary>
         /// Closes the media source.

+ 2 - 0
MediaBrowser.Controller/Session/ISessionManager.cs

@@ -99,6 +99,8 @@ namespace MediaBrowser.Controller.Session
         /// <exception cref="System.ArgumentNullException"></exception>
         Task OnPlaybackProgress(PlaybackProgressInfo info);
 
+        Task OnPlaybackProgress(PlaybackProgressInfo info, bool isAutomated);
+
         /// <summary>
         /// Used to report that playback has ended for an item
         /// </summary>

+ 94 - 11
MediaBrowser.Controller/Session/SessionInfo.cs

@@ -4,24 +4,30 @@ using System;
 using System.Collections.Generic;
 using System.Linq;
 using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Threading;
 
 namespace MediaBrowser.Controller.Session
 {
     /// <summary>
     /// Class SessionInfo
     /// </summary>
-    public class SessionInfo
+    public class SessionInfo : IDisposable
     {
-        public SessionInfo()
+        private ISessionManager _sessionManager;
+        private readonly ILogger _logger;
+
+        public SessionInfo(ISessionManager sessionManager, ILogger logger)
         {
-            QueueableMediaTypes = new List<string>();
+            _sessionManager = sessionManager;
+            _logger = logger;
 
             AdditionalUsers = new List<SessionUserInfo>();
             PlayState = new PlayerStateInfo();
         }
 
         public PlayerStateInfo PlayState { get; set; }
-        
+
         public List<SessionUserInfo> AdditionalUsers { get; set; }
 
         public ClientCapabilities Capabilities { get; set; }
@@ -32,12 +38,6 @@ namespace MediaBrowser.Controller.Session
         /// <value>The remote end point.</value>
         public string RemoteEndPoint { get; set; }
 
-        /// <summary>
-        /// Gets or sets the queueable media types.
-        /// </summary>
-        /// <value>The queueable media types.</value>
-        public List<string> QueueableMediaTypes { get; set; }
-
         /// <summary>
         /// Gets or sets the playable media types.
         /// </summary>
@@ -133,7 +133,7 @@ namespace MediaBrowser.Controller.Session
         /// </summary>
         /// <value>The application icon URL.</value>
         public string AppIconUrl { get; set; }
-        
+
         /// <summary>
         /// Gets or sets the supported commands.
         /// </summary>
@@ -196,5 +196,88 @@ namespace MediaBrowser.Controller.Session
         {
             return (UserId ?? Guid.Empty) == userId || AdditionalUsers.Any(i => userId == new Guid(i.UserId));
         }
+
+        private readonly object _progressLock = new object();
+        private ITimer _progressTimer;
+        private PlaybackProgressInfo _lastProgressInfo;
+
+        public void StartAutomaticProgress(ITimerFactory timerFactory, PlaybackProgressInfo progressInfo)
+        {
+            lock (_progressLock)
+            {
+                _lastProgressInfo = progressInfo;
+
+                if (_progressTimer == null)
+                {
+                    _progressTimer = timerFactory.Create(OnProgressTimerCallback, null, 1000, 1000);
+                }
+                else
+                {
+                    _progressTimer.Change(1000, 1000);
+                }
+            }
+        }
+
+        // 1 second
+        private const long ProgressIncrement = 10000000;
+
+        private async void OnProgressTimerCallback(object state)
+        {
+            var progressInfo = _lastProgressInfo;
+            if (progressInfo == null)
+            {
+                return;
+            }
+            if (progressInfo.IsPaused)
+            {
+                return;
+            }
+
+            var positionTicks = progressInfo.PositionTicks ?? 0;
+            if (positionTicks < 0)
+            {
+                positionTicks = 0;
+            }
+
+            var newPositionTicks = positionTicks + ProgressIncrement;
+            var item = progressInfo.Item;
+            long? runtimeTicks = item == null ? null : item.RunTimeTicks;
+
+            // Don't report beyond the runtime
+            if (runtimeTicks.HasValue && newPositionTicks >= runtimeTicks.Value)
+            {
+                return;
+            }
+
+            progressInfo.PositionTicks = newPositionTicks;
+
+            try
+            {
+                await _sessionManager.OnPlaybackProgress(progressInfo, true).ConfigureAwait(false);
+            }
+            catch (Exception ex)
+            {
+                _logger.ErrorException("Error reporting playback progress", ex);
+            }
+        }
+
+        public void StopAutomaticProgress()
+        {
+            lock (_progressLock)
+            {
+                if (_progressTimer != null)
+                {
+                    _progressTimer.Dispose();
+                    _progressTimer = null;
+                }
+                _lastProgressInfo = null;
+            }
+        }
+
+        public void Dispose()
+        {
+            StopAutomaticProgress();
+            _sessionManager = null;
+        }
     }
 }

+ 1 - 1
MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs

@@ -356,7 +356,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
                 {
                     OpenToken = state.MediaSource.OpenToken
 
-                }, false, cancellationToken).ConfigureAwait(false);
+                }, cancellationToken).ConfigureAwait(false);
 
                 EncodingHelper.AttachMediaSourceInfo(state, liveStreamResponse.MediaSource, null);
 

+ 1 - 12
MediaBrowser.Model/Session/PlaybackStartInfo.cs

@@ -1,5 +1,4 @@
-using System.Collections.Generic;
-
+
 namespace MediaBrowser.Model.Session
 {
     /// <summary>
@@ -7,15 +6,5 @@ namespace MediaBrowser.Model.Session
     /// </summary>
     public class PlaybackStartInfo : PlaybackProgressInfo
     {
-        public PlaybackStartInfo()
-        {
-            QueueableMediaTypes = new List<string>();
-        }
-
-        /// <summary>
-        /// Gets or sets the queueable media types.
-        /// </summary>
-        /// <value>The queueable media types.</value>
-        public List<string> QueueableMediaTypes { get; set; }
     }
 }

+ 0 - 7
MediaBrowser.Model/Session/SessionInfoDto.cs

@@ -14,12 +14,6 @@ namespace MediaBrowser.Model.Session
         /// <value>The supported commands.</value>
         public List<string> SupportedCommands { get; set; }
 
-        /// <summary>
-        /// Gets or sets the queueable media types.
-        /// </summary>
-        /// <value>The queueable media types.</value>
-        public List<string> QueueableMediaTypes { get; set; }
-
         /// <summary>
         /// Gets or sets the playable media types.
         /// </summary>
@@ -119,7 +113,6 @@ namespace MediaBrowser.Model.Session
             AdditionalUsers = new List<SessionUserInfo>();
 
             PlayableMediaTypes = new List<string>();
-            QueueableMediaTypes = new List<string>();
             SupportedCommands = new List<string>();
         }
     }

+ 1 - 1
SharedVersion.cs

@@ -1,3 +1,3 @@
 using System.Reflection;
 
-[assembly: AssemblyVersion("3.2.12.7")]
+[assembly: AssemblyVersion("3.2.12.8")]