Explorar o código

update display of active recordings

Luke Pulverenti %!s(int64=8) %!d(string=hai) anos
pai
achega
d5b5c8e1a5
Modificáronse 33 ficheiros con 361 adicións e 135 borrados
  1. 2 2
      MediaBrowser.Api/Playback/BaseStreamingService.cs
  2. 9 0
      MediaBrowser.Controller/Entities/AggregateFolder.cs
  3. 12 4
      MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
  4. 9 0
      MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
  5. 9 0
      MediaBrowser.Controller/Entities/BaseItem.cs
  6. 9 0
      MediaBrowser.Controller/Entities/CollectionFolder.cs
  7. 9 0
      MediaBrowser.Controller/Entities/Folder.cs
  8. 9 0
      MediaBrowser.Controller/Entities/GameSystem.cs
  9. 2 0
      MediaBrowser.Controller/Entities/IHasUserData.cs
  10. 2 2
      MediaBrowser.Controller/Entities/Photo.cs
  11. 9 0
      MediaBrowser.Controller/Entities/PhotoAlbum.cs
  12. 9 0
      MediaBrowser.Controller/Entities/UserRootFolder.cs
  13. 9 0
      MediaBrowser.Controller/Entities/UserView.cs
  14. 9 0
      MediaBrowser.Controller/Entities/Video.cs
  15. 9 0
      MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs
  16. 1 1
      MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
  17. 1 0
      MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs
  18. 9 0
      MediaBrowser.Controller/Playlists/Playlist.cs
  19. 2 2
      MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
  20. 13 2
      MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs
  21. 34 6
      MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
  22. 2 1
      MediaBrowser.Model/MediaInfo/MediaProtocol.cs
  23. 1 1
      MediaBrowser.Server.Implementations/Dto/DtoService.cs
  24. 2 1
      MediaBrowser.Server.Implementations/Library/UserDataManager.cs
  25. 36 18
      MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
  26. 110 0
      MediaBrowser.Server.Implementations/LiveTv/LiveStreamHelper.cs
  27. 19 0
      MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
  28. 1 87
      MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
  29. 1 0
      MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
  30. 7 3
      MediaBrowser.Server.Implementations/Session/SessionManager.cs
  31. 2 2
      Nuget/MediaBrowser.Common.Internal.nuspec
  32. 1 1
      Nuget/MediaBrowser.Common.nuspec
  33. 2 2
      Nuget/MediaBrowser.Server.Core.nuspec

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

@@ -819,10 +819,10 @@ namespace MediaBrowser.Api.Playback
         {
             if (state.PlayableStreamFileNames.Count > 0)
             {
-                return MediaEncoder.GetProbeSizeArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol);
+                return MediaEncoder.GetProbeSizeAndAnalyzeDurationArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol);
             }
 
-            return MediaEncoder.GetProbeSizeArgument(new[] { state.MediaPath }, state.InputProtocol);
+            return MediaEncoder.GetProbeSizeAndAnalyzeDurationArgument(new[] { state.MediaPath }, state.InputProtocol);
         }
 
         /// <summary>

+ 9 - 0
MediaBrowser.Controller/Entities/AggregateFolder.cs

@@ -45,6 +45,15 @@ namespace MediaBrowser.Controller.Entities
             return false;
         }
 
+        [IgnoreDataMember]
+        public override bool SupportsPlayedStatus
+        {
+            get
+            {
+                return false;
+            }
+        }
+
         /// <summary>
         /// The _virtual children
         /// </summary>

+ 12 - 4
MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs

@@ -17,6 +17,9 @@ namespace MediaBrowser.Controller.Entities.Audio
     /// </summary>
     public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>, IMetadataContainer
     {
+        public List<string> AlbumArtists { get; set; }
+        public List<string> Artists { get; set; }
+
         public MusicAlbum()
         {
             Artists = new List<string>();
@@ -48,6 +51,15 @@ namespace MediaBrowser.Controller.Entities.Audio
             }
         }
 
