aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Reed <ebr@mediabrowser3.com>2013-05-18 18:18:41 -0400
committerEric Reed <ebr@mediabrowser3.com>2013-05-18 18:18:41 -0400
commit00449ff66dbbaba9901c47c65070868ca111ac45 (patch)
tree14980d9711cbcc5d5d92a02031715d8f79b0eaf8
parent584641a6f43fee18f65dc9c8abd24b88742922ce (diff)
parent407016a30702694e39505afbb599791ed7c2dcfe (diff)
Merge branch 'master' of https://github.com/MediaBrowser/MediaBrowser
-rw-r--r--MediaBrowser.Api/Images/ImageService.cs11
-rw-r--r--MediaBrowser.Api/MediaBrowser.Api.csproj3
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs19
-rw-r--r--MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs65
-rw-r--r--MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs75
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs2
-rw-r--r--MediaBrowser.Api/UserLibrary/ItemsService.cs2
-rw-r--r--MediaBrowser.Common.Implementations/BaseApplicationHost.cs4
-rw-r--r--MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs168
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs8
-rw-r--r--MediaBrowser.Controller/Entities/CollectionFolder.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs2
-rw-r--r--MediaBrowser.Controller/Providers/BaseItemXmlParser.cs8
-rw-r--r--MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs7
-rw-r--r--MediaBrowser.Controller/Providers/ImagesByNameProvider.cs3
-rw-r--r--MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs4
-rw-r--r--MediaBrowser.Controller/Providers/TV/RemoteEpisodeProvider.cs50
-rw-r--r--MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs157
-rw-r--r--MediaBrowser.Controller/Providers/TV/SeriesXmlParser.cs11
-rw-r--r--MediaBrowser.Controller/Resolvers/ResolverPriority.cs3
-rw-r--r--MediaBrowser.Controller/Session/ISessionManager.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Library/LibraryManager.cs6
-rw-r--r--MediaBrowser.Server.Implementations/Providers/ProviderManager.cs2
-rw-r--r--MediaBrowser.Server.Implementations/ScheduledTasks/AudioImagesTask.cs12
-rw-r--r--MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs4
-rw-r--r--MediaBrowser.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs2
-rw-r--r--MediaBrowser.Server.Implementations/ScheduledTasks/VideoImagesTask.cs7
-rw-r--r--MediaBrowser.Server.Implementations/Session/SessionManager.cs37
-rw-r--r--MediaBrowser.ServerApplication/App.xaml.cs13
-rw-r--r--MediaBrowser.ServerApplication/ApplicationHost.cs57
-rw-r--r--MediaBrowser.ServerApplication/EntryPoints/UdpServerEntryPoint.cs61
-rw-r--r--MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj1
-rw-r--r--Nuget/MediaBrowser.Common.Internal.nuspec4
-rw-r--r--Nuget/MediaBrowser.Common.nuspec2
-rw-r--r--Nuget/MediaBrowser.Server.Core.nuspec4
35 files changed, 477 insertions, 341 deletions
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index 3f5b9da2a..51608a899 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -361,7 +361,7 @@ namespace MediaBrowser.Api.Images
index++;
}
-
+
index = 0;
foreach (var image in item.ScreenshotImagePaths)
@@ -422,7 +422,7 @@ namespace MediaBrowser.Api.Images
return list;
}
-
+
/// <summary>
/// Gets the specified request.
/// </summary>
@@ -765,7 +765,7 @@ namespace MediaBrowser.Api.Images
}
// Don't save locally if there's no parent (special feature, trailer, etc)
- var saveLocally = (!(entity is Audio) && entity.Parent != null && !string.IsNullOrEmpty(entity.MetaLocation)) || entity is User;
+ var saveLocally = !(entity is Audio) && entity.Parent != null && !string.IsNullOrEmpty(entity.MetaLocation) || entity is User;
if (imageType != ImageType.Primary)
{
@@ -775,6 +775,11 @@ namespace MediaBrowser.Api.Images
}
}
+ if (entity.LocationType != LocationType.FileSystem)
+ {
+ saveLocally = false;
+ }
+
var imagePath = _providerManager.GetSavePath(entity, filename + "." + extension, saveLocally);
// Save to file system
diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index 2819a649a..fb06e35ea 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -56,6 +56,8 @@
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Net.Http.WebRequest" />
<Reference Include="System.XML" />
</ItemGroup>
<ItemGroup>
@@ -82,6 +84,7 @@
<Compile Include="Playback\Progressive\BaseProgressiveStreamingService.cs" />
<Compile Include="Playback\BaseStreamingService.cs" />
<Compile Include="Playback\Progressive\ProgressiveStreamWriter.cs" />
+ <Compile Include="Playback\StaticRemoteStreamWriter.cs" />
<Compile Include="Playback\StreamRequest.cs" />
<Compile Include="Playback\StreamState.cs" />
<Compile Include="Playback\Progressive\VideoService.cs" />
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index 04b6a656d..19b339cd7 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -622,9 +622,26 @@ namespace MediaBrowser.Api.Playback
/// <returns>System.String.</returns>
protected string GetUserAgentParam(BaseItem item)
{
+ var useragent = GetUserAgent(item);
+
+ if (!string.IsNullOrEmpty(useragent))
+ {
+ return "-user-agent \"" + useragent + "\"";
+ }
+
+ return string.Empty;
+ }
+
+ /// <summary>
+ /// Gets the user agent.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <returns>System.String.</returns>
+ protected string GetUserAgent(BaseItem item)
+ {
if (item.Path.IndexOf("apple.com", StringComparison.OrdinalIgnoreCase) != -1)
{
- return "-user-agent \"QuickTime/7.6.2\"";
+ return "QuickTime/7.6.2";
}
return string.Empty;
diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
index 9bcce87c8..ab1fb4f90 100644
--- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
@@ -1,4 +1,7 @@
-using MediaBrowser.Api.Images;
+using System.Net;
+using System.Net.Cache;
+using System.Net.Http;
+using MediaBrowser.Api.Images;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.MediaInfo;
using MediaBrowser.Common.Net;
@@ -188,6 +191,11 @@ namespace MediaBrowser.Api.Playback.Progressive
var responseHeaders = new Dictionary<string, string>();
+ if (request.Static && state.Item.LocationType == LocationType.Remote)
+ {
+ return GetStaticRemoteStreamResult(state.Item, responseHeaders, isHeadRequest).Result;
+ }
+
var outputPath = GetOutputFilePath(state);
var outputPathExists = File.Exists(outputPath);
@@ -210,6 +218,61 @@ namespace MediaBrowser.Api.Playback.Progressive
}
/// <summary>
+ /// Gets the static remote stream result.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="responseHeaders">The response headers.</param>
+ /// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
+ /// <returns>Task{System.Object}.</returns>
+ private async Task<object> GetStaticRemoteStreamResult(BaseItem item, Dictionary<string, string> responseHeaders, bool isHeadRequest)
+ {
+ responseHeaders["Accept-Ranges"] = "none";
+
+ var httpClient = new HttpClient(new WebRequestHandler
+ {
+ CachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache),
+ AutomaticDecompression = DecompressionMethods.None
+ });
+
+ using (var message = new HttpRequestMessage(HttpMethod.Get, item.Path))
+ {
+ var useragent = GetUserAgent(item);
+
+ if (!string.IsNullOrEmpty(useragent))
+ {
+ message.Headers.Add("User-Agent", useragent);
+ }
+
+ var response = await httpClient.SendAsync(message, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
+
+ response.EnsureSuccessStatusCode();
+
+ var contentType = response.Content.Headers.ContentType.MediaType;
+
+ // Headers only
+ if (isHeadRequest)
+ {
+ response.Dispose();
+ httpClient.Dispose();
+
+ return ResultFactory.GetResult(null, contentType, responseHeaders);
+ }
+
+ var result = new StaticRemoteStreamWriter(response, httpClient);
+
+ result.Options["Content-Type"] = contentType;
+
+ // Add the response headers to the result object
+ foreach (var header in responseHeaders)
+ {
+ result.Options[header.Key] = header.Value;
+ }
+
+ return result;
+ }
+ }
+
+ /// <summary>
/// Gets the album art response.
/// </summary>
/// <param name="state">The state.</param>
diff --git a/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs b/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs
new file mode 100644
index 000000000..89e13acb3
--- /dev/null
+++ b/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs
@@ -0,0 +1,75 @@
+using ServiceStack.Service;
+using ServiceStack.ServiceHost;
+using System.Collections.Generic;
+using System.IO;
+using System.Net.Http;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Api.Playback
+{
+ /// <summary>
+ /// Class StaticRemoteStreamWriter
+ /// </summary>
+ public class StaticRemoteStreamWriter : IStreamWriter, IHasOptions
+ {
+ /// <summary>
+ /// The _input stream
+ /// </summary>
+ private readonly HttpResponseMessage _msg;
+
+ private readonly HttpClient _client;
+
+ /// <summary>
+ /// The _options
+ /// </summary>
+ private readonly IDictionary<string, string> _options = new Dictionary<string, string>();
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="StaticRemoteStreamWriter"/> class.
+ /// </summary>
+ public StaticRemoteStreamWriter(HttpResponseMessage msg, HttpClient client)
+ {
+ _msg = msg;
+ _client = client;
+ }
+
+ /// <summary>
+ /// Gets the options.
+ /// </summary>
+ /// <value>The options.</value>
+ public IDictionary<string, string> Options
+ {
+ get { return _options; }
+ }
+
+ /// <summary>
+ /// Writes to.
+ /// </summary>
+ /// <param name="responseStream">The response stream.</param>
+ public void WriteTo(Stream responseStream)
+ {
+ var task = WriteToAsync(responseStream);
+
+ Task.WaitAll(task);
+ }
+
+ /// <summary>
+ /// Writes to async.
+ /// </summary>
+ /// <param name="responseStream">The response stream.</param>
+ /// <returns>Task.</returns>
+ public async Task WriteToAsync(Stream responseStream)
+ {
+ using (_client)
+ {
+ using (_msg)
+ {
+ using (var input = await _msg.Content.ReadAsStreamAsync().ConfigureAwait(false))
+ {
+ await input.CopyToAsync(responseStream).ConfigureAwait(false);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
index 22098a368..26b0aa192 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
@@ -135,7 +135,7 @@ namespace MediaBrowser.Api.UserLibrary
{
if (!string.IsNullOrEmpty(request.NameStartsWithOrGreater))
{
- items = items.Where(i => string.Compare(request.NameStartsWithOrGreater, i.Name, StringComparison.OrdinalIgnoreCase) < 1);
+ items = items.Where(i => string.Compare(request.NameStartsWithOrGreater, i.Name, StringComparison.CurrentCultureIgnoreCase) < 1);
}
var filters = request.GetFilters().ToList();
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index c57778fd6..fbf41eb38 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -456,7 +456,7 @@ namespace MediaBrowser.Api.UserLibrary
if (!string.IsNullOrEmpty(request.NameStartsWithOrGreater))
{
- items = items.Where(i => string.Compare(request.NameStartsWithOrGreater, i.SortName, StringComparison.OrdinalIgnoreCase) < 1);
+ items = items.Where(i => string.Compare(request.NameStartsWithOrGreater, i.SortName, StringComparison.CurrentCultureIgnoreCase) < 1);
}
// Filter by Series Status
diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
index 34bdda94f..7451b6b97 100644
--- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
+++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
@@ -180,8 +180,6 @@ namespace MediaBrowser.Common.Implementations
await RegisterResources().ConfigureAwait(false);
FindParts();
-
- await RunStartupTasks().ConfigureAwait(false);
}
protected virtual void OnLoggerLoaded()
@@ -193,7 +191,7 @@ namespace MediaBrowser.Common.Implementations
/// Runs the startup tasks.
/// </summary>
/// <returns>Task.</returns>
- protected virtual Task RunStartupTasks()
+ public virtual Task RunStartupTasks()
{
return Task.Run(() =>
{
diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
index 4c51d1299..7ea2d0adf 100644
--- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
+++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
@@ -97,7 +97,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
};
client = new HttpClient(handler);
- client.Timeout = TimeSpan.FromSeconds(30);
+ client.Timeout = TimeSpan.FromSeconds(15);
_httpClients.TryAdd(host, client);
}
@@ -136,8 +136,8 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
{
var now = DateTime.UtcNow;
- var isCacheValid = (!cachedInfo.MustRevalidate && !string.IsNullOrEmpty(cachedInfo.Etag) && (now - cachedInfo.RequestDate).TotalDays < 7)
- || (cachedInfo.Expires.HasValue && cachedInfo.Expires.Value > now);
+ var isCacheValid = cachedInfo.Expires.HasValue ? cachedInfo.Expires.Value > now :
+ !cachedInfo.MustRevalidate && !string.IsNullOrEmpty(cachedInfo.Etag) && (now - cachedInfo.RequestDate).TotalDays < 5;
if (isCacheValid)
{
@@ -157,89 +157,90 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
options.CancellationToken.ThrowIfCancellationRequested();
- var message = GetHttpRequestMessage(options);
-
- if (options.EnableResponseCache && cachedInfo != null)
+ using (var message = GetHttpRequestMessage(options))
{
- if (!string.IsNullOrEmpty(cachedInfo.Etag))
+ if (options.EnableResponseCache && cachedInfo != null)
{
- message.Headers.Add("If-None-Match", cachedInfo.Etag);
+ if (!string.IsNullOrEmpty(cachedInfo.Etag))
+ {
+ message.Headers.Add("If-None-Match", cachedInfo.Etag);
+ }
+ else if (cachedInfo.LastModified.HasValue)
+ {
+ message.Headers.IfModifiedSince = new DateTimeOffset(cachedInfo.LastModified.Value);
+ }
}
- else if (cachedInfo.LastModified.HasValue)
+
+ if (options.ResourcePool != null)
{
- message.Headers.IfModifiedSince = new DateTimeOffset(cachedInfo.LastModified.Value);
+ await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false);
}
- }
- if (options.ResourcePool != null)
- {
- await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false);
- }
-
- _logger.Info("HttpClientManager.Get url: {0}", options.Url);
+ _logger.Info("HttpClientManager.Get url: {0}", options.Url);
- try
- {
- options.CancellationToken.ThrowIfCancellationRequested();
+ try
+ {
+ options.CancellationToken.ThrowIfCancellationRequested();
- var response = await GetHttpClient(GetHostFromUrl(options.Url)).SendAsync(message, HttpCompletionOption.ResponseHeadersRead, options.CancellationToken).ConfigureAwait(false);
+ var response = await GetHttpClient(GetHostFromUrl(options.Url)).SendAsync(message, HttpCompletionOption.ResponseHeadersRead, options.CancellationToken).ConfigureAwait(false);
- if (options.EnableResponseCache)
- {
- if (response.StatusCode != HttpStatusCode.NotModified)
+ if (options.EnableResponseCache)
{
- EnsureSuccessStatusCode(response);
- }
+ if (response.StatusCode != HttpStatusCode.NotModified)
+ {
+ EnsureSuccessStatusCode(response);
+ }
- options.CancellationToken.ThrowIfCancellationRequested();
+ options.CancellationToken.ThrowIfCancellationRequested();
- cachedInfo = UpdateInfoCache(cachedInfo, options.Url, cachedInfoPath, response);
+ cachedInfo = UpdateInfoCache(cachedInfo, options.Url, cachedInfoPath, response);
- if (response.StatusCode == HttpStatusCode.NotModified)
- {
- _logger.Debug("Server indicates not modified for {0}. Returning cached result.", options.Url);
-
- return GetCachedResponse(cachedReponsePath);
- }
+ if (response.StatusCode == HttpStatusCode.NotModified)
+ {
+ _logger.Debug("Server indicates not modified for {0}. Returning cached result.", options.Url);
- if (!string.IsNullOrEmpty(cachedInfo.Etag) || cachedInfo.LastModified.HasValue ||
- (cachedInfo.Expires.HasValue && cachedInfo.Expires.Value > DateTime.UtcNow))
+ return GetCachedResponse(cachedReponsePath);
+ }
+
+ if (!string.IsNullOrEmpty(cachedInfo.Etag) || cachedInfo.LastModified.HasValue ||
+ (cachedInfo.Expires.HasValue && cachedInfo.Expires.Value > DateTime.UtcNow))
+ {
+ await UpdateResponseCache(response, cachedReponsePath).ConfigureAwait(false);
+
+ return GetCachedResponse(cachedReponsePath);
+ }
+ }
+ else
{
- await UpdateResponseCache(response, cachedReponsePath).ConfigureAwait(false);
+ EnsureSuccessStatusCode(response);
- return GetCachedResponse(cachedReponsePath);
+ options.CancellationToken.ThrowIfCancellationRequested();
}
+
+ return await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
}
- else
+ catch (OperationCanceledException ex)
{
- EnsureSuccessStatusCode(response);
-
- options.CancellationToken.ThrowIfCancellationRequested();
+ throw GetCancellationException(options.Url, options.CancellationToken, ex);
}
+ catch (HttpRequestException ex)
+ {
+ _logger.ErrorException("Error getting response from " + options.Url, ex);
- return await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
- }
- catch (OperationCanceledException ex)
- {
- throw GetCancellationException(options.Url, options.CancellationToken, ex);
- }
- catch (HttpRequestException ex)
- {
- _logger.ErrorException("Error getting response from " + options.Url, ex);
-
- throw new HttpException(ex.Message, ex);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting response from " + options.Url, ex);
+ throw new HttpException(ex.Message, ex);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error getting response from " + options.Url, ex);
- throw;
- }
- finally
- {
- if (options.ResourcePool != null)
+ throw;
+ }
+ finally
{
- options.ResourcePool.Release();
+ if (options.ResourcePool != null)
+ {
+ options.ResourcePool.Release();
+ }
}
}
}
@@ -469,39 +470,42 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
{
options.CancellationToken.ThrowIfCancellationRequested();
- using (var response = await GetHttpClient(GetHostFromUrl(options.Url)).SendAsync(GetHttpRequestMessage(options), HttpCompletionOption.ResponseHeadersRead, options.CancellationToken).ConfigureAwait(false))
+ using (var message = GetHttpRequestMessage(options))
{
- EnsureSuccessStatusCode(response);
+ using (var response = await GetHttpClient(GetHostFromUrl(options.Url)).SendAsync(message, HttpCompletionOption.ResponseHeadersRead, options.CancellationToken).ConfigureAwait(false))
+ {
+ EnsureSuccessStatusCode(response);
- options.CancellationToken.ThrowIfCancellationRequested();
+ options.CancellationToken.ThrowIfCancellationRequested();
- var contentLength = GetContentLength(response);
+ var contentLength = GetContentLength(response);
- if (!contentLength.HasValue)
- {
- // We're not able to track progress
- using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
+ if (!contentLength.HasValue)
{
- using (var fs = new FileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
+ // We're not able to track progress
+ using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
{
- await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false);
+ using (var fs = new FileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
+ {
+ await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false);
+ }
}
}
- }
- else
- {
- using (var stream = ProgressStream.CreateReadProgressStream(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), options.Progress.Report, contentLength.Value))
+ else
{
- using (var fs = new FileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
+ using (var stream = ProgressStream.CreateReadProgressStream(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), options.Progress.Report, contentLength.Value))
{
- await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false);
+ using (var fs = new FileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
+ {
+ await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false);
+ }
}
}
- }
- options.Progress.Report(100);
+ options.Progress.Report(100);
- options.CancellationToken.ThrowIfCancellationRequested();
+ options.CancellationToken.ThrowIfCancellationRequested();
+ }
}
}
catch (Exception ex)
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index a0dba1aab..1bc6b523e 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -647,6 +647,11 @@ namespace MediaBrowser.Controller.Entities
public long? RunTimeTicks { get; set; }
/// <summary>
+ /// Gets or sets the original run time ticks.
+ /// </summary>
+ /// <value>The original run time ticks.</value>
+ public long? OriginalRunTimeTicks { get; set; }
+ /// <summary>
/// Gets or sets the aspect ratio.
/// </summary>
/// <value>The aspect ratio.</value>
@@ -900,7 +905,6 @@ namespace MediaBrowser.Controller.Entities
if (changed || forceSave || themeSongsChanged || themeVideosChanged || localTrailersChanged)
{
cancellationToken.ThrowIfCancellationRequested();
-
await LibraryManager.UpdateItem(this, cancellationToken).ConfigureAwait(false);
}
@@ -1501,7 +1505,7 @@ namespace MediaBrowser.Controller.Entities
}
// Refresh metadata
- return RefreshMetadata(CancellationToken.None);
+ return RefreshMetadata(CancellationToken.None, forceSave: true);
}
}
}
diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs
index 67692273d..70f3548f3 100644
--- a/MediaBrowser.Controller/Entities/CollectionFolder.cs
+++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs
@@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Entities
/// Specialized Folder class that points to a subset of the physical folders in the system.
/// It is created from the user-specific folders within the system root
/// </summary>
- public class CollectionFolder : Folder, ICollectionFolder, IByReferenceItem
+ public class CollectionFolder : Folder, ICollectionFolder
{
/// <summary>
/// Gets a value indicating whether this instance is virtual folder.
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 472cc115e..66a4ca215 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -760,7 +760,7 @@ namespace MediaBrowser.Controller.Entities
var child = currentTuple.Item1;
//refresh it
- await child.RefreshMetadata(cancellationToken, resetResolveArgs: child.IsFolder).ConfigureAwait(false);
+ await child.RefreshMetadata(cancellationToken, resetResolveArgs: child.IsFolder, forceSave: currentTuple.Item2).ConfigureAwait(false);
// Refresh children if a folder and the item changed or recursive is set to true
var refreshChildren = child.IsFolder && (currentTuple.Item2 || (recursive.HasValue && recursive.Value));
diff --git a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs
index 65ec6899f..60a2c19a7 100644
--- a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs
+++ b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs
@@ -325,7 +325,7 @@ namespace MediaBrowser.Controller.Providers
if (!string.IsNullOrWhiteSpace(val))
{
- item.AddTrailerUrl(val);
+ //item.AddTrailerUrl(val);
}
break;
}
@@ -336,10 +336,10 @@ namespace MediaBrowser.Controller.Providers
if (!string.IsNullOrWhiteSpace(val))
{
- int ProductionYear;
- if (int.TryParse(val, out ProductionYear) && ProductionYear > 1850)
+ int productionYear;
+ if (int.TryParse(val, out productionYear) && productionYear > 1850)
{
- item.ProductionYear = ProductionYear;
+ item.ProductionYear = productionYear;
}
}
diff --git a/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs b/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs
index 3e8501dfa..6e14682dd 100644
--- a/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs
+++ b/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs
@@ -91,12 +91,13 @@ namespace MediaBrowser.Controller.Providers
}
// Only validate paths from the same directory - need to copy to a list because we are going to potentially modify the collection below
- var deletedKeys = item.Images.Keys.Where(image =>
+ var deletedKeys = item.Images.ToList().Where(image =>
{
- var path = item.Images[image];
+ var path = image.Value;
return IsInMetaLocation(item, path) && item.ResolveArgs.GetMetaFileByPath(path) == null;
- }).ToList();
+
+ }).Select(i => i.Key).ToList();
// Now remove them from the dictionary
foreach (var key in deletedKeys)
diff --git a/MediaBrowser.Controller/Providers/ImagesByNameProvider.cs b/MediaBrowser.Controller/Providers/ImagesByNameProvider.cs
index 64a988378..3611607c9 100644
--- a/MediaBrowser.Controller/Providers/ImagesByNameProvider.cs
+++ b/MediaBrowser.Controller/Providers/ImagesByNameProvider.cs
@@ -126,7 +126,8 @@ namespace MediaBrowser.Controller.Providers
}
data.Data = ConfigurationManager.ApplicationPaths.ItemsByNamePath.GetMD5();
-
+ SetLastRefreshed(item, DateTime.UtcNow);
+
return result;
}
diff --git a/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs
index 307db023f..38d80883a 100644
--- a/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs
+++ b/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs
@@ -973,8 +973,8 @@ namespace MediaBrowser.Controller.Providers.Movies
boxset.OfficialRating = firstChild != null ? firstChild.OfficialRating : null;
}
- //if (movie.RunTimeTicks == null && movieData.runtime > 0)
- // movie.RunTimeTicks = TimeSpan.FromMinutes(movieData.runtime).Ticks;
+ if (movieData.runtime > 0)
+ movie.OriginalRunTimeTicks = TimeSpan.FromMinutes(movieData.runtime).Ticks;
//studios
if (movieData.production_companies != null)
diff --git a/MediaBrowser.Controller/Providers/TV/RemoteEpisodeProvider.cs b/MediaBrowser.Controller/Providers/TV/RemoteEpisodeProvider.cs
index 2b4173ed9..b6852e9ba 100644
--- a/MediaBrowser.Controller/Providers/TV/RemoteEpisodeProvider.cs
+++ b/MediaBrowser.Controller/Providers/TV/RemoteEpisodeProvider.cs
@@ -46,11 +46,11 @@ namespace MediaBrowser.Controller.Providers.TV
/// <summary>
/// The episode query
/// </summary>
- private const string episodeQuery = "http://www.thetvdb.com/api/{0}/series/{1}/default/{2}/{3}/{4}.xml";
+ private const string EpisodeQuery = "http://www.thetvdb.com/api/{0}/series/{1}/default/{2}/{3}/{4}.xml";
/// <summary>
/// The abs episode query
/// </summary>
- private const string absEpisodeQuery = "http://www.thetvdb.com/api/{0}/series/{1}/absolute/{2}/{3}.xml";
+ private const string AbsEpisodeQuery = "http://www.thetvdb.com/api/{0}/series/{1}/absolute/{2}/{3}.xml";
/// <summary>
/// Supportses the specified item.
@@ -179,25 +179,19 @@ namespace MediaBrowser.Controller.Providers.TV
seasonNumber = "0"; // Specials
}
- var url = string.Format(episodeQuery, TVUtils.TvdbApiKey, seriesId, seasonNumber, episodeNumber, ConfigurationManager.Configuration.PreferredMetadataLanguage);
+ var url = string.Format(EpisodeQuery, TVUtils.TvdbApiKey, seriesId, seasonNumber, episodeNumber, ConfigurationManager.Configuration.PreferredMetadataLanguage);
var doc = new XmlDocument();
- try
+ using (var result = await HttpClient.Get(new HttpRequestOptions
{
- using (var result = await HttpClient.Get(new HttpRequestOptions
- {
- Url = url,
- ResourcePool = RemoteSeriesProvider.Current.TvDbResourcePool,
- CancellationToken = cancellationToken,
- EnableResponseCache = true
+ Url = url,
+ ResourcePool = RemoteSeriesProvider.Current.TvDbResourcePool,
+ CancellationToken = cancellationToken,
+ EnableResponseCache = true
- }).ConfigureAwait(false))
- {
- doc.Load(result);
- }
- }
- catch (HttpException)
+ }).ConfigureAwait(false))
{
+ doc.Load(result);
}
//episode does not exist under this season, try absolute numbering.
@@ -205,25 +199,19 @@ namespace MediaBrowser.Controller.Providers.TV
//this is basicly just for anime.
if (!doc.HasChildNodes && Int32.Parse(seasonNumber) == 1)
{
- url = string.Format(absEpisodeQuery, TVUtils.TvdbApiKey, seriesId, episodeNumber, ConfigurationManager.Configuration.PreferredMetadataLanguage);
+ url = string.Format(AbsEpisodeQuery, TVUtils.TvdbApiKey, seriesId, episodeNumber, ConfigurationManager.Configuration.PreferredMetadataLanguage);
- try
+ using (var result = await HttpClient.Get(new HttpRequestOptions
{
- using (var result = await HttpClient.Get(new HttpRequestOptions
- {
- Url = url,
- ResourcePool = RemoteSeriesProvider.Current.TvDbResourcePool,
- CancellationToken = cancellationToken,
- EnableResponseCache = true
+ Url = url,
+ ResourcePool = RemoteSeriesProvider.Current.TvDbResourcePool,
+ CancellationToken = cancellationToken,
+ EnableResponseCache = true
- }).ConfigureAwait(false))
- {
- if (result != null) doc.Load(result);
- usingAbsoluteData = true;
- }
- }
- catch (HttpException)
+ }).ConfigureAwait(false))
{
+ if (result != null) doc.Load(result);
+ usingAbsoluteData = true;
}
}
diff --git a/MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs b/MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs
index eb689ed2f..39fe4f2c6 100644
--- a/MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs
+++ b/MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs
@@ -1,5 +1,4 @@
-using System.Globalization;
-using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
@@ -11,6 +10,7 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net;
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Net;
using System.Text;
@@ -142,8 +142,7 @@ namespace MediaBrowser.Controller.Providers.TV
if (item.DontFetchMeta) return false;
- return !HasLocalMeta(item) && (ConfigurationManager.Configuration.MetadataRefreshDays != -1 &&
- DateTime.UtcNow.Subtract(downloadDate).TotalDays > ConfigurationManager.Configuration.MetadataRefreshDays);
+ return !HasLocalMeta(item) && base.NeedsRefreshInternal(item, providerInfo);
}
/// <summary>
@@ -164,16 +163,17 @@ namespace MediaBrowser.Controller.Providers.TV
var seriesId = Path.GetFileName(path).GetAttributeValue("tvdbid") ?? await GetSeriesId(series, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
-
+
+ var status = ProviderRefreshStatus.Success;
+
if (!string.IsNullOrEmpty(seriesId))
{
series.SetProviderId(MetadataProviders.Tvdb, seriesId);
- if (!HasCompleteMetadata(series))
- {
- await FetchSeriesData(series, seriesId, cancellationToken).ConfigureAwait(false);
- }
+
+ status = await FetchSeriesData(series, seriesId, cancellationToken).ConfigureAwait(false);
}
- SetLastRefreshed(item, DateTime.UtcNow);
+
+ SetLastRefreshed(item, DateTime.UtcNow, status);
return true;
}
Logger.Info("Series provider not fetching because local meta exists or requested to ignore: " + item.Name);
@@ -188,11 +188,9 @@ namespace MediaBrowser.Controller.Providers.TV
/// <param name="seriesId">The series id.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{System.Boolean}.</returns>
- private async Task<bool> FetchSeriesData(Series series, string seriesId, CancellationToken cancellationToken)
+ private async Task<ProviderRefreshStatus> FetchSeriesData(Series series, string seriesId, CancellationToken cancellationToken)
{
- var success = false;
-
- var name = series.Name;
+ var status = ProviderRefreshStatus.Success;
if (!string.IsNullOrEmpty(seriesId))
{
@@ -200,22 +198,16 @@ namespace MediaBrowser.Controller.Providers.TV
string url = string.Format(seriesGet, TVUtils.TvdbApiKey, seriesId, ConfigurationManager.Configuration.PreferredMetadataLanguage);
var doc = new XmlDocument();
- try
+ using (var xml = await HttpClient.Get(new HttpRequestOptions
{
- using (var xml = await HttpClient.Get(new HttpRequestOptions
- {
- Url = url,
- ResourcePool = TvDbResourcePool,
- CancellationToken = cancellationToken,
- EnableResponseCache = true
+ Url = url,
+ ResourcePool = TvDbResourcePool,
+ CancellationToken = cancellationToken,
+ EnableResponseCache = true
- }).ConfigureAwait(false))
- {
- doc.Load(xml);
- }
- }
- catch (HttpException)
+ }).ConfigureAwait(false))
{
+ doc.Load(xml);
}
if (doc.HasChildNodes)
@@ -224,8 +216,6 @@ namespace MediaBrowser.Controller.Providers.TV
var actorTask = FetchActors(series, seriesId, doc, cancellationToken);
var imageTask = FetchImages(series, seriesId, cancellationToken);
- success = true;
-
series.Name = doc.SafeGetString("//SeriesName");
series.Overview = doc.SafeGetString("//Overview");
series.CommunityRating = doc.SafeGetSingle("//Rating", 0, 10);
@@ -268,8 +258,15 @@ namespace MediaBrowser.Controller.Providers.TV
}
}
- //wait for other tasks
- await Task.WhenAll(actorTask, imageTask).ConfigureAwait(false);
+ try
+ {
+ //wait for other tasks
+ await Task.WhenAll(actorTask, imageTask).ConfigureAwait(false);
+ }
+ catch (HttpException)
+ {
+ status = ProviderRefreshStatus.CompletedWithErrors;
+ }
if (ConfigurationManager.Configuration.SaveLocalMeta)
{
@@ -281,9 +278,7 @@ namespace MediaBrowser.Controller.Providers.TV
}
}
-
-
- return success;
+ return status;
}
/// <summary>
@@ -299,22 +294,16 @@ namespace MediaBrowser.Controller.Providers.TV
string urlActors = string.Format(getActors, TVUtils.TvdbApiKey, seriesId);
var docActors = new XmlDocument();
- try
+ using (var actors = await HttpClient.Get(new HttpRequestOptions
{
- using (var actors = await HttpClient.Get(new HttpRequestOptions
- {
- Url = urlActors,
- ResourcePool = TvDbResourcePool,
- CancellationToken = cancellationToken,
- EnableResponseCache = true
+ Url = urlActors,
+ ResourcePool = TvDbResourcePool,
+ CancellationToken = cancellationToken,
+ EnableResponseCache = true
- }).ConfigureAwait(false))
- {
- docActors.Load(actors);
- }
- }
- catch (HttpException)
+ }).ConfigureAwait(false))
{
+ docActors.Load(actors);
}
if (docActors.HasChildNodes)
@@ -380,22 +369,16 @@ namespace MediaBrowser.Controller.Providers.TV
string url = string.Format("http://www.thetvdb.com/api/" + TVUtils.TvdbApiKey + "/series/{0}/banners.xml", seriesId);
var images = new XmlDocument();
- try
+ using (var imgs = await HttpClient.Get(new HttpRequestOptions
{
- using (var imgs = await HttpClient.Get(new HttpRequestOptions
- {
- Url = url,
- ResourcePool = TvDbResourcePool,
- CancellationToken = cancellationToken,
- EnableResponseCache = true
+ Url = url,
+ ResourcePool = TvDbResourcePool,
+ CancellationToken = cancellationToken,
+ EnableResponseCache = true
- }).ConfigureAwait(false))
- {
- images.Load(imgs);
- }
- }
- catch (HttpException)
+ }).ConfigureAwait(false))
{
+ images.Load(imgs);
}
if (images.HasChildNodes)
@@ -408,17 +391,7 @@ namespace MediaBrowser.Controller.Providers.TV
n = n.SelectSingleNode("./BannerPath");
if (n != null)
{
- try
- {
- series.PrimaryImagePath = await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n.InnerText, "folder" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, TvDbResourcePool, cancellationToken).ConfigureAwait(false);
- }
- catch (HttpException)
- {
- }
- catch (IOException)
- {
-
- }
+ series.PrimaryImagePath = await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n.InnerText, "folder" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, TvDbResourcePool, cancellationToken).ConfigureAwait(false);
}
}
}
@@ -431,19 +404,9 @@ namespace MediaBrowser.Controller.Providers.TV
n = n.SelectSingleNode("./BannerPath");
if (n != null)
{
- try
- {
- var bannerImagePath = await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n.InnerText, "banner" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, TvDbResourcePool, cancellationToken);
-
- series.SetImage(ImageType.Banner, bannerImagePath);
- }
- catch (HttpException)
- {
- }
- catch (IOException)
- {
+ var bannerImagePath = await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n.InnerText, "banner" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, TvDbResourcePool, cancellationToken);
- }
+ series.SetImage(ImageType.Banner, bannerImagePath);
}
}
}
@@ -460,17 +423,7 @@ namespace MediaBrowser.Controller.Providers.TV
var bdName = "backdrop" + (bdNo > 0 ? bdNo.ToString(UsCulture) : "");
if (ConfigurationManager.Configuration.RefreshItemImages || !series.HasLocalImage(bdName))
{
- try
- {
- series.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + p.InnerText, bdName + Path.GetExtension(p.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, TvDbResourcePool, cancellationToken).ConfigureAwait(false));
- }
- catch (HttpException)
- {
- }
- catch (IOException)
- {
-
- }
+ series.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + p.InnerText, bdName + Path.GetExtension(p.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, TvDbResourcePool, cancellationToken).ConfigureAwait(false));
}
bdNo++;
if (bdNo >= ConfigurationManager.Configuration.MaxBackdrops) break;
@@ -481,27 +434,13 @@ namespace MediaBrowser.Controller.Providers.TV
}
/// <summary>
- /// Determines whether [has complete metadata] [the specified series].
- /// </summary>
- /// <param name="series">The series.</param>
- /// <returns><c>true</c> if [has complete metadata] [the specified series]; otherwise, <c>false</c>.</returns>
- private bool HasCompleteMetadata(Series series)
- {
- return (series.HasImage(ImageType.Banner)) && (series.CommunityRating != null)
- && (series.Overview != null) && (series.Name != null) && (series.People != null)
- && (series.Genres != null) && (series.OfficialRating != null);
- }
-
- /// <summary>
/// Determines whether [has local meta] [the specified item].
/// </summary>
/// <param name="item">The item.</param>
/// <returns><c>true</c> if [has local meta] [the specified item]; otherwise, <c>false</c>.</returns>
private bool HasLocalMeta(BaseItem item)
{
- //need at least the xml and folder.jpg/png
- return item.ResolveArgs.ContainsMetaFileByName(LOCAL_META_FILE_NAME) && (item.ResolveArgs.ContainsMetaFileByName("folder.jpg") ||
- item.ResolveArgs.ContainsMetaFileByName("folder.png"));
+ return item.ResolveArgs.ContainsMetaFileByName(LOCAL_META_FILE_NAME);
}
/// <summary>
diff --git a/MediaBrowser.Controller/Providers/TV/SeriesXmlParser.cs b/MediaBrowser.Controller/Providers/TV/SeriesXmlParser.cs
index f63a47627..c03e2a7f5 100644
--- a/MediaBrowser.Controller/Providers/TV/SeriesXmlParser.cs
+++ b/MediaBrowser.Controller/Providers/TV/SeriesXmlParser.cs
@@ -63,8 +63,15 @@ namespace MediaBrowser.Controller.Providers.TV
}
case "Airs_Time":
- item.AirTime = reader.ReadElementContentAsString();
- break;
+ {
+ var val = reader.ReadElementContentAsString();
+
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ item.AirTime = val;
+ }
+ break;
+ }
case "SeriesName":
item.Name = reader.ReadElementContentAsString();
diff --git a/MediaBrowser.Controller/Resolvers/ResolverPriority.cs b/MediaBrowser.Controller/Resolvers/ResolverPriority.cs
index 63a107fda..df5edeb05 100644
--- a/MediaBrowser.Controller/Resolvers/ResolverPriority.cs
+++ b/MediaBrowser.Controller/Resolvers/ResolverPriority.cs
@@ -18,9 +18,10 @@ namespace MediaBrowser.Controller.Resolvers
/// The third
/// </summary>
Third = 3,
+ Fourth = 4,
/// <summary>
/// The last
/// </summary>
- Last = 4
+ Last = 5
}
}
diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs
index 8227170d4..f28721f5f 100644
--- a/MediaBrowser.Controller/Session/ISessionManager.cs
+++ b/MediaBrowser.Controller/Session/ISessionManager.cs
@@ -52,7 +52,7 @@ namespace MediaBrowser.Controller.Session
/// <param name="deviceId">The device id.</param>
/// <param name="deviceName">Name of the device.</param>
/// <exception cref="System.ArgumentNullException"></exception>
- void OnPlaybackStart(User user, BaseItem item, string clientType, string deviceId, string deviceName);
+ Task OnPlaybackStart(User user, BaseItem item, string clientType, string deviceId, string deviceName);
/// <summary>
/// Used to report playback progress for an item
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index 65905b082..b692e97f3 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -269,16 +269,16 @@ namespace MediaBrowser.Server.Implementations.Library
// Need to use DistinctBy Id because there could be multiple instances with the same id
// due to sharing the default library
var userRootFolders = _userManager.Users.Select(i => i.RootFolder)
- .DistinctBy(i => i.Id)
+ .Distinct()
.ToList();
items.AddRange(userRootFolders);
// Get all user collection folders
+ // Skip BasePluginFolders because we already got them from RootFolder.RecursiveChildren
var userFolders =
- _userManager.Users.SelectMany(i => i.RootFolder.Children)
+ userRootFolders.SelectMany(i => i.Children)
.Where(i => !(i is BasePluginFolder))
- .DistinctBy(i => i.Id)
.ToList();
items.AddRange(userFolders);
diff --git a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs
index b0a0f8760..cc586ccbf 100644
--- a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs
+++ b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs
@@ -408,7 +408,7 @@ namespace MediaBrowser.Server.Implementations.Providers
{
return (saveLocally && item.MetaLocation != null) ?
Path.Combine(item.MetaLocation, targetFileName) :
- _remoteImageCache.GetResourcePath(item.GetType().FullName + item.Path.ToLower(), targetFileName);
+ _remoteImageCache.GetResourcePath(item.GetType().FullName + item.Id.ToString(), targetFileName);
}
/// <summary>
diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/AudioImagesTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/AudioImagesTask.cs
index d3ed270b8..c56a2b54a 100644
--- a/MediaBrowser.Server.Implementations/ScheduledTasks/AudioImagesTask.cs
+++ b/MediaBrowser.Server.Implementations/ScheduledTasks/AudioImagesTask.cs
@@ -46,14 +46,14 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
private readonly List<Audio> _newlyAddedItems = new List<Audio>();
- private const int NewItemDelay = 300000;
+ private const int NewItemDelay = 60000;
/// <summary>
/// The current new item timer
/// </summary>
/// <value>The new item timer.</value>
private Timer NewItemTimer { get; set; }
-
+
/// <summary>
/// Initializes a new instance of the <see cref="AudioImagesTask" /> class.
/// </summary>
@@ -118,7 +118,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
foreach (var item in newSongs
.Where(i => i.LocationType == LocationType.FileSystem && string.IsNullOrEmpty(i.PrimaryImagePath) && i.MediaStreams.Any(m => m.Type == MediaStreamType.Video))
- .Take(20))
+ .Take(10))
{
try
{
@@ -130,7 +130,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
}
}
}
-
+
/// <summary>
/// Gets the name of the task
/// </summary>
@@ -216,7 +216,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
var filename = item.Album ?? string.Empty;
- filename += album == null ? item.Id.ToString("N") + item.DateModified.Ticks : album.Id.ToString() + album.DateModified.Ticks;
+ filename += album == null ? item.Id.ToString("N") + item.DateModified.Ticks : album.Id.ToString("N") + album.DateModified.Ticks;
var path = ImageCache.GetResourcePath(filename + "_primary", ".jpg");
@@ -232,7 +232,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
{
try
{
- await _mediaEncoder.ExtractImage(new[] {item.Path}, InputType.AudioFile, null, path, cancellationToken).ConfigureAwait(false);
+ await _mediaEncoder.ExtractImage(new[] { item.Path }, InputType.AudioFile, null, path, cancellationToken).ConfigureAwait(false);
}
finally
{
diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
index 87b99973d..4178d4f8b 100644
--- a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
+++ b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
@@ -33,7 +33,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
private readonly List<Video> _newlyAddedItems = new List<Video>();
- private const int NewItemDelay = 300000;
+ private const int NewItemDelay = 60000;
/// <summary>
/// The current new item timer
@@ -95,7 +95,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
foreach (var item in newItems
.Where(i => i.LocationType == LocationType.FileSystem && string.IsNullOrEmpty(i.PrimaryImagePath) && i.MediaStreams.Any(m => m.Type == MediaStreamType.Video))
- .Take(5))
+ .Take(1))
{
try
{
diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs
index 6082b629e..a343943f7 100644
--- a/MediaBrowser.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs
+++ b/MediaBrowser.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs
@@ -1,11 +1,11 @@
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Tasks;
+using MediaBrowser.Server.Implementations.Library;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Server.Implementations.Library;
namespace MediaBrowser.Server.Implementations.ScheduledTasks
{
diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/VideoImagesTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/VideoImagesTask.cs
index dcceb382c..f0afe6358 100644
--- a/MediaBrowser.Server.Implementations/ScheduledTasks/VideoImagesTask.cs
+++ b/MediaBrowser.Server.Implementations/ScheduledTasks/VideoImagesTask.cs
@@ -55,7 +55,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
private readonly List<BaseItem> _newlyAddedItems = new List<BaseItem>();
- private const int NewItemDelay = 300000;
+ private const int NewItemDelay = 60000;
/// <summary>
/// The current new item timer
@@ -124,7 +124,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
NewItemTimer = null;
}
- foreach (var item in GetItemsForExtraction(newItems.Take(5)))
+ foreach (var item in GetItemsForExtraction(newItems.Take(3)))
{
try
{
@@ -215,7 +215,8 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
var videos = allItems.OfType<Video>().ToList();
- var items = videos;
+ var items = videos.ToList();
+
items.AddRange(localTrailers);
items.AddRange(themeVideos);
diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
index 2f9c7e389..d3dbbc62b 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
@@ -200,7 +200,7 @@ namespace MediaBrowser.Server.Implementations.Session
/// <param name="deviceName">Name of the device.</param>
/// <exception cref="System.ArgumentNullException">
/// </exception>
- public void OnPlaybackStart(User user, BaseItem item, string clientType, string deviceId, string deviceName)
+ public async Task OnPlaybackStart(User user, BaseItem item, string clientType, string deviceId, string deviceName)
{
if (user == null)
{
@@ -213,6 +213,15 @@ namespace MediaBrowser.Server.Implementations.Session
UpdateNowPlayingItemId(user, clientType, deviceId, deviceName, item, false);
+ var key = item.GetUserDataKey();
+
+ var data = await _userDataRepository.GetUserData(user.Id, key).ConfigureAwait(false);
+
+ data.PlayCount++;
+ data.LastPlayedDate = DateTime.UtcNow;
+
+ await _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None).ConfigureAwait(false);
+
// Nothing to save here
// Fire events to inform plugins
EventHelper.QueueEventIfNotNull(PlaybackStart, this, new PlaybackProgressEventArgs
@@ -254,7 +263,7 @@ namespace MediaBrowser.Server.Implementations.Session
{
var data = await _userDataRepository.GetUserData(user.Id, key).ConfigureAwait(false);
- UpdatePlayState(item, data, positionTicks.Value, false);
+ UpdatePlayState(item, data, positionTicks.Value);
await _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None).ConfigureAwait(false);
}
@@ -297,7 +306,7 @@ namespace MediaBrowser.Server.Implementations.Session
if (positionTicks.HasValue)
{
- UpdatePlayState(item, data, positionTicks.Value, true);
+ UpdatePlayState(item, data, positionTicks.Value);
}
else
{
@@ -322,11 +331,12 @@ namespace MediaBrowser.Server.Implementations.Session
/// <param name="item">The item</param>
/// <param name="data">User data for the item</param>
/// <param name="positionTicks">The current playback position</param>
- /// <param name="incrementPlayCount">Whether or not to increment playcount</param>
- private void UpdatePlayState(BaseItem item, UserItemData data, long positionTicks, bool incrementPlayCount)
+ private void UpdatePlayState(BaseItem item, UserItemData data, long positionTicks)
{
+ var hasRuntime = item.RunTimeTicks.HasValue && item.RunTimeTicks > 0;
+
// If a position has been reported, and if we know the duration
- if (positionTicks > 0 && item.RunTimeTicks.HasValue && item.RunTimeTicks > 0)
+ if (positionTicks > 0 && hasRuntime)
{
var pctIn = Decimal.Divide(positionTicks, item.RunTimeTicks.Value) * 100;
@@ -334,7 +344,6 @@ namespace MediaBrowser.Server.Implementations.Session
if (pctIn < _configurationManager.Configuration.MinResumePct)
{
positionTicks = 0;
- incrementPlayCount = false;
}
// If we're at the end, assume completed
@@ -356,19 +365,19 @@ namespace MediaBrowser.Server.Implementations.Session
}
}
}
+ else if (!hasRuntime)
+ {
+ // If we don't know the runtime we'll just have to assume it was fully played
+ data.Played = true;
+ positionTicks = 0;
+ }
if (item is Audio)
{
- data.PlaybackPositionTicks = 0;
+ positionTicks = 0;
}
data.PlaybackPositionTicks = positionTicks;
-
- if (incrementPlayCount)
- {
- data.PlayCount++;
- data.LastPlayedDate = DateTime.UtcNow;
- }
}
}
}
diff --git a/MediaBrowser.ServerApplication/App.xaml.cs b/MediaBrowser.ServerApplication/App.xaml.cs
index 762eb4cd2..5a1d7505c 100644
--- a/MediaBrowser.ServerApplication/App.xaml.cs
+++ b/MediaBrowser.ServerApplication/App.xaml.cs
@@ -6,6 +6,7 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Server.Implementations;
+using MediaBrowser.ServerApplication.Splash;
using Microsoft.Win32;
using System;
using System.Diagnostics;
@@ -164,11 +165,19 @@ namespace MediaBrowser.ServerApplication
Logger = CompositionRoot.LogManager.GetLogger("App");
+ var splash = new SplashWindow(CompositionRoot.ApplicationVersion);
+
+ splash.Show();
+
await CompositionRoot.Init();
- var win = new MainWindow(CompositionRoot.LogManager, CompositionRoot, CompositionRoot.ServerConfigurationManager, CompositionRoot.UserManager, CompositionRoot.LibraryManager, CompositionRoot.JsonSerializer, CompositionRoot.DisplayPreferencesManager);
+ splash.Hide();
+
+ var task = CompositionRoot.RunStartupTasks();
+
+ new MainWindow(CompositionRoot.LogManager, CompositionRoot, CompositionRoot.ServerConfigurationManager, CompositionRoot.UserManager, CompositionRoot.LibraryManager, CompositionRoot.JsonSerializer, CompositionRoot.DisplayPreferencesManager).Show();
- win.Show();
+ await task.ConfigureAwait(false);
}
catch (Exception ex)
{
diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs
index 4dd24d98f..35a9698c3 100644
--- a/MediaBrowser.ServerApplication/ApplicationHost.cs
+++ b/MediaBrowser.ServerApplication/ApplicationHost.cs
@@ -44,7 +44,6 @@ using MediaBrowser.Server.Implementations.Udp;
using MediaBrowser.Server.Implementations.Updates;
using MediaBrowser.Server.Implementations.WebSocket;
using MediaBrowser.ServerApplication.Implementations;
-using MediaBrowser.ServerApplication.Splash;
using MediaBrowser.WebDashboard.Api;
using System;
using System.Collections.Generic;
@@ -63,7 +62,7 @@ namespace MediaBrowser.ServerApplication
/// </summary>
public class ApplicationHost : BaseApplicationHost<ServerApplicationPaths>, IServerApplicationHost
{
- private const int UdpServerPort = 7359;
+ internal const int UdpServerPort = 7359;
/// <summary>
/// Gets the server kernel.
@@ -140,11 +139,6 @@ namespace MediaBrowser.ServerApplication
private IHttpServer HttpServer { get; set; }
/// <summary>
- /// Gets or sets the UDP server.
- /// </summary>
- /// <value>The UDP server.</value>
- private UdpServer UdpServer { get; set; }
- /// <summary>
/// Gets or sets the display preferences manager.
/// </summary>
/// <value>The display preferences manager.</value>
@@ -176,25 +170,10 @@ namespace MediaBrowser.ServerApplication
private Task<IHttpServer> _httpServerCreationTask;
/// <summary>
- /// Inits this instance.
- /// </summary>
- /// <returns>Task.</returns>
- public override async Task Init()
- {
- var win = new SplashWindow(ApplicationVersion);
-
- win.Show();
-
- await base.Init();
-
- win.Hide();
- }
-
- /// <summary>
/// Runs the startup tasks.
/// </summary>
/// <returns>Task.</returns>
- protected override async Task RunStartupTasks()
+ public override async Task RunStartupTasks()
{
await base.RunStartupTasks().ConfigureAwait(false);
@@ -390,21 +369,8 @@ namespace MediaBrowser.ServerApplication
() => LibraryManager.AddParts(GetExports<IResolverIgnoreRule>(), GetExports<IVirtualFolderCreator>(), GetExports<IItemResolver>(), GetExports<IIntroProvider>(), GetExports<IBaseItemComparer>()),
- () => ProviderManager.AddMetadataProviders(GetExports<BaseMetadataProvider>().ToArray()),
+ () => ProviderManager.AddMetadataProviders(GetExports<BaseMetadataProvider>().ToArray())
- () =>
- {
- UdpServer = new UdpServer(Logger, NetworkManager, ServerConfigurationManager);
-
- try
- {
- UdpServer.Start(UdpServerPort);
- }
- catch (SocketException ex)
- {
- Logger.ErrorException("Failed to start UDP Server", ex);
- }
- }
);
}
@@ -472,23 +438,6 @@ namespace MediaBrowser.ServerApplication
}
/// <summary>
- /// Releases unmanaged and - optionally - managed resources.
- /// </summary>
- /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected override void Dispose(bool dispose)
- {
- if (dispose)
- {
- if (UdpServer != null)
- {
- UdpServer.Dispose();
- }
- }
-
- base.Dispose(dispose);
- }
-
- /// <summary>
/// Checks for update.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
diff --git a/MediaBrowser.ServerApplication/EntryPoints/UdpServerEntryPoint.cs b/MediaBrowser.ServerApplication/EntryPoints/UdpServerEntryPoint.cs
new file mode 100644
index 000000000..af4ce84e3
--- /dev/null
+++ b/MediaBrowser.ServerApplication/EntryPoints/UdpServerEntryPoint.cs
@@ -0,0 +1,61 @@
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Plugins;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Server.Implementations.Udp;
+using System.Net.Sockets;
+
+namespace MediaBrowser.ServerApplication.EntryPoints
+{
+ public class UdpServerEntryPoint : IServerEntryPoint
+ {
+ /// <summary>
+ /// Gets or sets the UDP server.
+ /// </summary>
+ /// <value>The UDP server.</value>
+ private UdpServer UdpServer { get; set; }
+
+ private readonly ILogger _logger;
+ private readonly INetworkManager _networkManager;
+ private readonly IServerConfigurationManager _serverConfigurationManager;
+
+ public UdpServerEntryPoint(ILogger logger, INetworkManager networkManager, IServerConfigurationManager serverConfigurationManager)
+ {
+ _logger = logger;
+ _networkManager = networkManager;
+ _serverConfigurationManager = serverConfigurationManager;
+ }
+
+ public void Run()
+ {
+ var udpServer = new UdpServer(_logger, _networkManager, _serverConfigurationManager);
+
+ try
+ {
+ udpServer.Start(ApplicationHost.UdpServerPort);
+
+ UdpServer = udpServer;
+ }
+ catch (SocketException ex)
+ {
+ _logger.ErrorException("Failed to start UDP Server", ex);
+ }
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool dispose)
+ {
+ if (dispose)
+ {
+ if (UdpServer != null)
+ {
+ UdpServer.Dispose();
+ }
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index 19b2d91ca..7c4eb128d 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -196,6 +196,7 @@
<Compile Include="EntryPoints\LoadRegistrations.cs" />
<Compile Include="EntryPoints\RefreshUsersMetadata.cs" />
<Compile Include="EntryPoints\StartupWizard.cs" />
+ <Compile Include="EntryPoints\UdpServerEntryPoint.cs" />
<Compile Include="EntryPoints\WebSocketEvents.cs" />
<Compile Include="Splash\SplashWindow.xaml.cs">
<DependentUpon>SplashWindow.xaml</DependentUpon>
diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec
index cbe918ddf..13b1bae99 100644
--- a/Nuget/MediaBrowser.Common.Internal.nuspec
+++ b/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.103</version>
+ <version>3.0.104</version>
<title>MediaBrowser.Common.Internal</title>
<authors>Luke</authors>
<owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
<description>Contains common components shared by Media Browser Theatre and Media Browser Server. Not intended for plugin developer consumption.</description>
<copyright>Copyright © Media Browser 2013</copyright>
<dependencies>
- <dependency id="MediaBrowser.Common" version="3.0.103" />
+ <dependency id="MediaBrowser.Common" version="3.0.104" />
<dependency id="NLog" version="2.0.1.2" />
<dependency id="ServiceStack.Text" version="3.9.45" />
<dependency id="SimpleInjector" version="2.2.1" />
diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec
index 00ba0028f..a8530230c 100644
--- a/Nuget/MediaBrowser.Common.nuspec
+++ b/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.103</version>
+ <version>3.0.104</version>
<title>MediaBrowser.Common</title>
<authors>Media Browser Team</authors>
<owners>ebr,Luke,scottisafool</owners>
diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec
index a2dee313d..8236cd633 100644
--- a/Nuget/MediaBrowser.Server.Core.nuspec
+++ b/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.103</version>
+ <version>3.0.104</version>
<title>Media Browser.Server.Core</title>
<authors>Media Browser Team</authors>
<owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
<description>Contains core components required to build plugins for Media Browser Server.</description>
<copyright>Copyright © Media Browser 2013</copyright>
<dependencies>
- <dependency id="MediaBrowser.Common" version="3.0.103" />
+ <dependency id="MediaBrowser.Common" version="3.0.104" />
</dependencies>
</metadata>
<files>