Kaynağa Gözat

improve live tv direct play

Luke Pulverenti 7 yıl önce
ebeveyn
işleme
164e7dc896

+ 7 - 2
Emby.Server.Implementations/ApplicationHost.cs

@@ -792,6 +792,11 @@ namespace Emby.Server.Implementations
 
         protected abstract IConnectManager CreateConnectManager();
         protected abstract ISyncManager CreateSyncManager();
+        
+        protected virtual IHttpClient CreateHttpClient()
+        {
+            return new HttpClientManager.HttpClientManager(ApplicationPaths, LogManager.GetLogger("HttpClient"), FileSystemManager, MemoryStreamFactory, GetDefaultUserAgent);
+        }
 
         /// <summary>
         /// Registers resources that classes will depend on
@@ -814,7 +819,7 @@ namespace Emby.Server.Implementations
 
             RegisterSingleInstance(FileSystemManager);
 
-            HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, LogManager.GetLogger("HttpClient"), FileSystemManager, MemoryStreamFactory, GetDefaultUserAgent);
+            HttpClient = CreateHttpClient();
             RegisterSingleInstance(HttpClient);
 
             RegisterSingleInstance(NetworkManager);
@@ -1118,7 +1123,7 @@ namespace Emby.Server.Implementations
             IsoManager.AddParts(list);
         }
 
-        private string GetDefaultUserAgent()
+        protected string GetDefaultUserAgent()
         {
             var name = FormatAttribute(Name);
 

+ 12 - 4
Emby.Server.Implementations/Devices/SqliteDeviceRepository.cs

@@ -72,10 +72,18 @@ namespace Emby.Server.Implementations.Devices
 
         private void MigrateDevices()
         {
-            var files = FileSystem
-                    .GetFilePaths(GetDevicesPath(), true)
-                    .Where(i => string.Equals(Path.GetFileName(i), "device.json", StringComparison.OrdinalIgnoreCase))
-                    .ToList();
+            List<string> files;
+            try
+            {
+                files = FileSystem
+                       .GetFilePaths(GetDevicesPath(), true)
+                       .Where(i => string.Equals(Path.GetFileName(i), "device.json", StringComparison.OrdinalIgnoreCase))
+                       .ToList();
+            }
+            catch (IOException)
+            {
+                return;
+            }
 
             foreach (var file in files)
             {

+ 2 - 0
Emby.Server.Implementations/HttpClientManager/HttpClientInfo.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Net.Http;
 
 namespace Emby.Server.Implementations.HttpClientManager
 {
@@ -12,5 +13,6 @@ namespace Emby.Server.Implementations.HttpClientManager
         /// </summary>
         /// <value>The last timeout.</value>
         public DateTime LastTimeout { get; set; }
+        public HttpClient HttpClient { get; set; }
     }
 }

+ 6 - 7
Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs

@@ -22,7 +22,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
         private readonly IHttpClient _httpClient;
         private readonly IServerApplicationHost _appHost;
 
-        private readonly CancellationTokenSource _liveStreamCancellationTokenSource = new CancellationTokenSource();
         private readonly TaskCompletionSource<bool> _liveStreamTaskCompletionSource = new TaskCompletionSource<bool>();
 
         public HdHomerunHttpStream(MediaSourceInfo mediaSource, string originalStreamId, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, IEnvironmentInfo environment)
@@ -35,7 +34,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
 
         protected override Task OpenInternal(CancellationToken openCancellationToken)
         {
-            _liveStreamCancellationTokenSource.Token.ThrowIfCancellationRequested();
+            LiveStreamCancellationTokenSource.Token.ThrowIfCancellationRequested();
 
             var mediaSource = OriginalMediaSource;
 
@@ -45,7 +44,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
 
             var taskCompletionSource = new TaskCompletionSource<bool>();
 
-            StartStreaming(url, taskCompletionSource, _liveStreamCancellationTokenSource.Token);
+            StartStreaming(url, taskCompletionSource, LiveStreamCancellationTokenSource.Token);
 
             //OpenedMediaSource.Protocol = MediaProtocol.File;
             //OpenedMediaSource.Path = tempFile;
@@ -65,12 +64,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
             //await Task.Delay(5000).ConfigureAwait(false);
         }
 
-        public override Task Close()
+        public override async Task Close()
         {
             Logger.Info("Closing HDHR live stream");
-            _liveStreamCancellationTokenSource.Cancel();
+            LiveStreamCancellationTokenSource.Cancel();
 
-            return _liveStreamTaskCompletionSource.Task;
+            await _liveStreamTaskCompletionSource.Task.ConfigureAwait(false);
+            await DeleteTempFile(TempFilePath).ConfigureAwait(false);
         }
 
         private Task StartStreaming(string url, TaskCompletionSource<bool> openTaskCompletionSource, CancellationToken cancellationToken)
@@ -112,7 +112,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
                 }
 
                 _liveStreamTaskCompletionSource.TrySetResult(true);
-                await DeleteTempFile(TempFilePath).ConfigureAwait(false);
             });
         }
 