+        [IgnoreDataMember]
+        public override bool SupportsPlayedStatus
+        {
+            get
+            {
+                return false;
+            }
+        }
+
         [IgnoreDataMember]
         public override bool SupportsCumulativeRunTimeTicks
         {
@@ -83,8 +95,6 @@ namespace MediaBrowser.Controller.Entities.Audio
             get { return false; }
         }
 
-        public List<string> AlbumArtists { get; set; }
-
         /// <summary>
         /// Gets the tracks.
         /// </summary>
@@ -103,8 +113,6 @@ namespace MediaBrowser.Controller.Entities.Audio
             return Tracks;
         }
 
-        public List<string> Artists { get; set; }
-
         public override List<string> GetUserDataKeys()
         {
             var list = base.GetUserDataKeys();

+ 9 - 0
MediaBrowser.Controller/Entities/Audio/MusicArtist.cs

@@ -48,6 +48,15 @@ namespace MediaBrowser.Controller.Entities.Audio
             get { return true; }
         }
 
+        [IgnoreDataMember]
+        public override bool SupportsPlayedStatus
+        {
+            get
+            {
+                return false;
+            }
+        }
+
         public override bool CanDelete()
         {
             return !IsAccessedByName;

+ 9 - 0
MediaBrowser.Controller/Entities/BaseItem.cs

@@ -129,6 +129,15 @@ namespace MediaBrowser.Controller.Entities
             get { return false; }
         }
 
+        [IgnoreDataMember]
+        public virtual bool SupportsPlayedStatus
+        {
+            get
+            {
+                return false;
+            }
+        }
+
         public bool DetectIsInMixedFolder()
         {
             if (SupportsIsInMixedFolderDetection)

+ 9 - 0
MediaBrowser.Controller/Entities/CollectionFolder.cs

@@ -38,6 +38,15 @@ namespace MediaBrowser.Controller.Entities
             }
         }
 
+        [IgnoreDataMember]
+        public override bool SupportsPlayedStatus
+        {
+            get
+            {
+                return false;
+            }
+        }
+
         public override bool CanDelete()
         {
             return false;

+ 9 - 0
MediaBrowser.Controller/Entities/Folder.cs

@@ -61,6 +61,15 @@ namespace MediaBrowser.Controller.Entities
             get { return false; }
         }
 
+        [IgnoreDataMember]
+        public override bool SupportsPlayedStatus
+        {
+            get
+            {
+                return true;
+            }
+        }
+
         /// <summary>
         /// Gets a value indicating whether this instance is folder.
         /// </summary>

+ 9 - 0
MediaBrowser.Controller/Entities/GameSystem.cs

@@ -26,6 +26,15 @@ namespace MediaBrowser.Controller.Entities
             }
         }
 
+        [IgnoreDataMember]
+        public override bool SupportsPlayedStatus
+        {
+            get
+            {
+                return false;
+            }
+        }
+
         /// <summary>
         /// Gets or sets the game system.
         /// </summary>

+ 2 - 0
MediaBrowser.Controller/Entities/IHasUserData.cs

@@ -20,5 +20,7 @@ namespace MediaBrowser.Controller.Entities
         Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user);
 
         bool EnableRememberingTrackSelections { get; }
+
+        bool SupportsPlayedStatus { get; }
     }
 }

+ 2 - 2
MediaBrowser.Controller/Entities/Photo.cs

@@ -29,13 +29,13 @@ namespace MediaBrowser.Controller.Entities
         {
             get
             {
-                return Album;
+                return AlbumEntity;
             }
         }
 
 
         [IgnoreDataMember]
-        public PhotoAlbum Album
+        public PhotoAlbum AlbumEntity
         {
             get
             {

+ 9 - 0
MediaBrowser.Controller/Entities/PhotoAlbum.cs

@@ -16,6 +16,15 @@ namespace MediaBrowser.Controller.Entities
             }
         }
 
