diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index fb4bd9244..7f41cb059 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -2329,7 +2329,8 @@ namespace MediaBrowser.Api.Playback state.TargetRefFrames, state.TargetVideoStreamCount, state.TargetAudioStreamCount, - state.TargetVideoCodecTag); + state.TargetVideoCodecTag, + state.IsTargetAVC); if (mediaProfile != null) { @@ -2547,7 +2548,8 @@ namespace MediaBrowser.Api.Playback state.TargetRefFrames, state.TargetVideoStreamCount, state.TargetAudioStreamCount, - state.TargetVideoCodecTag + state.TargetVideoCodecTag, + state.IsTargetAVC ).FirstOrDefault() ?? string.Empty; } diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index 019f378c5..863bc0193 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -516,5 +516,18 @@ namespace MediaBrowser.Api.Playback return false; } } + + public bool? IsTargetAVC + { + get + { + if (Request.Static) + { + return VideoStream == null ? null : VideoStream.IsAVC; + } + + return true; + } + } } } diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 60af2c56a..89fe71d3c 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -154,6 +154,9 @@ namespace MediaBrowser.Controller.Entities public List> OrderBy { get; set; } + public DateTime? MinDateCreated { get; set; } + public DateTime? MinDateLastSaved { get; set; } + public InternalItemsQuery() { GroupByPresentationUniqueKey = true; diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs index 84c1b3bde..f53dec3bf 100644 --- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs +++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs @@ -177,7 +177,8 @@ namespace MediaBrowser.Dlna.Didl streamInfo.TargetRefFrames, streamInfo.TargetVideoStreamCount, streamInfo.TargetAudioStreamCount, - streamInfo.TargetVideoCodecTag); + streamInfo.TargetVideoCodecTag, + streamInfo.IsTargetAVC); foreach (var contentFeature in contentFeatureList) { @@ -322,7 +323,8 @@ namespace MediaBrowser.Dlna.Didl streamInfo.TargetRefFrames, streamInfo.TargetVideoStreamCount, streamInfo.TargetAudioStreamCount, - streamInfo.TargetVideoCodecTag); + streamInfo.TargetVideoCodecTag, + streamInfo.IsTargetAVC); var filename = url.Substring(0, url.IndexOf('?')); diff --git a/MediaBrowser.Dlna/PlayTo/PlayToController.cs b/MediaBrowser.Dlna/PlayTo/PlayToController.cs index 6345e2105..f6b24e615 100644 --- a/MediaBrowser.Dlna/PlayTo/PlayToController.cs +++ b/MediaBrowser.Dlna/PlayTo/PlayToController.cs @@ -540,7 +540,8 @@ namespace MediaBrowser.Dlna.PlayTo streamInfo.TargetRefFrames, streamInfo.TargetVideoStreamCount, streamInfo.TargetAudioStreamCount, - streamInfo.TargetVideoCodecTag); + streamInfo.TargetVideoCodecTag, + streamInfo.IsTargetAVC); return list.FirstOrDefault(); } diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs index d3738d903..0c7ff1b76 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs @@ -392,6 +392,19 @@ namespace MediaBrowser.MediaEncoding.Encoder } } + public bool? IsTargetAVC + { + get + { + if (Options.Static) + { + return VideoStream == null ? null : VideoStream.IsAVC; + } + + return false; + } + } + public int? TargetVideoStreamCount { get diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs index c72532669..b66a3ed96 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs @@ -823,7 +823,8 @@ namespace MediaBrowser.MediaEncoding.Encoder state.TargetRefFrames, state.TargetVideoStreamCount, state.TargetAudioStreamCount, - state.TargetVideoCodecTag); + state.TargetVideoCodecTag, + state.IsTargetAVC); if (mediaProfile != null) { diff --git a/MediaBrowser.Model/Dlna/ConditionProcessor.cs b/MediaBrowser.Model/Dlna/ConditionProcessor.cs index 69f1369dc..ec13cacfa 100644 --- a/MediaBrowser.Model/Dlna/ConditionProcessor.cs +++ b/MediaBrowser.Model/Dlna/ConditionProcessor.cs @@ -20,12 +20,15 @@ namespace MediaBrowser.Model.Dlna int? refFrames, int? numVideoStreams, int? numAudioStreams, - string videoCodecTag) + string videoCodecTag, + bool? isAvc) { switch (condition.Property) { case ProfileConditionValue.IsAnamorphic: return IsConditionSatisfied(condition, isAnamorphic); + case ProfileConditionValue.IsAvc: + return IsConditionSatisfied(condition, isAvc); case ProfileConditionValue.VideoFramerate: return IsConditionSatisfied(condition, videoFramerate); case ProfileConditionValue.VideoLevel: diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs index c4b3383a2..4a16a2780 100644 --- a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs +++ b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs @@ -118,7 +118,8 @@ namespace MediaBrowser.Model.Dlna int? refFrames, int? numVideoStreams, int? numAudioStreams, - string videoCodecTag) + string videoCodecTag, + bool? isAvc) { // first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none string orgOp = ";DLNA.ORG_OP=" + DlnaMaps.GetOrgOpValue(runtimeTicks.HasValue, isDirectStream, transcodeSeekInfo); @@ -159,7 +160,8 @@ namespace MediaBrowser.Model.Dlna refFrames, numVideoStreams, numAudioStreams, - videoCodecTag); + videoCodecTag, + isAvc); List orgPnValues = new List(); diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs index d6a322322..884a9f29d 100644 --- a/MediaBrowser.Model/Dlna/DeviceProfile.cs +++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs @@ -285,7 +285,8 @@ namespace MediaBrowser.Model.Dlna int? refFrames, int? numVideoStreams, int? numAudioStreams, - string videoCodecTag) + string videoCodecTag, + bool? isAvc) { container = StringHelper.TrimStart(container ?? string.Empty, '.'); @@ -319,7 +320,7 @@ namespace MediaBrowser.Model.Dlna var anyOff = false; foreach (ProfileCondition c in i.Conditions) { - if (!conditionProcessor.IsVideoConditionSatisfied(c, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag)) + if (!conditionProcessor.IsVideoConditionSatisfied(c, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)) { anyOff = true; break; diff --git a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs index c17a09c3f..7e2002f17 100644 --- a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs +++ b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs @@ -20,6 +20,7 @@ NumAudioStreams = 16, NumVideoStreams = 17, IsSecondaryAudio = 18, - VideoCodecTag = 19 + VideoCodecTag = 19, + IsAvc = 20 } } \ No newline at end of file diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 30d1498bf..52b7fd43a 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -541,6 +541,7 @@ namespace MediaBrowser.Model.Dlna float? videoFramerate = videoStream == null ? null : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate; bool? isAnamorphic = videoStream == null ? null : videoStream.IsAnamorphic; string videoCodecTag = videoStream == null ? null : videoStream.CodecTag; + bool? isAvc = videoStream == null ? null : videoStream.IsAVC; TransportStreamTimestamp? timestamp = videoStream == null ? TransportStreamTimestamp.None : item.Timestamp; int? packetLength = videoStream == null ? null : videoStream.PacketLength; @@ -549,7 +550,7 @@ namespace MediaBrowser.Model.Dlna int? numAudioStreams = item.GetStreamCount(MediaStreamType.Audio); int? numVideoStreams = item.GetStreamCount(MediaStreamType.Video); - if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag)) + if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)) { LogConditionFailure(options.Profile, "VideoCodecProfile", applyCondition, item); applyConditions = false; @@ -718,6 +719,7 @@ namespace MediaBrowser.Model.Dlna float? videoFramerate = videoStream == null ? null : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate; bool? isAnamorphic = videoStream == null ? null : videoStream.IsAnamorphic; string videoCodecTag = videoStream == null ? null : videoStream.CodecTag; + bool? isAvc = videoStream == null ? null : videoStream.IsAVC; int? audioBitrate = audioStream == null ? null : audioStream.BitRate; int? audioChannels = audioStream == null ? null : audioStream.Channels; @@ -733,7 +735,7 @@ namespace MediaBrowser.Model.Dlna // Check container conditions foreach (ProfileCondition i in conditions) { - if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag)) + if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)) { LogConditionFailure(profile, "VideoContainerProfile", i, mediaSource); @@ -760,7 +762,7 @@ namespace MediaBrowser.Model.Dlna bool applyConditions = true; foreach (ProfileCondition applyCondition in i.ApplyConditions) { - if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag)) + if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)) { LogConditionFailure(profile, "VideoCodecProfile", applyCondition, mediaSource); applyConditions = false; @@ -780,7 +782,7 @@ namespace MediaBrowser.Model.Dlna foreach (ProfileCondition i in conditions) { - if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag)) + if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)) { LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource); diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index f7dc893c8..c9cb873e1 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -676,6 +676,19 @@ namespace MediaBrowser.Model.Dlna } } + public bool? IsTargetAVC + { + get + { + if (IsDirectStream) + { + return TargetVideoStream == null ? null : TargetVideoStream.IsAVC; + } + + return true; + } + } + public int? TargetWidth { get diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 3de330557..36b5987a0 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -211,6 +211,20 @@ namespace MediaBrowser.Providers.Manager throw; } } + catch (IOException ex) + { + var retry = !string.IsNullOrWhiteSpace(retryPath) && + !string.Equals(path, retryPath, StringComparison.OrdinalIgnoreCase); + + if (retry) + { + _logger.Error("IOException saving to {0}. {2}. Will retry saving to {1}", path, retryPath, ex.Message); + } + else + { + throw; + } + } source.Position = 0; await SaveImageToLocation(source, retryPath, cancellationToken).ConfigureAwait(false); diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 3db764ae1..4530bfcb6 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -606,15 +606,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV ActiveRecordingInfo activeRecordingInfo; if (!_activeRecordings.TryGetValue(updatedTimer.Id, out activeRecordingInfo)) { - UpdateExistingTimerWithNewData(existingTimer, updatedTimer); - - _timerProvider.Update(existingTimer); + existingTimer.PrePaddingSeconds = updatedTimer.PrePaddingSeconds; + existingTimer.PostPaddingSeconds = updatedTimer.PostPaddingSeconds; + existingTimer.IsPostPaddingRequired = updatedTimer.IsPostPaddingRequired; + existingTimer.IsPrePaddingRequired = updatedTimer.IsPrePaddingRequired; } return Task.FromResult(true); } - private void UpdateExistingTimerWithNewData(TimerInfo existingTimer, TimerInfo updatedTimer) + private void UpdateExistingTimerWithNewMetadata(TimerInfo existingTimer, TimerInfo updatedTimer) { // Update the program info but retain the status existingTimer.ChannelId = updatedTimer.ChannelId; @@ -1430,7 +1431,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { SaveSeriesNfo(timer, recordingPath, seriesPath); } - else if (!timer.IsMovie || timer.IsSports) + else if (!timer.IsMovie || timer.IsSports || timer.IsNews) { SaveVideoNfo(timer, recordingPath); } @@ -1620,7 +1621,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV ActiveRecordingInfo activeRecordingInfo; if (!_activeRecordings.TryGetValue(timer.Id, out activeRecordingInfo)) { - UpdateExistingTimerWithNewData(existingTimer, timer); + UpdateExistingTimerWithNewMetadata(existingTimer, timer); if (ShouldCancelTimerForSeriesTimer(seriesTimer, timer)) { diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs index 2cdd0571b..d49e3f258 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs @@ -104,7 +104,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun Action onStarted = null; if (isFirstAttempt) { - onStarted = () => openTaskCompletionSource.TrySetResult(true); + onStarted = () => ResolveWhenExists(openTaskCompletionSource, tempFilePath, cancellationToken); } await DirectRecorder.CopyUntilCancelled(response.Content, outputStream, onStarted, cancellationToken).ConfigureAwait(false); } @@ -137,6 +137,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun }).ConfigureAwait(false); } + private async void ResolveWhenExists(TaskCompletionSource taskCompletionSource, string file, CancellationToken cancellationToken) + { + while (!File.Exists(file) && !cancellationToken.IsCancellationRequested) + { + await Task.Delay(50).ConfigureAwait(false); + } + + taskCompletionSource.TrySetResult(true); + } + private async void DeleteTempFile(string path) { for (var i = 0; i < 10; i++) diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index c843ab596..5a11742dc 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -2724,6 +2724,18 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.Parameters.Add(cmd, "@MinIndexNumber", DbType.Int32).Value = query.MinIndexNumber.Value; } + if (query.MinDateCreated.HasValue) + { + whereClauses.Add("DateCreated>=@MinDateCreated"); + cmd.Parameters.Add(cmd, "@MinDateCreated", DbType.DateTime).Value = query.MinDateCreated.Value; + } + + if (query.MinDateLastSaved.HasValue) + { + whereClauses.Add("DateLastSaved>=@MinDateLastSaved"); + cmd.Parameters.Add(cmd, "@MinDateLastSaved", DbType.DateTime).Value = query.MinDateLastSaved.Value; + } + //if (query.MinPlayers.HasValue) //{ // whereClauses.Add("Players>=@MinPlayers");