+ 3 - 4
Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs

@@ -26,7 +26,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
         private readonly IServerApplicationHost _appHost;
         private readonly ISocketFactory _socketFactory;
 
-        private readonly CancellationTokenSource _liveStreamCancellationTokenSource = new CancellationTokenSource();
         private readonly TaskCompletionSource<bool> _liveStreamTaskCompletionSource = new TaskCompletionSource<bool>();
         private readonly IHdHomerunChannelCommands _channelCommands;
         private readonly int _numTuners;
@@ -45,7 +44,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
 
         protected override Task OpenInternal(CancellationToken openCancellationToken)
         {
-            _liveStreamCancellationTokenSource.Token.ThrowIfCancellationRequested();
+            LiveStreamCancellationTokenSource.Token.ThrowIfCancellationRequested();
 
             var mediaSource = OriginalMediaSource;
 
@@ -56,7 +55,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
 
             var taskCompletionSource = new TaskCompletionSource<bool>();
 
-            StartStreaming(uri.Host, localPort, taskCompletionSource, _liveStreamCancellationTokenSource.Token);
+            StartStreaming(uri.Host, localPort, taskCompletionSource, LiveStreamCancellationTokenSource.Token);
 
             //OpenedMediaSource.Protocol = MediaProtocol.File;
             //OpenedMediaSource.Path = tempFile;
@@ -76,7 +75,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
         public override Task Close()
         {
             Logger.Info("Closing HDHR UDP live stream");
-            _liveStreamCancellationTokenSource.Cancel();
+            LiveStreamCancellationTokenSource.Cancel();
 
             return _liveStreamTaskCompletionSource.Task;
         }

+ 26 - 8
Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs

@@ -32,6 +32,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
 
         protected readonly string TempFilePath;
         protected readonly ILogger Logger;
+        protected readonly CancellationTokenSource LiveStreamCancellationTokenSource = new CancellationTokenSource();
 
         public LiveStream(MediaSourceInfo mediaSource, IEnvironmentInfo environment, IFileSystem fileSystem, ILogger logger, IServerApplicationPaths appPaths)
         {
@@ -80,6 +81,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
                 FileSystem.DeleteFile(path);
                 return;
             }
+            catch (DirectoryNotFoundException)
+            {
+                return;
+            }
+            catch (FileNotFoundException)
+            {
+                return;
+            }
             catch
             {
 
@@ -96,6 +105,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
 
         public async Task CopyToAsync(Stream stream, CancellationToken cancellationToken)
         {
+            cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, LiveStreamCancellationTokenSource.Token).Token;
+
             var allowAsync = false;//Environment.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows;
             // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
 
@@ -110,16 +121,27 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
         private static async Task CopyTo(Stream source, Stream destination, int bufferSize, Action onStarted, CancellationToken cancellationToken)
         {
             byte[] buffer = new byte[bufferSize];
-            while (true)
+
+            var eofCount = 0;
+            var emptyReadLimit = 1000;
+
+            while (eofCount < emptyReadLimit)
             {
                 cancellationToken.ThrowIfCancellationRequested();
 
-                var read = source.Read(buffer, 0, buffer.Length);
+                var bytesRead = source.Read(buffer, 0, buffer.Length);
 
-                if (read > 0)
+                if (bytesRead == 0)
+                {
+                    eofCount++;
+                    await Task.Delay(10, cancellationToken).ConfigureAwait(false);
+                }
+                else
                 {
+                    eofCount = 0;
+
                     //await destination.WriteAsync(buffer, 0, read).ConfigureAwait(false);
-                    destination.Write(buffer, 0, read);
+                    destination.Write(buffer, 0, bytesRead);
 
                     if (onStarted != null)
                     {
@@ -127,10 +149,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
                         onStarted = null;
                     }
                 }
-                else
-                {
-                    await Task.Delay(10).ConfigureAwait(false);
-                }
             }
         }
 

+ 2 - 2
MediaBrowser.Api/LiveTv/LiveTvService.cs

@@ -734,7 +734,7 @@ namespace MediaBrowser.Api.LiveTv
 
             outputHeaders["Content-Type"] = Model.Net.MimeTypes.GetMimeType(path);
 
-            return new ProgressiveFileCopier(_fileSystem, path, outputHeaders, Logger, _environment, CancellationToken.None)
+            return new ProgressiveFileCopier(_fileSystem, path, outputHeaders, Logger, _environment)
             {
                 AllowEndOfFile = false
             };
@@ -753,7 +753,7 @@ namespace MediaBrowser.Api.LiveTv
 
             outputHeaders["Content-Type"] = Model.Net.MimeTypes.GetMimeType("file." + request.Container);
 
-            return new ProgressiveFileCopier(directStreamProvider, outputHeaders, Logger, _environment, CancellationToken.None)
+            return new ProgressiveFileCopier(directStreamProvider, outputHeaders, Logger, _environment)
             {
                 AllowEndOfFile = false
             };

+ 5 - 8
MediaBrowser.Api/LiveTv/ProgressiveFileCopier.cs

@@ -16,7 +16,6 @@ namespace MediaBrowser.Api.LiveTv
         private readonly IFileSystem _fileSystem;
         private readonly ILogger _logger;
         private readonly string _path;
-        private readonly CancellationToken _cancellationToken;
         private readonly Dictionary<string, string> _outputHeaders;
 
         const int StreamCopyToBufferSize = 81920;
@@ -28,22 +27,20 @@ namespace MediaBrowser.Api.LiveTv
         private readonly IDirectStreamProvider _directStreamProvider;
         private readonly IEnvironmentInfo _environment;
 
-        public ProgressiveFileCopier(IFileSystem fileSystem, string path, Dictionary<string, string> outputHeaders, ILogger logger, IEnvironmentInfo environment, CancellationToken cancellationToken)
+        public ProgressiveFileCopier(IFileSystem fileSystem, string path, Dictionary<string, string> outputHeaders, ILogger logger, IEnvironmentInfo environment)
         {
             _fileSystem = fileSystem;
             _path = path;
             _outputHeaders = outputHeaders;
             _logger = logger;
-            _cancellationToken = cancellationToken;
             _environment = environment;
         }
 
-        public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, Dictionary<string, string> outputHeaders, ILogger logger, IEnvironmentInfo environment, CancellationToken cancellationToken)
+        public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, Dictionary<string, string> outputHeaders, ILogger logger, IEnvironmentInfo environment)
         {
             _directStreamProvider = directStreamProvider;
             _outputHeaders = outputHeaders;
             _logger = logger;
-            _cancellationToken = cancellationToken;
             _environment = environment;
         }
 