+        [IgnoreDataMember]
+        public override bool SupportsPlayedStatus
+        {
+            get
+            {
+                return false;
+            }
+        }
+
         protected override bool GetBlockUnratedValue(UserPolicy config)
         {
             return config.BlockUnratedItems.Contains(UnratedItem.Other);

+ 9 - 0
MediaBrowser.Controller/Entities/UserRootFolder.cs

@@ -33,6 +33,15 @@ namespace MediaBrowser.Controller.Entities
             }
         }
 
+        [IgnoreDataMember]
+        public override bool SupportsPlayedStatus
+        {
+            get
+            {
+                return false;
+            }
+        }
+
         private void ClearCache()
         {
             lock (_childIdsLock)

+ 9 - 0
MediaBrowser.Controller/Entities/UserView.cs

@@ -44,6 +44,15 @@ namespace MediaBrowser.Controller.Entities
             return list;
         }
 
+        [IgnoreDataMember]
+        public override bool SupportsPlayedStatus
+        {
+            get
+            {
+                return false;
+            }
+        }
+
         public override int GetChildCount(User user)
         {
             return GetChildren(user, true).Count();

+ 9 - 0
MediaBrowser.Controller/Entities/Video.cs

@@ -44,6 +44,15 @@ namespace MediaBrowser.Controller.Entities
             }
         }
 
+        [IgnoreDataMember]
+        public override bool SupportsPlayedStatus
+        {
+            get
+            {
+                return true;
+            }
+        }
+
         public override string CreatePresentationUniqueKey()
         {
             if (!string.IsNullOrWhiteSpace(PrimaryVersionId))

+ 9 - 0
MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs

@@ -54,6 +54,15 @@ namespace MediaBrowser.Controller.LiveTv
             }
         }
 
+        [IgnoreDataMember]
+        public override bool SupportsPlayedStatus
+        {
+            get
+            {
+                return Status == RecordingStatus.Completed && base.SupportsPlayedStatus;
+            }
+        }
+
         [IgnoreDataMember]
         public override LocationType LocationType
         {

+ 1 - 1
MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs

@@ -84,7 +84,7 @@ namespace MediaBrowser.Controller.MediaEncoding
         /// <param name="inputFiles">The input files.</param>
         /// <param name="protocol">The protocol.</param>
         /// <returns>System.String.</returns>
-        string GetProbeSizeArgument(string[] inputFiles, MediaProtocol protocol);
+        string GetProbeSizeAndAnalyzeDurationArgument(string[] inputFiles, MediaProtocol protocol);
 
         /// <summary>
         /// Gets the input argument.

+ 1 - 0
MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs

@@ -15,6 +15,7 @@ namespace MediaBrowser.Controller.MediaEncoding
         public IIsoMount MountedIso { get; set; }
         public VideoType VideoType { get; set; }
         public List<string> PlayableStreamFileNames { get; set; }
+        public int AnalyzeDurationSections { get; set; }
 
         public MediaInfoRequest()
         {

+ 9 - 0
MediaBrowser.Controller/Playlists/Playlist.cs

@@ -31,6 +31,15 @@ namespace MediaBrowser.Controller.Playlists
             }
         }
 
+        [IgnoreDataMember]
+        public override bool SupportsPlayedStatus
+        {
+            get
+            {
+                return string.Equals(MediaType, "Video", StringComparison.OrdinalIgnoreCase);
+            }
+        }
+
         [IgnoreDataMember]
         public override bool AlwaysScanInternalMetadataPath
         {

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

@@ -431,10 +431,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
         {
             if (state.PlayableStreamFileNames.Count > 0)
             {
-                return MediaEncoder.GetProbeSizeArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol);
+                return MediaEncoder.GetProbeSizeAndAnalyzeDurationArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol);
             }
 
