mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-06-23 15:30:56 -04:00
Merge branch 'master' of https://github.com/MediaBrowser/MediaBrowser
This commit is contained in:
commit
00449ff66d
@ -361,7 +361,7 @@ namespace MediaBrowser.Api.Images
|
|||||||
|
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
index = 0;
|
index = 0;
|
||||||
|
|
||||||
foreach (var image in item.ScreenshotImagePaths)
|
foreach (var image in item.ScreenshotImagePaths)
|
||||||
@ -422,7 +422,7 @@ namespace MediaBrowser.Api.Images
|
|||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the specified request.
|
/// Gets the specified request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -765,7 +765,7 @@ namespace MediaBrowser.Api.Images
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Don't save locally if there's no parent (special feature, trailer, etc)
|
// 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)
|
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);
|
var imagePath = _providerManager.GetSavePath(entity, filename + "." + extension, saveLocally);
|
||||||
|
|
||||||
// Save to file system
|
// Save to file system
|
||||||
|
@ -56,6 +56,8 @@
|
|||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
<Reference Include="System.Drawing" />
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Net.Http.WebRequest" />
|
||||||
<Reference Include="System.XML" />
|
<Reference Include="System.XML" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -82,6 +84,7 @@
|
|||||||
<Compile Include="Playback\Progressive\BaseProgressiveStreamingService.cs" />
|
<Compile Include="Playback\Progressive\BaseProgressiveStreamingService.cs" />
|
||||||
<Compile Include="Playback\BaseStreamingService.cs" />
|
<Compile Include="Playback\BaseStreamingService.cs" />
|
||||||
<Compile Include="Playback\Progressive\ProgressiveStreamWriter.cs" />
|
<Compile Include="Playback\Progressive\ProgressiveStreamWriter.cs" />
|
||||||
|
<Compile Include="Playback\StaticRemoteStreamWriter.cs" />
|
||||||
<Compile Include="Playback\StreamRequest.cs" />
|
<Compile Include="Playback\StreamRequest.cs" />
|
||||||
<Compile Include="Playback\StreamState.cs" />
|
<Compile Include="Playback\StreamState.cs" />
|
||||||
<Compile Include="Playback\Progressive\VideoService.cs" />
|
<Compile Include="Playback\Progressive\VideoService.cs" />
|
||||||
|
@ -621,10 +621,27 @@ namespace MediaBrowser.Api.Playback
|
|||||||
/// <param name="item">The item.</param>
|
/// <param name="item">The item.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
protected string GetUserAgentParam(BaseItem item)
|
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)
|
if (item.Path.IndexOf("apple.com", StringComparison.OrdinalIgnoreCase) != -1)
|
||||||
{
|
{
|
||||||
return "-user-agent \"QuickTime/7.6.2\"";
|
return "QuickTime/7.6.2";
|
||||||
}
|
}
|
||||||
|
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
|
@ -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.IO;
|
||||||
using MediaBrowser.Common.MediaInfo;
|
using MediaBrowser.Common.MediaInfo;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
@ -188,6 +191,11 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||||||
|
|
||||||
var responseHeaders = new Dictionary<string, string>();
|
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 outputPath = GetOutputFilePath(state);
|
||||||
var outputPathExists = File.Exists(outputPath);
|
var outputPathExists = File.Exists(outputPath);
|
||||||
|
|
||||||
@ -209,6 +217,61 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||||||
return GetStreamResult(state, responseHeaders, isHeadRequest).Result;
|
return GetStreamResult(state, responseHeaders, isHeadRequest).Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <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>
|
/// <summary>
|
||||||
/// Gets the album art response.
|
/// Gets the album art response.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
75
MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs
Normal file
75
MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -135,7 +135,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(request.NameStartsWithOrGreater))
|
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();
|
var filters = request.GetFilters().ToList();
|
||||||
|
@ -456,7 +456,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(request.NameStartsWithOrGreater))
|
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
|
// Filter by Series Status
|
||||||
|
@ -180,8 +180,6 @@ namespace MediaBrowser.Common.Implementations
|
|||||||
await RegisterResources().ConfigureAwait(false);
|
await RegisterResources().ConfigureAwait(false);
|
||||||
|
|
||||||
FindParts();
|
FindParts();
|
||||||
|
|
||||||
await RunStartupTasks().ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnLoggerLoaded()
|
protected virtual void OnLoggerLoaded()
|
||||||
@ -193,7 +191,7 @@ namespace MediaBrowser.Common.Implementations
|
|||||||
/// Runs the startup tasks.
|
/// Runs the startup tasks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
protected virtual Task RunStartupTasks()
|
public virtual Task RunStartupTasks()
|
||||||
{
|
{
|
||||||
return Task.Run(() =>
|
return Task.Run(() =>
|
||||||
{
|
{
|
||||||
|
@ -97,7 +97,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||||||
};
|
};
|
||||||
|
|
||||||
client = new HttpClient(handler);
|
client = new HttpClient(handler);
|
||||||
client.Timeout = TimeSpan.FromSeconds(30);
|
client.Timeout = TimeSpan.FromSeconds(15);
|
||||||
_httpClients.TryAdd(host, client);
|
_httpClients.TryAdd(host, client);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,8 +136,8 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||||||
{
|
{
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
|
|
||||||
var isCacheValid = (!cachedInfo.MustRevalidate && !string.IsNullOrEmpty(cachedInfo.Etag) && (now - cachedInfo.RequestDate).TotalDays < 7)
|
var isCacheValid = cachedInfo.Expires.HasValue ? cachedInfo.Expires.Value > now :
|
||||||
|| (cachedInfo.Expires.HasValue && cachedInfo.Expires.Value > now);
|
!cachedInfo.MustRevalidate && !string.IsNullOrEmpty(cachedInfo.Etag) && (now - cachedInfo.RequestDate).TotalDays < 5;
|
||||||
|
|
||||||
if (isCacheValid)
|
if (isCacheValid)
|
||||||
{
|
{
|
||||||
@ -157,89 +157,90 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||||||
|
|
||||||
options.CancellationToken.ThrowIfCancellationRequested();
|
options.CancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
var message = GetHttpRequestMessage(options);
|
using (var message = GetHttpRequestMessage(options))
|
||||||
|
|
||||||
if (options.EnableResponseCache && cachedInfo != null)
|
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(cachedInfo.Etag))
|
if (options.EnableResponseCache && cachedInfo != null)
|
||||||
{
|
{
|
||||||
message.Headers.Add("If-None-Match", cachedInfo.Etag);
|
if (!string.IsNullOrEmpty(cachedInfo.Etag))
|
||||||
}
|
|
||||||
else if (cachedInfo.LastModified.HasValue)
|
|
||||||
{
|
|
||||||
message.Headers.IfModifiedSince = new DateTimeOffset(cachedInfo.LastModified.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.ResourcePool != null)
|
|
||||||
{
|
|
||||||
await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Info("HttpClientManager.Get url: {0}", options.Url);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
options.CancellationToken.ThrowIfCancellationRequested();
|
|
||||||
|
|
||||||
var response = await GetHttpClient(GetHostFromUrl(options.Url)).SendAsync(message, HttpCompletionOption.ResponseHeadersRead, options.CancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (options.EnableResponseCache)
|
|
||||||
{
|
|
||||||
if (response.StatusCode != HttpStatusCode.NotModified)
|
|
||||||
{
|
{
|
||||||
EnsureSuccessStatusCode(response);
|
message.Headers.Add("If-None-Match", cachedInfo.Etag);
|
||||||
}
|
}
|
||||||
|
else if (cachedInfo.LastModified.HasValue)
|
||||||
options.CancellationToken.ThrowIfCancellationRequested();
|
|
||||||
|
|
||||||
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);
|
message.Headers.IfModifiedSince = new DateTimeOffset(cachedInfo.LastModified.Value);
|
||||||
|
|
||||||
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
|
|
||||||
{
|
|
||||||
EnsureSuccessStatusCode(response);
|
|
||||||
|
|
||||||
options.CancellationToken.ThrowIfCancellationRequested();
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (options.ResourcePool != null)
|
if (options.ResourcePool != null)
|
||||||
{
|
{
|
||||||
options.ResourcePool.Release();
|
await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Info("HttpClientManager.Get url: {0}", options.Url);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
options.CancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
var response = await GetHttpClient(GetHostFromUrl(options.Url)).SendAsync(message, HttpCompletionOption.ResponseHeadersRead, options.CancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (options.EnableResponseCache)
|
||||||
|
{
|
||||||
|
if (response.StatusCode != HttpStatusCode.NotModified)
|
||||||
|
{
|
||||||
|
EnsureSuccessStatusCode(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
options.CancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
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 (!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
|
||||||
|
{
|
||||||
|
EnsureSuccessStatusCode(response);
|
||||||
|
|
||||||
|
options.CancellationToken.ThrowIfCancellationRequested();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (options.ResourcePool != null)
|
||||||
|
{
|
||||||
|
options.ResourcePool.Release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -469,39 +470,42 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||||||
{
|
{
|
||||||
options.CancellationToken.ThrowIfCancellationRequested();
|
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))
|
||||||
|
|
||||||
options.CancellationToken.ThrowIfCancellationRequested();
|
|
||||||
|
|
||||||
var contentLength = GetContentLength(response);
|
|
||||||
|
|
||||||
if (!contentLength.HasValue)
|
|
||||||
{
|
{
|
||||||
// We're not able to track progress
|
EnsureSuccessStatusCode(response);
|
||||||
using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
|
|
||||||
|
options.CancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
var contentLength = GetContentLength(response);
|
||||||
|
|
||||||
|
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
|
||||||
else
|
|
||||||
{
|
|
||||||
using (var stream = ProgressStream.CreateReadProgressStream(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), options.Progress.Report, contentLength.Value))
|
|
||||||
{
|
{
|
||||||
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.CancellationToken.ThrowIfCancellationRequested();
|
||||||
}
|
}
|
||||||
|
|
||||||
options.Progress.Report(100);
|
|
||||||
|
|
||||||
options.CancellationToken.ThrowIfCancellationRequested();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -646,6 +646,11 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
/// <value>The run time ticks.</value>
|
/// <value>The run time ticks.</value>
|
||||||
public long? RunTimeTicks { get; set; }
|
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>
|
/// <summary>
|
||||||
/// Gets or sets the aspect ratio.
|
/// Gets or sets the aspect ratio.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -900,7 +905,6 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
if (changed || forceSave || themeSongsChanged || themeVideosChanged || localTrailersChanged)
|
if (changed || forceSave || themeSongsChanged || themeVideosChanged || localTrailersChanged)
|
||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
await LibraryManager.UpdateItem(this, cancellationToken).ConfigureAwait(false);
|
await LibraryManager.UpdateItem(this, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1501,7 +1505,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Refresh metadata
|
// Refresh metadata
|
||||||
return RefreshMetadata(CancellationToken.None);
|
return RefreshMetadata(CancellationToken.None, forceSave: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
/// Specialized Folder class that points to a subset of the physical folders in the system.
|
/// 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
|
/// It is created from the user-specific folders within the system root
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CollectionFolder : Folder, ICollectionFolder, IByReferenceItem
|
public class CollectionFolder : Folder, ICollectionFolder
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether this instance is virtual folder.
|
/// Gets a value indicating whether this instance is virtual folder.
|
||||||
|
@ -760,7 +760,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
var child = currentTuple.Item1;
|
var child = currentTuple.Item1;
|
||||||
|
|
||||||
//refresh it
|
//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
|
// 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));
|
var refreshChildren = child.IsFolder && (currentTuple.Item2 || (recursive.HasValue && recursive.Value));
|
||||||
|
@ -325,7 +325,7 @@ namespace MediaBrowser.Controller.Providers
|
|||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(val))
|
if (!string.IsNullOrWhiteSpace(val))
|
||||||
{
|
{
|
||||||
item.AddTrailerUrl(val);
|
//item.AddTrailerUrl(val);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -336,10 +336,10 @@ namespace MediaBrowser.Controller.Providers
|
|||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(val))
|
if (!string.IsNullOrWhiteSpace(val))
|
||||||
{
|
{
|
||||||
int ProductionYear;
|
int productionYear;
|
||||||
if (int.TryParse(val, out ProductionYear) && ProductionYear > 1850)
|
if (int.TryParse(val, out productionYear) && productionYear > 1850)
|
||||||
{
|
{
|
||||||
item.ProductionYear = ProductionYear;
|
item.ProductionYear = productionYear;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
// 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;
|
return IsInMetaLocation(item, path) && item.ResolveArgs.GetMetaFileByPath(path) == null;
|
||||||
}).ToList();
|
|
||||||
|
}).Select(i => i.Key).ToList();
|
||||||
|
|
||||||
// Now remove them from the dictionary
|
// Now remove them from the dictionary
|
||||||
foreach (var key in deletedKeys)
|
foreach (var key in deletedKeys)
|
||||||
|
@ -126,7 +126,8 @@ namespace MediaBrowser.Controller.Providers
|
|||||||
}
|
}
|
||||||
|
|
||||||
data.Data = ConfigurationManager.ApplicationPaths.ItemsByNamePath.GetMD5();
|
data.Data = ConfigurationManager.ApplicationPaths.ItemsByNamePath.GetMD5();
|
||||||
|
SetLastRefreshed(item, DateTime.UtcNow);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -973,8 +973,8 @@ namespace MediaBrowser.Controller.Providers.Movies
|
|||||||
boxset.OfficialRating = firstChild != null ? firstChild.OfficialRating : null;
|
boxset.OfficialRating = firstChild != null ? firstChild.OfficialRating : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (movie.RunTimeTicks == null && movieData.runtime > 0)
|
if (movieData.runtime > 0)
|
||||||
// movie.RunTimeTicks = TimeSpan.FromMinutes(movieData.runtime).Ticks;
|
movie.OriginalRunTimeTicks = TimeSpan.FromMinutes(movieData.runtime).Ticks;
|
||||||
|
|
||||||
//studios
|
//studios
|
||||||
if (movieData.production_companies != null)
|
if (movieData.production_companies != null)
|
||||||
|
@ -46,11 +46,11 @@ namespace MediaBrowser.Controller.Providers.TV
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The episode query
|
/// The episode query
|
||||||
/// </summary>
|
/// </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>
|
/// <summary>
|
||||||
/// The abs episode query
|
/// The abs episode query
|
||||||
/// </summary>
|
/// </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>
|
/// <summary>
|
||||||
/// Supportses the specified item.
|
/// Supportses the specified item.
|
||||||
@ -179,11 +179,28 @@ namespace MediaBrowser.Controller.Providers.TV
|
|||||||
seasonNumber = "0"; // Specials
|
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();
|
var doc = new XmlDocument();
|
||||||
|
|
||||||
try
|
using (var result = await HttpClient.Get(new HttpRequestOptions
|
||||||
{
|
{
|
||||||
|
Url = url,
|
||||||
|
ResourcePool = RemoteSeriesProvider.Current.TvDbResourcePool,
|
||||||
|
CancellationToken = cancellationToken,
|
||||||
|
EnableResponseCache = true
|
||||||
|
|
||||||
|
}).ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
doc.Load(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
//episode does not exist under this season, try absolute numbering.
|
||||||
|
//still assuming it's numbered as 1x01
|
||||||
|
//this is basicly just for anime.
|
||||||
|
if (!doc.HasChildNodes && Int32.Parse(seasonNumber) == 1)
|
||||||
|
{
|
||||||
|
url = string.Format(AbsEpisodeQuery, TVUtils.TvdbApiKey, seriesId, episodeNumber, ConfigurationManager.Configuration.PreferredMetadataLanguage);
|
||||||
|
|
||||||
using (var result = await HttpClient.Get(new HttpRequestOptions
|
using (var result = await HttpClient.Get(new HttpRequestOptions
|
||||||
{
|
{
|
||||||
Url = url,
|
Url = url,
|
||||||
@ -193,37 +210,8 @@ namespace MediaBrowser.Controller.Providers.TV
|
|||||||
|
|
||||||
}).ConfigureAwait(false))
|
}).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
doc.Load(result);
|
if (result != null) doc.Load(result);
|
||||||
}
|
usingAbsoluteData = true;
|
||||||
}
|
|
||||||
catch (HttpException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
//episode does not exist under this season, try absolute numbering.
|
|
||||||
//still assuming it's numbered as 1x01
|
|
||||||
//this is basicly just for anime.
|
|
||||||
if (!doc.HasChildNodes && Int32.Parse(seasonNumber) == 1)
|
|
||||||
{
|
|
||||||
url = string.Format(absEpisodeQuery, TVUtils.TvdbApiKey, seriesId, episodeNumber, ConfigurationManager.Configuration.PreferredMetadataLanguage);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var result = await HttpClient.Get(new HttpRequestOptions
|
|
||||||
{
|
|
||||||
Url = url,
|
|
||||||
ResourcePool = RemoteSeriesProvider.Current.TvDbResourcePool,
|
|
||||||
CancellationToken = cancellationToken,
|
|
||||||
EnableResponseCache = true
|
|
||||||
|
|
||||||
}).ConfigureAwait(false))
|
|
||||||
{
|
|
||||||
if (result != null) doc.Load(result);
|
|
||||||
usingAbsoluteData = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (HttpException)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using System.Globalization;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.Extensions;
|
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
@ -11,6 +10,7 @@ using MediaBrowser.Model.Logging;
|
|||||||
using MediaBrowser.Model.Net;
|
using MediaBrowser.Model.Net;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -142,8 +142,7 @@ namespace MediaBrowser.Controller.Providers.TV
|
|||||||
|
|
||||||
if (item.DontFetchMeta) return false;
|
if (item.DontFetchMeta) return false;
|
||||||
|
|
||||||
return !HasLocalMeta(item) && (ConfigurationManager.Configuration.MetadataRefreshDays != -1 &&
|
return !HasLocalMeta(item) && base.NeedsRefreshInternal(item, providerInfo);
|
||||||
DateTime.UtcNow.Subtract(downloadDate).TotalDays > ConfigurationManager.Configuration.MetadataRefreshDays);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -164,16 +163,17 @@ namespace MediaBrowser.Controller.Providers.TV
|
|||||||
var seriesId = Path.GetFileName(path).GetAttributeValue("tvdbid") ?? await GetSeriesId(series, cancellationToken);
|
var seriesId = Path.GetFileName(path).GetAttributeValue("tvdbid") ?? await GetSeriesId(series, cancellationToken);
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
var status = ProviderRefreshStatus.Success;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(seriesId))
|
if (!string.IsNullOrEmpty(seriesId))
|
||||||
{
|
{
|
||||||
series.SetProviderId(MetadataProviders.Tvdb, seriesId);
|
series.SetProviderId(MetadataProviders.Tvdb, seriesId);
|
||||||
if (!HasCompleteMetadata(series))
|
|
||||||
{
|
status = await FetchSeriesData(series, seriesId, cancellationToken).ConfigureAwait(false);
|
||||||
await FetchSeriesData(series, seriesId, cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
SetLastRefreshed(item, DateTime.UtcNow);
|
|
||||||
|
SetLastRefreshed(item, DateTime.UtcNow, status);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Logger.Info("Series provider not fetching because local meta exists or requested to ignore: " + item.Name);
|
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="seriesId">The series id.</param>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task{System.Boolean}.</returns>
|
/// <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 status = ProviderRefreshStatus.Success;
|
||||||
|
|
||||||
var name = series.Name;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(seriesId))
|
if (!string.IsNullOrEmpty(seriesId))
|
||||||
{
|
{
|
||||||
@ -200,22 +198,16 @@ namespace MediaBrowser.Controller.Providers.TV
|
|||||||
string url = string.Format(seriesGet, TVUtils.TvdbApiKey, seriesId, ConfigurationManager.Configuration.PreferredMetadataLanguage);
|
string url = string.Format(seriesGet, TVUtils.TvdbApiKey, seriesId, ConfigurationManager.Configuration.PreferredMetadataLanguage);
|
||||||
var doc = new XmlDocument();
|
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,
|
||||||
Url = url,
|
CancellationToken = cancellationToken,
|
||||||
ResourcePool = TvDbResourcePool,
|
EnableResponseCache = true
|
||||||
CancellationToken = cancellationToken,
|
|
||||||
EnableResponseCache = true
|
|
||||||
|
|
||||||
}).ConfigureAwait(false))
|
}).ConfigureAwait(false))
|
||||||
{
|
|
||||||
doc.Load(xml);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (HttpException)
|
|
||||||
{
|
{
|
||||||
|
doc.Load(xml);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doc.HasChildNodes)
|
if (doc.HasChildNodes)
|
||||||
@ -224,8 +216,6 @@ namespace MediaBrowser.Controller.Providers.TV
|
|||||||
var actorTask = FetchActors(series, seriesId, doc, cancellationToken);
|
var actorTask = FetchActors(series, seriesId, doc, cancellationToken);
|
||||||
var imageTask = FetchImages(series, seriesId, cancellationToken);
|
var imageTask = FetchImages(series, seriesId, cancellationToken);
|
||||||
|
|
||||||
success = true;
|
|
||||||
|
|
||||||
series.Name = doc.SafeGetString("//SeriesName");
|
series.Name = doc.SafeGetString("//SeriesName");
|
||||||
series.Overview = doc.SafeGetString("//Overview");
|
series.Overview = doc.SafeGetString("//Overview");
|
||||||
series.CommunityRating = doc.SafeGetSingle("//Rating", 0, 10);
|
series.CommunityRating = doc.SafeGetSingle("//Rating", 0, 10);
|
||||||
@ -268,8 +258,15 @@ namespace MediaBrowser.Controller.Providers.TV
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//wait for other tasks
|
try
|
||||||
await Task.WhenAll(actorTask, imageTask).ConfigureAwait(false);
|
{
|
||||||
|
//wait for other tasks
|
||||||
|
await Task.WhenAll(actorTask, imageTask).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (HttpException)
|
||||||
|
{
|
||||||
|
status = ProviderRefreshStatus.CompletedWithErrors;
|
||||||
|
}
|
||||||
|
|
||||||
if (ConfigurationManager.Configuration.SaveLocalMeta)
|
if (ConfigurationManager.Configuration.SaveLocalMeta)
|
||||||
{
|
{
|
||||||
@ -281,9 +278,7 @@ namespace MediaBrowser.Controller.Providers.TV
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -299,22 +294,16 @@ namespace MediaBrowser.Controller.Providers.TV
|
|||||||
string urlActors = string.Format(getActors, TVUtils.TvdbApiKey, seriesId);
|
string urlActors = string.Format(getActors, TVUtils.TvdbApiKey, seriesId);
|
||||||
var docActors = new XmlDocument();
|
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,
|
||||||
Url = urlActors,
|
CancellationToken = cancellationToken,
|
||||||
ResourcePool = TvDbResourcePool,
|
EnableResponseCache = true
|
||||||
CancellationToken = cancellationToken,
|
|
||||||
EnableResponseCache = true
|
|
||||||
|
|
||||||
}).ConfigureAwait(false))
|
}).ConfigureAwait(false))
|
||||||
{
|
|
||||||
docActors.Load(actors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (HttpException)
|
|
||||||
{
|
{
|
||||||
|
docActors.Load(actors);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (docActors.HasChildNodes)
|
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);
|
string url = string.Format("http://www.thetvdb.com/api/" + TVUtils.TvdbApiKey + "/series/{0}/banners.xml", seriesId);
|
||||||
var images = new XmlDocument();
|
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,
|
||||||
Url = url,
|
CancellationToken = cancellationToken,
|
||||||
ResourcePool = TvDbResourcePool,
|
EnableResponseCache = true
|
||||||
CancellationToken = cancellationToken,
|
|
||||||
EnableResponseCache = true
|
|
||||||
|
|
||||||
}).ConfigureAwait(false))
|
}).ConfigureAwait(false))
|
||||||
{
|
|
||||||
images.Load(imgs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (HttpException)
|
|
||||||
{
|
{
|
||||||
|
images.Load(imgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (images.HasChildNodes)
|
if (images.HasChildNodes)
|
||||||
@ -408,17 +391,7 @@ namespace MediaBrowser.Controller.Providers.TV
|
|||||||
n = n.SelectSingleNode("./BannerPath");
|
n = n.SelectSingleNode("./BannerPath");
|
||||||
if (n != null)
|
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);
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -431,19 +404,9 @@ namespace MediaBrowser.Controller.Providers.TV
|
|||||||
n = n.SelectSingleNode("./BannerPath");
|
n = n.SelectSingleNode("./BannerPath");
|
||||||
if (n != null)
|
if (n != null)
|
||||||
{
|
{
|
||||||
try
|
var bannerImagePath = await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n.InnerText, "banner" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, TvDbResourcePool, cancellationToken);
|
||||||
{
|
|
||||||
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);
|
series.SetImage(ImageType.Banner, bannerImagePath);
|
||||||
}
|
|
||||||
catch (HttpException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
catch (IOException)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -460,17 +423,7 @@ namespace MediaBrowser.Controller.Providers.TV
|
|||||||
var bdName = "backdrop" + (bdNo > 0 ? bdNo.ToString(UsCulture) : "");
|
var bdName = "backdrop" + (bdNo > 0 ? bdNo.ToString(UsCulture) : "");
|
||||||
if (ConfigurationManager.Configuration.RefreshItemImages || !series.HasLocalImage(bdName))
|
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));
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
bdNo++;
|
bdNo++;
|
||||||
if (bdNo >= ConfigurationManager.Configuration.MaxBackdrops) break;
|
if (bdNo >= ConfigurationManager.Configuration.MaxBackdrops) break;
|
||||||
@ -480,18 +433,6 @@ 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>
|
/// <summary>
|
||||||
/// Determines whether [has local meta] [the specified item].
|
/// Determines whether [has local meta] [the specified item].
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -499,9 +440,7 @@ namespace MediaBrowser.Controller.Providers.TV
|
|||||||
/// <returns><c>true</c> if [has local meta] [the specified item]; otherwise, <c>false</c>.</returns>
|
/// <returns><c>true</c> if [has local meta] [the specified item]; otherwise, <c>false</c>.</returns>
|
||||||
private bool HasLocalMeta(BaseItem item)
|
private bool HasLocalMeta(BaseItem item)
|
||||||
{
|
{
|
||||||
//need at least the xml and folder.jpg/png
|
return item.ResolveArgs.ContainsMetaFileByName(LOCAL_META_FILE_NAME);
|
||||||
return item.ResolveArgs.ContainsMetaFileByName(LOCAL_META_FILE_NAME) && (item.ResolveArgs.ContainsMetaFileByName("folder.jpg") ||
|
|
||||||
item.ResolveArgs.ContainsMetaFileByName("folder.png"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -63,8 +63,15 @@ namespace MediaBrowser.Controller.Providers.TV
|
|||||||
}
|
}
|
||||||
|
|
||||||
case "Airs_Time":
|
case "Airs_Time":
|
||||||
item.AirTime = reader.ReadElementContentAsString();
|
{
|
||||||
break;
|
var val = reader.ReadElementContentAsString();
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(val))
|
||||||
|
{
|
||||||
|
item.AirTime = val;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case "SeriesName":
|
case "SeriesName":
|
||||||
item.Name = reader.ReadElementContentAsString();
|
item.Name = reader.ReadElementContentAsString();
|
||||||
|
@ -18,9 +18,10 @@ namespace MediaBrowser.Controller.Resolvers
|
|||||||
/// The third
|
/// The third
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Third = 3,
|
Third = 3,
|
||||||
|
Fourth = 4,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The last
|
/// The last
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Last = 4
|
Last = 5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ namespace MediaBrowser.Controller.Session
|
|||||||
/// <param name="deviceId">The device id.</param>
|
/// <param name="deviceId">The device id.</param>
|
||||||
/// <param name="deviceName">Name of the device.</param>
|
/// <param name="deviceName">Name of the device.</param>
|
||||||
/// <exception cref="System.ArgumentNullException"></exception>
|
/// <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>
|
/// <summary>
|
||||||
/// Used to report playback progress for an item
|
/// Used to report playback progress for an item
|
||||||
|
@ -269,16 +269,16 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||||||
// Need to use DistinctBy Id because there could be multiple instances with the same id
|
// Need to use DistinctBy Id because there could be multiple instances with the same id
|
||||||
// due to sharing the default library
|
// due to sharing the default library
|
||||||
var userRootFolders = _userManager.Users.Select(i => i.RootFolder)
|
var userRootFolders = _userManager.Users.Select(i => i.RootFolder)
|
||||||
.DistinctBy(i => i.Id)
|
.Distinct()
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
items.AddRange(userRootFolders);
|
items.AddRange(userRootFolders);
|
||||||
|
|
||||||
// Get all user collection folders
|
// Get all user collection folders
|
||||||
|
// Skip BasePluginFolders because we already got them from RootFolder.RecursiveChildren
|
||||||
var userFolders =
|
var userFolders =
|
||||||
_userManager.Users.SelectMany(i => i.RootFolder.Children)
|
userRootFolders.SelectMany(i => i.Children)
|
||||||
.Where(i => !(i is BasePluginFolder))
|
.Where(i => !(i is BasePluginFolder))
|
||||||
.DistinctBy(i => i.Id)
|
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
items.AddRange(userFolders);
|
items.AddRange(userFolders);
|
||||||
|
@ -408,7 +408,7 @@ namespace MediaBrowser.Server.Implementations.Providers
|
|||||||
{
|
{
|
||||||
return (saveLocally && item.MetaLocation != null) ?
|
return (saveLocally && item.MetaLocation != null) ?
|
||||||
Path.Combine(item.MetaLocation, targetFileName) :
|
Path.Combine(item.MetaLocation, targetFileName) :
|
||||||
_remoteImageCache.GetResourcePath(item.GetType().FullName + item.Path.ToLower(), targetFileName);
|
_remoteImageCache.GetResourcePath(item.GetType().FullName + item.Id.ToString(), targetFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -46,14 +46,14 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
|||||||
|
|
||||||
private readonly List<Audio> _newlyAddedItems = new List<Audio>();
|
private readonly List<Audio> _newlyAddedItems = new List<Audio>();
|
||||||
|
|
||||||
private const int NewItemDelay = 300000;
|
private const int NewItemDelay = 60000;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current new item timer
|
/// The current new item timer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The new item timer.</value>
|
/// <value>The new item timer.</value>
|
||||||
private Timer NewItemTimer { get; set; }
|
private Timer NewItemTimer { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="AudioImagesTask" /> class.
|
/// Initializes a new instance of the <see cref="AudioImagesTask" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -118,7 +118,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
|||||||
|
|
||||||
foreach (var item in newSongs
|
foreach (var item in newSongs
|
||||||
.Where(i => i.LocationType == LocationType.FileSystem && string.IsNullOrEmpty(i.PrimaryImagePath) && i.MediaStreams.Any(m => m.Type == MediaStreamType.Video))
|
.Where(i => i.LocationType == LocationType.FileSystem && string.IsNullOrEmpty(i.PrimaryImagePath) && i.MediaStreams.Any(m => m.Type == MediaStreamType.Video))
|
||||||
.Take(20))
|
.Take(10))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -130,7 +130,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the name of the task
|
/// Gets the name of the task
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -216,7 +216,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
|||||||
|
|
||||||
var filename = item.Album ?? string.Empty;
|
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");
|
var path = ImageCache.GetResourcePath(filename + "_primary", ".jpg");
|
||||||
|
|
||||||
@ -232,7 +232,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
|||||||
{
|
{
|
||||||
try
|
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
|
finally
|
||||||
{
|
{
|
||||||
|
@ -33,7 +33,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
|||||||
|
|
||||||
private readonly List<Video> _newlyAddedItems = new List<Video>();
|
private readonly List<Video> _newlyAddedItems = new List<Video>();
|
||||||
|
|
||||||
private const int NewItemDelay = 300000;
|
private const int NewItemDelay = 60000;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current new item timer
|
/// The current new item timer
|
||||||
@ -95,7 +95,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
|||||||
|
|
||||||
foreach (var item in newItems
|
foreach (var item in newItems
|
||||||
.Where(i => i.LocationType == LocationType.FileSystem && string.IsNullOrEmpty(i.PrimaryImagePath) && i.MediaStreams.Any(m => m.Type == MediaStreamType.Video))
|
.Where(i => i.LocationType == LocationType.FileSystem && string.IsNullOrEmpty(i.PrimaryImagePath) && i.MediaStreams.Any(m => m.Type == MediaStreamType.Video))
|
||||||
.Take(5))
|
.Take(1))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
using MediaBrowser.Common.ScheduledTasks;
|
using MediaBrowser.Common.ScheduledTasks;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Model.Tasks;
|
using MediaBrowser.Model.Tasks;
|
||||||
|
using MediaBrowser.Server.Implementations.Library;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Server.Implementations.Library;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
||||||
{
|
{
|
||||||
|
@ -55,7 +55,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
|||||||
|
|
||||||
private readonly List<BaseItem> _newlyAddedItems = new List<BaseItem>();
|
private readonly List<BaseItem> _newlyAddedItems = new List<BaseItem>();
|
||||||
|
|
||||||
private const int NewItemDelay = 300000;
|
private const int NewItemDelay = 60000;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current new item timer
|
/// The current new item timer
|
||||||
@ -124,7 +124,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
|||||||
NewItemTimer = null;
|
NewItemTimer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var item in GetItemsForExtraction(newItems.Take(5)))
|
foreach (var item in GetItemsForExtraction(newItems.Take(3)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -215,7 +215,8 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
|||||||
|
|
||||||
var videos = allItems.OfType<Video>().ToList();
|
var videos = allItems.OfType<Video>().ToList();
|
||||||
|
|
||||||
var items = videos;
|
var items = videos.ToList();
|
||||||
|
|
||||||
items.AddRange(localTrailers);
|
items.AddRange(localTrailers);
|
||||||
|
|
||||||
items.AddRange(themeVideos);
|
items.AddRange(themeVideos);
|
||||||
|
@ -200,7 +200,7 @@ namespace MediaBrowser.Server.Implementations.Session
|
|||||||
/// <param name="deviceName">Name of the device.</param>
|
/// <param name="deviceName">Name of the device.</param>
|
||||||
/// <exception cref="System.ArgumentNullException">
|
/// <exception cref="System.ArgumentNullException">
|
||||||
/// </exception>
|
/// </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)
|
if (user == null)
|
||||||
{
|
{
|
||||||
@ -213,6 +213,15 @@ namespace MediaBrowser.Server.Implementations.Session
|
|||||||
|
|
||||||
UpdateNowPlayingItemId(user, clientType, deviceId, deviceName, item, false);
|
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
|
// Nothing to save here
|
||||||
// Fire events to inform plugins
|
// Fire events to inform plugins
|
||||||
EventHelper.QueueEventIfNotNull(PlaybackStart, this, new PlaybackProgressEventArgs
|
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);
|
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);
|
await _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,7 +306,7 @@ namespace MediaBrowser.Server.Implementations.Session
|
|||||||
|
|
||||||
if (positionTicks.HasValue)
|
if (positionTicks.HasValue)
|
||||||
{
|
{
|
||||||
UpdatePlayState(item, data, positionTicks.Value, true);
|
UpdatePlayState(item, data, positionTicks.Value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -322,11 +331,12 @@ namespace MediaBrowser.Server.Implementations.Session
|
|||||||
/// <param name="item">The item</param>
|
/// <param name="item">The item</param>
|
||||||
/// <param name="data">User data for the item</param>
|
/// <param name="data">User data for the item</param>
|
||||||
/// <param name="positionTicks">The current playback position</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)
|
||||||
private void UpdatePlayState(BaseItem item, UserItemData data, long positionTicks, bool incrementPlayCount)
|
|
||||||
{
|
{
|
||||||
|
var hasRuntime = item.RunTimeTicks.HasValue && item.RunTimeTicks > 0;
|
||||||
|
|
||||||
// If a position has been reported, and if we know the duration
|
// 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;
|
var pctIn = Decimal.Divide(positionTicks, item.RunTimeTicks.Value) * 100;
|
||||||
|
|
||||||
@ -334,7 +344,6 @@ namespace MediaBrowser.Server.Implementations.Session
|
|||||||
if (pctIn < _configurationManager.Configuration.MinResumePct)
|
if (pctIn < _configurationManager.Configuration.MinResumePct)
|
||||||
{
|
{
|
||||||
positionTicks = 0;
|
positionTicks = 0;
|
||||||
incrementPlayCount = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're at the end, assume completed
|
// 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)
|
if (item is Audio)
|
||||||
{
|
{
|
||||||
data.PlaybackPositionTicks = 0;
|
positionTicks = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
data.PlaybackPositionTicks = positionTicks;
|
data.PlaybackPositionTicks = positionTicks;
|
||||||
|
|
||||||
if (incrementPlayCount)
|
|
||||||
{
|
|
||||||
data.PlayCount++;
|
|
||||||
data.LastPlayedDate = DateTime.UtcNow;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ using MediaBrowser.Controller.Configuration;
|
|||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using MediaBrowser.Server.Implementations;
|
using MediaBrowser.Server.Implementations;
|
||||||
|
using MediaBrowser.ServerApplication.Splash;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
@ -164,11 +165,19 @@ namespace MediaBrowser.ServerApplication
|
|||||||
|
|
||||||
Logger = CompositionRoot.LogManager.GetLogger("App");
|
Logger = CompositionRoot.LogManager.GetLogger("App");
|
||||||
|
|
||||||
|
var splash = new SplashWindow(CompositionRoot.ApplicationVersion);
|
||||||
|
|
||||||
|
splash.Show();
|
||||||
|
|
||||||
await CompositionRoot.Init();
|
await CompositionRoot.Init();
|
||||||
|
|
||||||
var win = new MainWindow(CompositionRoot.LogManager, CompositionRoot, CompositionRoot.ServerConfigurationManager, CompositionRoot.UserManager, CompositionRoot.LibraryManager, CompositionRoot.JsonSerializer, CompositionRoot.DisplayPreferencesManager);
|
splash.Hide();
|
||||||
|
|
||||||
win.Show();
|
var task = CompositionRoot.RunStartupTasks();
|
||||||
|
|
||||||
|
new MainWindow(CompositionRoot.LogManager, CompositionRoot, CompositionRoot.ServerConfigurationManager, CompositionRoot.UserManager, CompositionRoot.LibraryManager, CompositionRoot.JsonSerializer, CompositionRoot.DisplayPreferencesManager).Show();
|
||||||
|
|
||||||
|
await task.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -44,7 +44,6 @@ using MediaBrowser.Server.Implementations.Udp;
|
|||||||
using MediaBrowser.Server.Implementations.Updates;
|
using MediaBrowser.Server.Implementations.Updates;
|
||||||
using MediaBrowser.Server.Implementations.WebSocket;
|
using MediaBrowser.Server.Implementations.WebSocket;
|
||||||
using MediaBrowser.ServerApplication.Implementations;
|
using MediaBrowser.ServerApplication.Implementations;
|
||||||
using MediaBrowser.ServerApplication.Splash;
|
|
||||||
using MediaBrowser.WebDashboard.Api;
|
using MediaBrowser.WebDashboard.Api;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -63,7 +62,7 @@ namespace MediaBrowser.ServerApplication
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ApplicationHost : BaseApplicationHost<ServerApplicationPaths>, IServerApplicationHost
|
public class ApplicationHost : BaseApplicationHost<ServerApplicationPaths>, IServerApplicationHost
|
||||||
{
|
{
|
||||||
private const int UdpServerPort = 7359;
|
internal const int UdpServerPort = 7359;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the server kernel.
|
/// Gets the server kernel.
|
||||||
@ -139,11 +138,6 @@ namespace MediaBrowser.ServerApplication
|
|||||||
/// <value>The HTTP server.</value>
|
/// <value>The HTTP server.</value>
|
||||||
private IHttpServer HttpServer { get; set; }
|
private IHttpServer HttpServer { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the UDP server.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The UDP server.</value>
|
|
||||||
private UdpServer UdpServer { get; set; }
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the display preferences manager.
|
/// Gets or sets the display preferences manager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -175,26 +169,11 @@ namespace MediaBrowser.ServerApplication
|
|||||||
|
|
||||||
private Task<IHttpServer> _httpServerCreationTask;
|
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>
|
/// <summary>
|
||||||
/// Runs the startup tasks.
|
/// Runs the startup tasks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
protected override async Task RunStartupTasks()
|
public override async Task RunStartupTasks()
|
||||||
{
|
{
|
||||||
await base.RunStartupTasks().ConfigureAwait(false);
|
await base.RunStartupTasks().ConfigureAwait(false);
|
||||||
|
|
||||||
@ -390,21 +369,8 @@ namespace MediaBrowser.ServerApplication
|
|||||||
|
|
||||||
() => LibraryManager.AddParts(GetExports<IResolverIgnoreRule>(), GetExports<IVirtualFolderCreator>(), GetExports<IItemResolver>(), GetExports<IIntroProvider>(), GetExports<IBaseItemComparer>()),
|
() => 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,23 +437,6 @@ namespace MediaBrowser.ServerApplication
|
|||||||
get { return ConfigurationManager.CommonConfiguration.EnableAutoUpdate; }
|
get { return ConfigurationManager.CommonConfiguration.EnableAutoUpdate; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <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>
|
/// <summary>
|
||||||
/// Checks for update.
|
/// Checks for update.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -196,6 +196,7 @@
|
|||||||
<Compile Include="EntryPoints\LoadRegistrations.cs" />
|
<Compile Include="EntryPoints\LoadRegistrations.cs" />
|
||||||
<Compile Include="EntryPoints\RefreshUsersMetadata.cs" />
|
<Compile Include="EntryPoints\RefreshUsersMetadata.cs" />
|
||||||
<Compile Include="EntryPoints\StartupWizard.cs" />
|
<Compile Include="EntryPoints\StartupWizard.cs" />
|
||||||
|
<Compile Include="EntryPoints\UdpServerEntryPoint.cs" />
|
||||||
<Compile Include="EntryPoints\WebSocketEvents.cs" />
|
<Compile Include="EntryPoints\WebSocketEvents.cs" />
|
||||||
<Compile Include="Splash\SplashWindow.xaml.cs">
|
<Compile Include="Splash\SplashWindow.xaml.cs">
|
||||||
<DependentUpon>SplashWindow.xaml</DependentUpon>
|
<DependentUpon>SplashWindow.xaml</DependentUpon>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Common.Internal</id>
|
<id>MediaBrowser.Common.Internal</id>
|
||||||
<version>3.0.103</version>
|
<version>3.0.104</version>
|
||||||
<title>MediaBrowser.Common.Internal</title>
|
<title>MediaBrowser.Common.Internal</title>
|
||||||
<authors>Luke</authors>
|
<authors>Luke</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<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>
|
<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>
|
<copyright>Copyright © Media Browser 2013</copyright>
|
||||||
<dependencies>
|
<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="NLog" version="2.0.1.2" />
|
||||||
<dependency id="ServiceStack.Text" version="3.9.45" />
|
<dependency id="ServiceStack.Text" version="3.9.45" />
|
||||||
<dependency id="SimpleInjector" version="2.2.1" />
|
<dependency id="SimpleInjector" version="2.2.1" />
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Common</id>
|
<id>MediaBrowser.Common</id>
|
||||||
<version>3.0.103</version>
|
<version>3.0.104</version>
|
||||||
<title>MediaBrowser.Common</title>
|
<title>MediaBrowser.Common</title>
|
||||||
<authors>Media Browser Team</authors>
|
<authors>Media Browser Team</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Server.Core</id>
|
<id>MediaBrowser.Server.Core</id>
|
||||||
<version>3.0.103</version>
|
<version>3.0.104</version>
|
||||||
<title>Media Browser.Server.Core</title>
|
<title>Media Browser.Server.Core</title>
|
||||||
<authors>Media Browser Team</authors>
|
<authors>Media Browser Team</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<description>Contains core components required to build plugins for Media Browser Server.</description>
|
<description>Contains core components required to build plugins for Media Browser Server.</description>
|
||||||
<copyright>Copyright © Media Browser 2013</copyright>
|
<copyright>Copyright © Media Browser 2013</copyright>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="MediaBrowser.Common" version="3.0.103" />
|
<dependency id="MediaBrowser.Common" version="3.0.104" />
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</metadata>
|
</metadata>
|
||||||
<files>
|
<files>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user