@@ -69,8 +66,6 @@ namespace MediaBrowser.Api.LiveTv
 
         public async Task WriteToAsync(Stream outputStream, CancellationToken cancellationToken)
         {
-            cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationToken).Token;
-
             if (_directStreamProvider != null)
             {
                 await _directStreamProvider.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false);
@@ -89,7 +84,9 @@ namespace MediaBrowser.Api.LiveTv
                     inputStream.Position = StartPosition;
                 }
 
-                while (eofCount < 20 || !AllowEndOfFile)
+                var emptyReadLimit = AllowEndOfFile ? 20 : 100;
+
+                while (eofCount < emptyReadLimit)
                 {
                     int bytesRead;
                     if (allowAsyncFileRead)

+ 47 - 19
MediaBrowser.Providers/Manager/MetadataService.cs

@@ -13,6 +13,7 @@ using System.Threading.Tasks;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Providers;
+using MediaBrowser.Providers.MediaInfo;
 
 namespace MediaBrowser.Providers.Manager
 {
@@ -37,6 +38,28 @@ namespace MediaBrowser.Providers.Manager
             LibraryManager = libraryManager;
         }
 
+        private bool RequiresRefresh(IHasMetadata item, IDirectoryService directoryService)
+        {
+            if (item.RequiresRefresh())
+            {
+                return true;
+            }
+
+            if (item.SupportsLocalMetadata)
+            {
+                var video = item as Video;
+
+                if (video != null && !video.IsPlaceHolder)
+                {
+                    return !video.SubtitleFiles
+                        .SequenceEqual(SubtitleResolver.GetSubtitleFiles(video, directoryService, FileSystem, false)
+                        .OrderBy(i => i), StringComparer.OrdinalIgnoreCase);
+                }
+            }
+
+            return false;
+        }
+
         public async Task<ItemUpdateType> RefreshMetadata(IHasMetadata item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken)
         {
             var itemOfType = (TItemType)item;
@@ -47,19 +70,35 @@ namespace MediaBrowser.Providers.Manager
 
             var libraryOptions = LibraryManager.GetLibraryOptions((BaseItem)item);
 
-            if (refreshOptions.MetadataRefreshMode != MetadataRefreshMode.None)
+            DateTime? newDateModified = null;
+            if (item.LocationType == LocationType.FileSystem)
             {
-                // TODO: If this returns true, should we instead just change metadata refresh mode to Full?
-                requiresRefresh = item.RequiresRefresh();
+                var file = refreshOptions.DirectoryService.GetFile(item.Path);
+                if (file != null)
+                {
+                    newDateModified = file.LastWriteTimeUtc;
+                    if (item.EnableRefreshOnDateModifiedChange)
+                    {
+                        if (newDateModified != item.DateModified)
+                        {
+                            Logger.Debug("Date modified for {0}. Old date {1} new date {2} Id {3}", item.Path, item.DateModified, newDateModified, item.Id);
+                            requiresRefresh = true;
+                        }
+                    }
+                }
             }
 
-            if (!requiresRefresh &&
-                libraryOptions.AutomaticRefreshIntervalDays > 0 &&
-                (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= libraryOptions.AutomaticRefreshIntervalDays)
+            if (!requiresRefresh && libraryOptions.AutomaticRefreshIntervalDays > 0 && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= libraryOptions.AutomaticRefreshIntervalDays)
             {
                 requiresRefresh = true;
             }
 
+            if (!requiresRefresh && refreshOptions.MetadataRefreshMode != MetadataRefreshMode.None)
+            {
+                // TODO: If this returns true, should we instead just change metadata refresh mode to Full?
+                requiresRefresh = RequiresRefresh(item, refreshOptions.DirectoryService);
+            }
+
             var itemImageProvider = new ItemImageProvider(Logger, ProviderManager, ServerConfigurationManager, FileSystem);
             var localImagesFailed = false;
 
@@ -145,20 +184,9 @@ namespace MediaBrowser.Providers.Manager
             var beforeSaveResult = BeforeSave(itemOfType, isFirstRefresh || refreshOptions.ReplaceAllMetadata || refreshOptions.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || requiresRefresh, updateType);
             updateType = updateType | beforeSaveResult;
 
-            if (item.LocationType == LocationType.FileSystem)
+            if (newDateModified.HasValue)
             {
-                var file = refreshOptions.DirectoryService.GetFile(item.Path);
-                if (file != null)
-                {
-                    var fileLastWriteTime = file.LastWriteTimeUtc;
-                    if (item.EnableRefreshOnDateModifiedChange && fileLastWriteTime != item.DateModified)
-                    {
-                        Logger.Debug("Date modified for {0}. Old date {1} new date {2} Id {3}", item.Path, item.DateModified, fileLastWriteTime, item.Id);
-                        requiresRefresh = true;
-                    }
-
-                    item.DateModified = fileLastWriteTime;
-                }
+                item.DateModified = newDateModified.Value;
             }
 
             // Save if changes were made, or it's never been saved before

+ 0 - 4
MediaBrowser.Providers/TV/MissingEpisodeProvider.cs

@@ -350,8 +350,6 @@ namespace MediaBrowser.Providers.TV
 
             foreach (var episodeToRemove in episodesToRemove.Select(e => e.Episode))
             {
-                _logger.Info("Removing missing/unaired episode {0} {1}x{2}", episodeToRemove.Series.Name, episodeToRemove.ParentIndexNumber, episodeToRemove.IndexNumber);
-
                 await episodeToRemove.Delete(new DeleteOptions
                 {
                     DeleteFileLocation = true
@@ -418,8 +416,6 @@ namespace MediaBrowser.Providers.TV
 
             foreach (var seasonToRemove in seasonsToRemove)
             {
-                _logger.Info("Removing virtual season {0} {1}", seasonToRemove.Series.Name, seasonToRemove.IndexNumber);
-
                 await seasonToRemove.Delete(new DeleteOptions
                 {
                     DeleteFileLocation = true