-            return MediaEncoder.GetProbeSizeArgument(new[] { state.MediaPath }, state.InputProtocol);
+            return MediaEncoder.GetProbeSizeAndAnalyzeDurationArgument(new[] { state.MediaPath }, state.InputProtocol);
         }
 
         /// <summary>

+ 13 - 2
MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs

@@ -26,6 +26,12 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
                 return string.Format("\"{0}\"", url);
             }
+            if (protocol == MediaProtocol.Udp)
+            {
+                var url = inputFiles.First();
+
+                return string.Format("\"{0}\"", url);
+            }
 
             return GetConcatInputArgument(inputFiles);
         }
@@ -74,9 +80,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
             return path.Replace("\"", "\\\"");
         }
 
-        public static string GetProbeSizeArgument(bool isDvd)
+        public static string GetProbeSizeArgument(int numInputFiles)
+        {
+            return numInputFiles > 1 ? "-probesize 1G" : "";
+        }
+
+        public static string GetAnalyzeDurationArgument(int numInputFiles)
         {
-            return isDvd ? "-probesize 1G -analyzeduration 200M" : "";
+            return numInputFiles > 1 ? "-analyzeduration 200M" : "";
         }
     }
 }

+ 34 - 6
MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs

@@ -426,10 +426,24 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
             var inputFiles = MediaEncoderHelpers.GetInputArgument(FileSystem, request.InputPath, request.Protocol, request.MountedIso, request.PlayableStreamFileNames);
 
-            var probeSizeArgument = GetProbeSizeArgument(inputFiles, request.Protocol);
+            var probeSize = EncodingUtils.GetProbeSizeArgument(inputFiles.Length);
+            string analyzeDuration;
+
+            if (request.AnalyzeDurationSections > 0)
+            {
+                analyzeDuration = "-analyzeduration " +
+                                  (request.AnalyzeDurationSections*1000000).ToString(CultureInfo.InvariantCulture);
+            }
+            else
+            {
+                analyzeDuration = EncodingUtils.GetAnalyzeDurationArgument(inputFiles.Length);
+            }
+
+            probeSize = probeSize + " " + analyzeDuration;
+            probeSize = probeSize.Trim();
 
             return GetMediaInfoInternal(GetInputArgument(inputFiles, request.Protocol), request.InputPath, request.Protocol, extractChapters,
-                probeSizeArgument, request.MediaType == DlnaProfileType.Audio, request.VideoType, cancellationToken);
+                probeSize, request.MediaType == DlnaProfileType.Audio, request.VideoType, cancellationToken);
         }
 
         /// <summary>
@@ -450,9 +464,23 @@ namespace MediaBrowser.MediaEncoding.Encoder
         /// <param name="inputFiles">The input files.</param>
         /// <param name="protocol">The protocol.</param>
         /// <returns>System.String.</returns>
-        public string GetProbeSizeArgument(string[] inputFiles, MediaProtocol protocol)
+        public string GetProbeSizeAndAnalyzeDurationArgument(string[] inputFiles, MediaProtocol protocol)
         {
-            return EncodingUtils.GetProbeSizeArgument(inputFiles.Length > 1);
+            var results = new List<string>();
+
+            var probeSize = EncodingUtils.GetProbeSizeArgument(inputFiles.Length);
+            var analyzeDuration = EncodingUtils.GetAnalyzeDurationArgument(inputFiles.Length);
+
+            if (!string.IsNullOrWhiteSpace(probeSize))
+            {
+                results.Add(probeSize);
+            }
+
+            if (!string.IsNullOrWhiteSpace(analyzeDuration))
+            {
+                results.Add(analyzeDuration);
+            }
+            return string.Join(" ", results.ToArray());
         }
 
         /// <summary>
@@ -871,7 +899,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
             var args = useIFrame ? string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}{4}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, thumbnail) :
                 string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg);
 
