diff --git a/Emby.Common.Implementations/Networking/NetworkManager.cs b/Emby.Common.Implementations/Networking/NetworkManager.cs index 2b84b2aa18..2f218656c9 100644 --- a/Emby.Common.Implementations/Networking/NetworkManager.cs +++ b/Emby.Common.Implementations/Networking/NetworkManager.cs @@ -500,11 +500,7 @@ namespace Emby.Common.Implementations.Networking { return IpAddressInfo.IPv6Loopback; } - return new IpAddressInfo - { - Address = address.ToString(), - AddressFamily = address.AddressFamily == AddressFamily.InterNetworkV6 ? IpAddressFamily.InterNetworkV6 : IpAddressFamily.InterNetwork - }; + return new IpAddressInfo(address.ToString(), address.AddressFamily == AddressFamily.InterNetworkV6 ? IpAddressFamily.InterNetworkV6 : IpAddressFamily.InterNetwork); } public async Task GetHostAddressesAsync(string host) diff --git a/Emby.Server.Implementations/FileOrganization/TvFolderOrganizer.cs b/Emby.Server.Implementations/FileOrganization/TvFolderOrganizer.cs index b035fdcfd5..807f1694cc 100644 --- a/Emby.Server.Implementations/FileOrganization/TvFolderOrganizer.cs +++ b/Emby.Server.Implementations/FileOrganization/TvFolderOrganizer.cs @@ -72,17 +72,24 @@ namespace Emby.Server.Implementations.FileOrganization foreach (var file in eligibleFiles) { + cancellationToken.ThrowIfCancellationRequested(); + var organizer = new EpisodeFileOrganizer(_organizationService, _config, _fileSystem, _logger, _libraryManager, _libraryMonitor, _providerManager); try { var result = await organizer.OrganizeEpisodeFile(file.FullName, options, options.TvOptions.OverwriteExistingEpisodes, cancellationToken).ConfigureAwait(false); + if (result.Status == FileSortingStatus.Success && !processedFolders.Contains(file.DirectoryName, StringComparer.OrdinalIgnoreCase)) { processedFolders.Add(file.DirectoryName); } } + catch (OperationCanceledException) + { + break; + } catch (Exception ex) { _logger.ErrorException("Error organizing episode {0}", ex, file.FullName); diff --git a/Emby.Server.Implementations/LiveTv/LiveStreamHelper.cs b/Emby.Server.Implementations/LiveTv/LiveStreamHelper.cs index 9a8a930bde..3906df0005 100644 --- a/Emby.Server.Implementations/LiveTv/LiveStreamHelper.cs +++ b/Emby.Server.Implementations/LiveTv/LiveStreamHelper.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; namespace Emby.Server.Implementations.LiveTv @@ -29,6 +30,8 @@ namespace Emby.Server.Implementations.LiveTv var now = DateTime.UtcNow; + var allowVideoStreamCopy = mediaSource.MediaStreams.Any(i => i.Type == MediaStreamType.Video && i.AllowStreamCopy); + var info = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest { InputPath = mediaSource.Path, @@ -73,6 +76,8 @@ namespace Emby.Server.Implementations.LiveTv var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaBrowser.Model.Entities.MediaStreamType.Video); if (videoStream != null) { + videoStream.AllowStreamCopy = allowVideoStreamCopy; + if (!videoStream.BitRate.HasValue) { var width = videoStream.Width ?? 1920; diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index b9e73b62ed..1c43b41882 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -261,7 +261,7 @@ namespace Emby.Server.Implementations.LiveTv return info.Item1; } - public Task> GetChannelStream(string id, string mediaSourceId, CancellationToken cancellationToken) + public Task> GetChannelStream(string id, string mediaSourceId, CancellationToken cancellationToken) { return GetLiveStream(id, mediaSourceId, true, cancellationToken); } @@ -323,7 +323,7 @@ namespace Emby.Server.Implementations.LiveTv return _services.FirstOrDefault(i => string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase)); } - private async Task> GetLiveStream(string id, string mediaSourceId, bool isChannel, CancellationToken cancellationToken) + private async Task> GetLiveStream(string id, string mediaSourceId, bool isChannel, CancellationToken cancellationToken) { if (string.Equals(id, mediaSourceId, StringComparison.OrdinalIgnoreCase)) { @@ -334,7 +334,6 @@ namespace Emby.Server.Implementations.LiveTv bool isVideo; ILiveTvService service; IDirectStreamProvider directStreamProvider = null; - var assumeInterlaced = false; if (isChannel) { @@ -383,12 +382,7 @@ namespace Emby.Server.Implementations.LiveTv Normalize(info, service, isVideo); - if (!(service is EmbyTV.EmbyTV)) - { - assumeInterlaced = true; - } - - return new Tuple(info, directStreamProvider, assumeInterlaced); + return new Tuple(info, directStreamProvider); } private void Normalize(MediaSourceInfo mediaSource, ILiveTvService service, bool isVideo) @@ -492,6 +486,12 @@ namespace Emby.Server.Implementations.LiveTv { stream.NalLengthSize = "0"; } + + if (stream.Type == MediaStreamType.Video) + { + stream.IsInterlaced = true; + stream.AllowStreamCopy = false; + } } } } diff --git a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs index 747e0fdd31..a9c449f837 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs @@ -104,7 +104,7 @@ namespace Emby.Server.Implementations.LiveTv openKeys.Add(item.Id.ToString("N")); openKeys.Add(source.Id ?? string.Empty); source.OpenToken = string.Join(StreamIdDelimeterString, openKeys.ToArray()); - } + } // Dummy this up so that direct play checks can still run if (string.IsNullOrEmpty(source.Path) && source.Protocol == MediaProtocol.Http) @@ -142,7 +142,7 @@ namespace Emby.Server.Implementations.LiveTv { if (!stream.SupportsProbing || stream.MediaStreams.Any(i => i.Index != -1)) { - await AddMediaInfo(stream, isAudio, cancellationToken).ConfigureAwait(false); + AddMediaInfo(stream, isAudio, cancellationToken); } else { @@ -158,7 +158,7 @@ namespace Emby.Server.Implementations.LiveTv return new Tuple(stream, directStreamProvider); } - private async Task AddMediaInfo(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken) + private void AddMediaInfo(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken) { mediaSource.DefaultSubtitleStreamIndex = null; diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 5242c5b1f2..c8fa6be8ce 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -157,7 +157,7 @@ namespace MediaBrowser.Controller.LiveTv /// The media source identifier. /// The cancellation token. /// Task{StreamResponseInfo}. - Task> GetChannelStream(string id, string mediaSourceId, CancellationToken cancellationToken); + Task> GetChannelStream(string id, string mediaSourceId, CancellationToken cancellationToken); /// /// Gets the program. diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 530ff13430..dd31d39b10 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -743,6 +743,11 @@ namespace MediaBrowser.Controller.MediaEncoding public bool CanStreamCopyVideo(EncodingJobInfo state, MediaStream videoStream) { + if (!videoStream.AllowStreamCopy) + { + return false; + } + var request = state.BaseRequest; if (videoStream.IsInterlaced) @@ -883,6 +888,11 @@ namespace MediaBrowser.Controller.MediaEncoding public bool CanStreamCopyAudio(EncodingJobInfo state, MediaStream audioStream, List supportedAudioCodecs) { + if (!audioStream.AllowStreamCopy) + { + return false; + } + var request = state.BaseRequest; // Source and target codecs must match diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index 3cd3e7dde9..133b9e5663 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -13,6 +13,11 @@ namespace MediaBrowser.Model.Entities [DebuggerDisplay("StreamType = {Type}")] public class MediaStream { + public MediaStream() + { + AllowStreamCopy = true; + } + /// /// Gets or sets the codec. /// @@ -153,6 +158,8 @@ namespace MediaBrowser.Model.Entities public bool? IsAVC { get; set; } + public bool AllowStreamCopy { get; set; } + /// /// Gets or sets the channel layout. /// diff --git a/MediaBrowser.Model/Net/IpAddressInfo.cs b/MediaBrowser.Model/Net/IpAddressInfo.cs index 00a16c03df..57a0039c43 100644 --- a/MediaBrowser.Model/Net/IpAddressInfo.cs +++ b/MediaBrowser.Model/Net/IpAddressInfo.cs @@ -12,13 +12,13 @@ namespace MediaBrowser.Model.Net public string Address { get; set; } public IpAddressFamily AddressFamily { get; set; } - public IpAddressInfo() - { - - } - public IpAddressInfo(string address, IpAddressFamily addressFamily) { + if (string.IsNullOrWhiteSpace(address)) + { + throw new ArgumentNullException("address"); + } + Address = address; AddressFamily = addressFamily; } diff --git a/RSSDP/SsdpCommunicationsServer.cs b/RSSDP/SsdpCommunicationsServer.cs index cc464e689c..e9dc4c54f7 100644 --- a/RSSDP/SsdpCommunicationsServer.cs +++ b/RSSDP/SsdpCommunicationsServer.cs @@ -247,10 +247,7 @@ namespace Rssdp.Infrastructure { await SendMessageIfSocketNotDisposed(messageData, new IpEndPointInfo { - IpAddress = new IpAddressInfo - { - Address = SsdpConstants.MulticastLocalAdminAddress - }, + IpAddress = new IpAddressInfo(SsdpConstants.MulticastLocalAdminAddress, IpAddressFamily.InterNetwork), Port = SsdpConstants.MulticastPort }, cancellationToken).ConfigureAwait(false);