diff --git a/Emby.Common.Implementations/Net/NetAcceptSocket.cs b/Emby.Common.Implementations/Net/NetAcceptSocket.cs index 3721709e60..82e7e9b009 100644 --- a/Emby.Common.Implementations/Net/NetAcceptSocket.cs +++ b/Emby.Common.Implementations/Net/NetAcceptSocket.cs @@ -100,7 +100,7 @@ namespace Emby.Common.Implementations.Net #if NET46 public Task SendFile(string path, byte[] preBuffer, byte[] postBuffer, CancellationToken cancellationToken) { - var options = TransmitFileOptions.UseKernelApc; + var options = TransmitFileOptions.UseDefaultWorkerThread; var completionSource = new TaskCompletionSource(); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index f59772c458..1673c9150d 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -213,9 +213,11 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV var subtitleArgs = CopySubtitles ? " -codec:s copy" : " -sn"; - var outputParam = string.Equals(Path.GetExtension(targetFile), ".mp4", StringComparison.OrdinalIgnoreCase) ? - " -f mp4 -movflags frag_keyframe+empty_moov" : - string.Empty; + //var outputParam = string.Equals(Path.GetExtension(targetFile), ".mp4", StringComparison.OrdinalIgnoreCase) ? + // " -f mp4 -movflags frag_keyframe+empty_moov" : + // string.Empty; + + var outputParam = string.Empty; var commandLineArgs = string.Format("-i \"{0}\"{5} {2} -map_metadata -1 -threads 0 {3}{4}{6} -y \"{1}\"", inputTempFile, diff --git a/MediaBrowser.Api/SearchService.cs b/MediaBrowser.Api/SearchService.cs index b4ee923650..5c0f918d93 100644 --- a/MediaBrowser.Api/SearchService.cs +++ b/MediaBrowser.Api/SearchService.cs @@ -9,6 +9,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Search; using System.Linq; using System.Threading.Tasks; +using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.Services; namespace MediaBrowser.Api @@ -170,11 +171,11 @@ namespace MediaBrowser.Api MatchedTerm = hintInfo.MatchedTerm, DisplayMediaType = item.DisplayMediaType, RunTimeTicks = item.RunTimeTicks, - ProductionYear = item.ProductionYear + ProductionYear = item.ProductionYear, + ChannelId = item.ChannelId, + EndDate = item.EndDate }; - result.ChannelId = item.ChannelId; - var primaryImageTag = _imageProcessor.GetImageCacheTag(item, ImageType.Primary); if (primaryImageTag != null) @@ -186,12 +187,27 @@ namespace MediaBrowser.Api SetThumbImageInfo(result, item); SetBackdropImageInfo(result, item); + var program = item as LiveTvProgram; + if (program != null) + { + result.StartDate = program.StartDate; + } + var hasSeries = item as IHasSeries; if (hasSeries != null) { result.Series = hasSeries.SeriesName; } + var series = item as Series; + if (series != null) + { + if (series.Status.HasValue) + { + result.Status = series.Status.Value.ToString(); + } + } + var album = item as MusicAlbum; if (album != null) diff --git a/MediaBrowser.Model/Search/SearchHint.cs b/MediaBrowser.Model/Search/SearchHint.cs index cea15a2a78..3ca0eafe63 100644 --- a/MediaBrowser.Model/Search/SearchHint.cs +++ b/MediaBrowser.Model/Search/SearchHint.cs @@ -1,4 +1,6 @@ -namespace MediaBrowser.Model.Search +using System; + +namespace MediaBrowser.Model.Search { /// /// Class SearchHintResult @@ -94,13 +96,18 @@ /// /// The display type of the media. public string DisplayMediaType { get; set; } - + + public DateTime? StartDate { get; set; } + public DateTime? EndDate { get; set; } + /// /// Gets or sets the series. /// /// The series. public string Series { get; set; } + public string Status { get; set; } + /// /// Gets or sets the album. /// diff --git a/MediaBrowser.Providers/Manager/GenericPriorityQueue.cs b/MediaBrowser.Providers/Manager/GenericPriorityQueue.cs index 18998fd599..03bb0f68c9 100644 --- a/MediaBrowser.Providers/Manager/GenericPriorityQueue.cs +++ b/MediaBrowser.Providers/Manager/GenericPriorityQueue.cs @@ -243,14 +243,16 @@ namespace Priority_Queue /// If queue is empty, result is undefined /// O(log n) /// - public TItem Dequeue() + public bool TryDequeue(out TItem item) { -#if DEBUG if (_numNodes <= 0) { - throw new InvalidOperationException("Cannot call Dequeue() on an empty queue"); + item = default(TItem); + return false; } +#if DEBUG + if (!IsValidQueue()) { throw new InvalidOperationException("Queue has been corrupted (Did you update a node priority manually instead of calling UpdatePriority()?" + @@ -260,7 +262,8 @@ namespace Priority_Queue TItem returnMe = _nodes[1]; Remove(returnMe); - return returnMe; + item = returnMe; + return true; } /// diff --git a/MediaBrowser.Providers/Manager/IPriorityQueue.cs b/MediaBrowser.Providers/Manager/IPriorityQueue.cs index 11f2c62148..425992b18b 100644 --- a/MediaBrowser.Providers/Manager/IPriorityQueue.cs +++ b/MediaBrowser.Providers/Manager/IPriorityQueue.cs @@ -24,7 +24,7 @@ namespace Priority_Queue /// /// Removes the head of the queue (node with minimum priority; ties are broken by order of insertion), and returns it. /// - TItem Dequeue(); + bool TryDequeue(out TItem item); /// /// Removes every node from the queue. diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index f08a7d3c32..7ff018c7b1 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -873,19 +873,12 @@ namespace MediaBrowser.Providers.Manager } } - private bool TryDequeue(out Tuple item) - { - item = _refreshQueue.Dequeue(); - - return item != null; - } - private async Task StartProcessingRefreshQueue() { Tuple refreshItem; var libraryManager = _libraryManagerFactory(); - while (TryDequeue(out refreshItem)) + while (_refreshQueue.TryDequeue(out refreshItem)) { if (_disposed) { diff --git a/MediaBrowser.Providers/Manager/SimplePriorityQueue.cs b/MediaBrowser.Providers/Manager/SimplePriorityQueue.cs index 6435aa06b9..f4c261a810 100644 --- a/MediaBrowser.Providers/Manager/SimplePriorityQueue.cs +++ b/MediaBrowser.Providers/Manager/SimplePriorityQueue.cs @@ -126,17 +126,25 @@ namespace Priority_Queue /// If queue is empty, throws an exception /// O(log n) /// - public TItem Dequeue() + public bool TryDequeue(out TItem item) { lock (_queue) { if (_queue.Count <= 0) { - throw new InvalidOperationException("Cannot call Dequeue() on an empty queue"); + item = default(TItem); + return false; } - SimpleNode node = _queue.Dequeue(); - return node.Data; + SimpleNode node; + if (_queue.TryDequeue(out node)) + { + item = node.Data; + return true; + } + + item = default(TItem); + return false; } } diff --git a/MediaBrowser.Providers/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Omdb/OmdbProvider.cs index 474fdf14cd..0bafe7947f 100644 --- a/MediaBrowser.Providers/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Omdb/OmdbProvider.cs @@ -103,17 +103,17 @@ namespace MediaBrowser.Providers.Omdb ParseAdditionalMetadata(itemResult, result); } - public async Task FetchEpisodeData(MetadataResult itemResult, int episodeNumber, int seasonNumber, string imdbId, string language, string country, CancellationToken cancellationToken) + public async Task FetchEpisodeData(MetadataResult itemResult, int episodeNumber, int seasonNumber, string episodeImdbId, string seriesImdbId, string language, string country, CancellationToken cancellationToken) where T : BaseItem { - if (string.IsNullOrWhiteSpace(imdbId)) + if (string.IsNullOrWhiteSpace(seriesImdbId)) { - throw new ArgumentNullException("imdbId"); + throw new ArgumentNullException("seriesImdbId"); } T item = itemResult.Item; - var seasonResult = await GetSeasonRootObject(imdbId, seasonNumber, cancellationToken).ConfigureAwait(false); + var seasonResult = await GetSeasonRootObject(seriesImdbId, seasonNumber, cancellationToken).ConfigureAwait(false); if (seasonResult == null) { @@ -122,12 +122,28 @@ namespace MediaBrowser.Providers.Omdb RootObject result = null; - foreach (var episode in (seasonResult.Episodes ?? new RootObject[] { })) + if (!string.IsNullOrWhiteSpace(episodeImdbId)) { - if (episode.Episode == episodeNumber) + foreach (var episode in (seasonResult.Episodes ?? new RootObject[] { })) { - result = episode; - break; + if (string.Equals(episodeImdbId, episode.imdbID, StringComparison.OrdinalIgnoreCase)) + { + result = episode; + break; + } + } + } + + // finally, search by numbers + if (result == null) + { + foreach (var episode in (seasonResult.Episodes ?? new RootObject[] { })) + { + if (episode.Episode == episodeNumber) + { + result = episode; + break; + } } } diff --git a/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs index 56aa3967c5..f73244cdfe 100644 --- a/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs @@ -58,11 +58,10 @@ namespace MediaBrowser.Providers.TV string seriesImdbId; if (info.SeriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out seriesImdbId) && !string.IsNullOrEmpty(seriesImdbId)) { - if (info.IndexNumber.HasValue && - info.ParentIndexNumber.HasValue) + if (info.IndexNumber.HasValue && info.ParentIndexNumber.HasValue) { result.HasMetadata = await new OmdbProvider(_jsonSerializer, _httpClient, _fileSystem, _configurationManager) - .FetchEpisodeData(result, info.IndexNumber.Value, info.ParentIndexNumber.Value, seriesImdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); + .FetchEpisodeData(result, info.IndexNumber.Value, info.ParentIndexNumber.Value, info.GetProviderId(MetadataProviders.Imdb), seriesImdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); } } diff --git a/SocketHttpListener.Portable/Net/HttpConnection.cs b/SocketHttpListener.Portable/Net/HttpConnection.cs index 5fe47fc635..ac8ada4862 100644 --- a/SocketHttpListener.Portable/Net/HttpConnection.cs +++ b/SocketHttpListener.Portable/Net/HttpConnection.cs @@ -217,7 +217,7 @@ namespace SocketHttpListener.Net { var supportsDirectSocketAccess = !context.Response.SendChunked && !isExpect100Continue && !secure; - o_stream = new ResponseStream(stream, context.Response, _memoryStreamFactory, _textEncoding, _fileSystem, sock, supportsDirectSocketAccess); + o_stream = new ResponseStream(stream, context.Response, _memoryStreamFactory, _textEncoding, _fileSystem, sock, supportsDirectSocketAccess, _logger); } else { diff --git a/SocketHttpListener.Portable/Net/ResponseStream.cs b/SocketHttpListener.Portable/Net/ResponseStream.cs index 3c79f47c23..71d0810463 100644 --- a/SocketHttpListener.Portable/Net/ResponseStream.cs +++ b/SocketHttpListener.Portable/Net/ResponseStream.cs @@ -5,6 +5,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; using MediaBrowser.Model.Net; using MediaBrowser.Model.Text; using SocketHttpListener.Primitives; @@ -26,8 +27,9 @@ namespace SocketHttpListener.Net private readonly IFileSystem _fileSystem; private readonly IAcceptSocket _socket; private readonly bool _supportsDirectSocketAccess; + private readonly ILogger _logger; - internal ResponseStream(Stream stream, HttpListenerResponse response, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IAcceptSocket socket, bool supportsDirectSocketAccess) + internal ResponseStream(Stream stream, HttpListenerResponse response, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IAcceptSocket socket, bool supportsDirectSocketAccess, ILogger logger) { this.response = response; _memoryStreamFactory = memoryStreamFactory; @@ -35,6 +37,7 @@ namespace SocketHttpListener.Net _fileSystem = fileSystem; _socket = socket; _supportsDirectSocketAccess = supportsDirectSocketAccess; + _logger = logger; this.stream = stream; } @@ -309,29 +312,34 @@ namespace SocketHttpListener.Net public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken) { - //if (_supportsDirectSocketAccess && offset == 0 && count == 0 && !response.SendChunked) + //if (_supportsDirectSocketAccess && offset == 0 && count == 0 && !response.SendChunked && response.ContentLength64 > 8192) //{ - // return TransmitFileOverSocket(path, offset, count, cancellationToken); + // return TransmitFileOverSocket(path, offset, count, fileShareMode, cancellationToken); //} return TransmitFileManaged(path, offset, count, fileShareMode, cancellationToken); } private readonly byte[] _emptyBuffer = new byte[] { }; - private async Task TransmitFileOverSocket(string path, long offset, long count, CancellationToken cancellationToken) + private Task TransmitFileOverSocket(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken) { MemoryStream ms = GetHeaders(response, _memoryStreamFactory, false); - var buffer = new byte[] {}; + byte[] buffer; if (ms != null) { - ms.Position = 0; - - byte[] msBuffer; - _memoryStreamFactory.TryGetBuffer(ms, out msBuffer); - buffer = msBuffer; + using (var msCopy = new MemoryStream()) + { + ms.CopyTo(msCopy); + buffer = msCopy.ToArray(); + } + } + else + { + return TransmitFileManaged(path, offset, count, fileShareMode, cancellationToken); } - await _socket.SendFile(path, buffer, _emptyBuffer, cancellationToken).ConfigureAwait(false); + _logger.Info("Socket sending file {0} {1}", path, response.ContentLength64); + return _socket.SendFile(path, buffer, _emptyBuffer, cancellationToken); } private async Task TransmitFileManaged(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)