-            var probeSize = GetProbeSizeArgument(new[] { inputPath }, protocol);
+            var probeSize = GetProbeSizeAndAnalyzeDurationArgument(new[] { inputPath }, protocol);
 
             if (!string.IsNullOrEmpty(probeSize))
             {
@@ -982,7 +1010,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
             var args = string.Format("-i {0} -threads 0 -v quiet -vf \"{2}\" -f image2 \"{1}\"", inputArgument, outputPath, vf);
 
-            var probeSize = GetProbeSizeArgument(new[] { inputArgument }, protocol);
+            var probeSize = GetProbeSizeAndAnalyzeDurationArgument(new[] { inputArgument }, protocol);
 
             if (!string.IsNullOrEmpty(probeSize))
             {

+ 2 - 1
MediaBrowser.Model/MediaInfo/MediaProtocol.cs

@@ -5,6 +5,7 @@ namespace MediaBrowser.Model.MediaInfo
         File = 0,
         Http = 1,
         Rtmp = 2,
-        Rtsp = 3
+        Rtsp = 3,
+        Udp = 4
     }
 }

+ 1 - 1
MediaBrowser.Server.Implementations/Dto/DtoService.cs

@@ -598,7 +598,7 @@ namespace MediaBrowser.Server.Implementations.Dto
             dto.Altitude = item.Altitude;
             dto.IsoSpeedRating = item.IsoSpeedRating;
 
-            var album = item.Album;
+            var album = item.AlbumEntity;
 
             if (album != null)
             {

+ 2 - 1
MediaBrowser.Server.Implementations/Library/UserDataManager.cs

@@ -269,9 +269,10 @@ namespace MediaBrowser.Server.Implementations.Library
                 positionTicks = 0;
             }
 
-            if (item is Audio)
+            if (!item.SupportsPlayedStatus)
             {
                 positionTicks = 0;
+                data.Played = false;
             }
 
             data.PlaybackPositionTicks = positionTicks;

+ 36 - 18
MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs

@@ -27,6 +27,7 @@ using System.Threading;
 using System.Threading.Tasks;
 using System.Xml;
 using CommonIO;
+using MediaBrowser.Common.Events;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Entities;
@@ -59,8 +60,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
 
         public static EmbyTV Current;
 
-        public event EventHandler DataSourceChanged { add { } remove { } }
-        public event EventHandler<RecordingStatusChangedEventArgs> RecordingStatusChanged { add { } remove { } }
+        public event EventHandler DataSourceChanged;
+        public event EventHandler<RecordingStatusChangedEventArgs> RecordingStatusChanged;
 
         private readonly ConcurrentDictionary<string, ActiveRecordingInfo> _activeRecordings =
             new ConcurrentDictionary<string, ActiveRecordingInfo>(StringComparer.OrdinalIgnoreCase);
@@ -1009,7 +1010,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             throw new NotImplementedException();
         }
 
-        public Task<List<MediaSourceInfo>> GetRecordingStreamMediaSources(string recordingId, CancellationToken cancellationToken)
+        public async Task<List<MediaSourceInfo>> GetRecordingStreamMediaSources(string recordingId, CancellationToken cancellationToken)
         {
             ActiveRecordingInfo info;
 
@@ -1017,22 +1018,27 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
 
             if (_activeRecordings.TryGetValue(recordingId, out info))
             {
-                return Task.FromResult(new List<MediaSourceInfo>
+                var stream = new MediaSourceInfo
+                {
+                    Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveRecordings/" + recordingId + "/stream",
+                    Id = recordingId,
+                    SupportsDirectPlay = false,
+                    SupportsDirectStream = true,
+                    SupportsTranscoding = true,
+                    IsInfiniteStream = true,
+                    RequiresOpening = false,
+                    RequiresClosing = false,
+                    Protocol = Model.MediaInfo.MediaProtocol.Http,
+                    BufferMs = 0
+                };
+
+                var isAudio = false;
+                await new LiveStreamHelper(_mediaEncoder, _logger).AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false);
+
+                return new List<MediaSourceInfo>
                 {
-                    new MediaSourceInfo
-                    {
-                        Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveRecordings/" + recordingId + "/stream",
-                        Id = recordingId,
-                        SupportsDirectPlay = false,
-                        SupportsDirectStream = true,
-                        SupportsTranscoding = true,
-                        IsInfiniteStream = true,
-                        RequiresOpening = false,
-                        RequiresClosing = false,
-                        Protocol = Model.MediaInfo.MediaProtocol.Http,
-                        BufferMs = 0
-                    }
-                });
+                    stream
+                };
             }
 
             throw new FileNotFoundException();
@@ -1258,6 +1264,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
 
             string liveStreamId = null;
 
+            OnRecordingStatusChanged();
+
             try
             {
                 var allMediaSources = await GetChannelStreamMediaSources(timer.ChannelId, CancellationToken.None).ConfigureAwait(false);
@@ -1353,6 +1361,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             {
                 _timerProvider.Delete(timer);
             }
+
+            OnRecordingStatusChanged();
+        }
+
+        private void OnRecordingStatusChanged()
+        {
+            EventHelper.FireEventIfNotNull(RecordingStatusChanged, this, new RecordingStatusChangedEventArgs
+            {
+
+            }, _logger);
         }
 
         private async void EnforceKeepUpTo(TimerInfo timer)

+ 110 - 0
MediaBrowser.Server.Implementations/LiveTv/LiveStreamHelper.cs

@@ -0,0 +1,110 @@
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.MediaEncoding;
+using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Logging;
+
+namespace MediaBrowser.Server.Implementations.LiveTv
+{
+    public class LiveStreamHelper
+    {
+        private readonly IMediaEncoder _mediaEncoder;
+        private readonly ILogger _logger;
+
+        public LiveStreamHelper(IMediaEncoder mediaEncoder, ILogger logger)
+        {
+            _mediaEncoder = mediaEncoder;
+            _logger = logger;
+        }
+
+        public async Task AddMediaInfoWithProbe(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
+        {
+            var originalRuntime = mediaSource.RunTimeTicks;
+
+            var now = DateTime.UtcNow;
+
+            var info = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest
+            {
+                InputPath = mediaSource.Path,
+                Protocol = mediaSource.Protocol,
+                MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video,
+                ExtractChapters = false,
+                AnalyzeDurationSections = 2
+
+            }, cancellationToken).ConfigureAwait(false);
+
+            _logger.Info("Live tv media info probe took {0} seconds", (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture));
+
+            mediaSource.Bitrate = info.Bitrate;
+            mediaSource.Container = info.Container;
+            mediaSource.Formats = info.Formats;
+            mediaSource.MediaStreams = info.MediaStreams;
+            mediaSource.RunTimeTicks = info.RunTimeTicks;
+            mediaSource.Size = info.Size;
+            mediaSource.Timestamp = info.Timestamp;
+            mediaSource.Video3DFormat = info.Video3DFormat;
+            mediaSource.VideoType = info.VideoType;
+
+            mediaSource.DefaultSubtitleStreamIndex = null;
+
+            // Null this out so that it will be treated like a live stream
+            if (!originalRuntime.HasValue)
+            {
+                mediaSource.RunTimeTicks = null;
+            }
+
+            var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Audio);
+
+            if (audioStream == null || audioStream.Index == -1)
+            {
+                mediaSource.DefaultAudioStreamIndex = null;
+            }
+            else
+            {
+                mediaSource.DefaultAudioStreamIndex = audioStream.Index;
+            }
+
+            var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Video);
+            if (videoStream != null)
+            {
+                if (!videoStream.BitRate.HasValue)
+                {
+                    var width = videoStream.Width ?? 1920;
+
+                    if (width >= 1900)
+                    {
+                        videoStream.BitRate = 8000000;
+                    }
+
+                    else if (width >= 1260)
+                    {
+                        videoStream.BitRate = 3000000;
+                    }
+
+                    else if (width >= 700)
+                    {
+                        videoStream.BitRate = 1000000;
+                    }
+                }
+
+                // This is coming up false and preventing stream copy
+                videoStream.IsAVC = null;
+            }
+
+            // Try to estimate this
+            if (!mediaSource.Bitrate.HasValue)
+            {
+                var total = mediaSource.MediaStreams.Select(i => i.BitRate ?? 0).Sum();
+
+                if (total > 0)
+                {
+                    mediaSource.Bitrate = total;
+                }
+            }
+        }
+    }
+}

+ 19 - 0
MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -121,9 +121,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             foreach (var service in _services)
             {
                 service.DataSourceChanged += service_DataSourceChanged;
+                service.RecordingStatusChanged += Service_RecordingStatusChanged;
             }
         }
 
+        private void Service_RecordingStatusChanged(object sender, RecordingStatusChangedEventArgs e)
+        {
+            _lastRecordingRefreshTime = DateTime.MinValue;
+        }
+
         public List<ITunerHost> TunerHosts
         {
             get { return _tunerHosts; }
@@ -2299,6 +2305,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
             var info = await service.GetNewTimerDefaultsAsync(cancellationToken, programInfo).ConfigureAwait(false);
 
+            info.RecordAnyChannel = true;
+            info.RecordAnyTime = true;
+            info.Days = new List<DayOfWeek>
+            {
+                DayOfWeek.Sunday,
+                DayOfWeek.Monday,
+                DayOfWeek.Tuesday,
+                DayOfWeek.Wednesday,
+                DayOfWeek.Thursday,
+                DayOfWeek.Friday,
+                DayOfWeek.Saturday
+            };
+
             info.Id = null;
 
             return new Tuple<SeriesTimerInfo, ILiveTvService>(info, service);

+ 1 - 87
MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs

@@ -146,7 +146,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 }
                 else
                 {
-                    await AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false);
+                    await new LiveStreamHelper(_mediaEncoder, _logger).AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false);
                 }
             }
             catch (Exception ex)
@@ -216,92 +216,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             }
         }
 
-        private async Task AddMediaInfoWithProbe(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
-        {
-            var originalRuntime = mediaSource.RunTimeTicks;
-
-            var now = DateTime.UtcNow;
-
-            var info = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest
-            {
-                InputPath = mediaSource.Path,
-                Protocol = mediaSource.Protocol,
-                MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video,
-                ExtractChapters = false
-
-            }, cancellationToken).ConfigureAwait(false);
-
-            _logger.Info("Live tv media info probe took {0} seconds", (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture));
-
-            mediaSource.Bitrate = info.Bitrate;
-            mediaSource.Container = info.Container;
-            mediaSource.Formats = info.Formats;
-            mediaSource.MediaStreams = info.MediaStreams;
-            mediaSource.RunTimeTicks = info.RunTimeTicks;
-            mediaSource.Size = info.Size;
-            mediaSource.Timestamp = info.Timestamp;
-            mediaSource.Video3DFormat = info.Video3DFormat;
-            mediaSource.VideoType = info.VideoType;
-
-            mediaSource.DefaultSubtitleStreamIndex = null;
-
-            // Null this out so that it will be treated like a live stream
-            if (!originalRuntime.HasValue)
-            {
-                mediaSource.RunTimeTicks = null;
-            }
-
-            var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Audio);
-
-            if (audioStream == null || audioStream.Index == -1)
-            {
-                mediaSource.DefaultAudioStreamIndex = null;
-            }
-            else
-            {
-                mediaSource.DefaultAudioStreamIndex = audioStream.Index;
-            }
-
-            var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Video);
-            if (videoStream != null)
-            {
-                if (!videoStream.BitRate.HasValue)
-                {
-                    var width = videoStream.Width ?? 1920;
-
-                    if (width >= 1900)
-                    {
-                        videoStream.BitRate = 8000000;
-                    }
-
-                    else if (width >= 1260)
-                    {
-                        videoStream.BitRate = 3000000;
-                    }
-
-                    else if (width >= 700)
-                    {
-                        videoStream.BitRate = 1000000;
-                    }
-                }
-
-                // This is coming up false and preventing stream copy
-                videoStream.IsAVC = null;
-            }
-
-            // Try to estimate this
-            if (!mediaSource.Bitrate.HasValue)
-            {
-                var total = mediaSource.MediaStreams.Select(i => i.BitRate ?? 0).Sum();
-
-                if (total > 0)
-                {
-                    mediaSource.Bitrate = total;
-                }
-            }
-        }
-
-
         public Task CloseMediaSource(string liveStreamId)
         {
             return _liveTvManager.CloseLiveStream(liveStreamId);

+ 1 - 0
MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj

@@ -234,6 +234,7 @@
     <Compile Include="LiveTv\EmbyTV\TimerManager.cs" />
     <Compile Include="LiveTv\Listings\SchedulesDirect.cs" />
     <Compile Include="LiveTv\Listings\XmlTvListingsProvider.cs" />
+    <Compile Include="LiveTv\LiveStreamHelper.cs" />
     <Compile Include="LiveTv\LiveTvConfigurationFactory.cs" />
     <Compile Include="LiveTv\LiveTvDtoService.cs" />
     <Compile Include="LiveTv\LiveTvManager.cs" />

+ 7 - 3
MediaBrowser.Server.Implementations/Session/SessionManager.cs

@@ -633,10 +633,14 @@ namespace MediaBrowser.Server.Implementations.Session
             data.PlayCount++;
             data.LastPlayedDate = DateTime.UtcNow;
 
-            if (!(item is Video))
+            if (!(item is Video) && item.SupportsPlayedStatus)
             {
                 data.Played = true;
             }
+            else
+            {
+                data.Played = false;
+            }
 
             await _userDataManager.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackStart, CancellationToken.None).ConfigureAwait(false);
         }
@@ -847,11 +851,11 @@ namespace MediaBrowser.Server.Implementations.Session
                 {
                     playedToCompletion = _userDataManager.UpdatePlayState(item, data, positionTicks.Value);
                 }
-                else
+                else 
                 {
                     // If the client isn't able to report this, then we'll just have to make an assumption
                     data.PlayCount++;
-                    data.Played = true;
+                    data.Played = item.SupportsPlayedStatus;
                     data.PlaybackPositionTicks = 0;
                     playedToCompletion = true;
                 }

+ 2 - 2
Nuget/MediaBrowser.Common.Internal.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Common.Internal</id>
-        <version>3.0.661</version>
+        <version>3.0.662</version>
         <title>MediaBrowser.Common.Internal</title>
         <authors>Luke</authors>
         <owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
         <description>Contains common components shared by Emby Theater and Emby Server. Not intended for plugin developer consumption.</description>
         <copyright>Copyright © Emby 2013</copyright>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.661" />
+            <dependency id="MediaBrowser.Common" version="3.0.662" />
             <dependency id="NLog" version="4.3.8" />
             <dependency id="SimpleInjector" version="3.2.2" />
         </dependencies>

+ 1 - 1
Nuget/MediaBrowser.Common.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Common</id>
-        <version>3.0.661</version>
+        <version>3.0.662</version>
         <title>MediaBrowser.Common</title>
         <authors>Emby Team</authors>
         <owners>ebr,Luke,scottisafool</owners>

+ 2 - 2
Nuget/MediaBrowser.Server.Core.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Server.Core</id>
-        <version>3.0.661</version>
+        <version>3.0.662</version>
         <title>Media Browser.Server.Core</title>
         <authors>Emby Team</authors>
         <owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
         <description>Contains core components required to build plugins for Emby Server.</description>
         <copyright>Copyright © Emby 2013</copyright>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.661" />
+            <dependency id="MediaBrowser.Common" version="3.0.662" />
 			<dependency id="Interfaces.IO" version="1.0.0.5" />
         </dependencies>
     </metadata>