re-factored some file system access
This commit is contained in:
parent
08d9004d8f
commit
02fedead11
|
@ -696,7 +696,8 @@ namespace MediaBrowser.Api.Images
|
|||
Item = item,
|
||||
Request = request,
|
||||
CropWhiteSpace = request.Type == ImageType.Logo || request.Type == ImageType.Art,
|
||||
OriginalImageDateModified = originalFileImageDateModified
|
||||
OriginalImageDateModified = originalFileImageDateModified,
|
||||
Enhancers = supportedImageEnhancers
|
||||
|
||||
}, contentType);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using ServiceStack.Service;
|
||||
using ServiceStack.ServiceHost;
|
||||
using System;
|
||||
|
@ -14,6 +15,8 @@ namespace MediaBrowser.Api.Images
|
|||
/// </summary>
|
||||
public class ImageWriter : IStreamWriter, IHasOptions
|
||||
{
|
||||
public List<IImageEnhancer> Enhancers;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the request.
|
||||
/// </summary>
|
||||
|
@ -67,7 +70,7 @@ namespace MediaBrowser.Api.Images
|
|||
{
|
||||
return Kernel.Instance.ImageManager.ProcessImage(Item, Request.Type, Request.Index ?? 0, CropWhiteSpace,
|
||||
OriginalImageDateModified, responseStream, Request.Width, Request.Height, Request.MaxWidth,
|
||||
Request.MaxHeight, Request.Quality);
|
||||
Request.MaxHeight, Request.Quality, Enhancers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -340,6 +340,13 @@ namespace MediaBrowser.Api.Playback
|
|||
|
||||
try
|
||||
{
|
||||
var parentPath = Path.GetDirectoryName(path);
|
||||
|
||||
if (!Directory.Exists(parentPath))
|
||||
{
|
||||
Directory.CreateDirectory(parentPath);
|
||||
}
|
||||
|
||||
var task = MediaEncoder.ExtractTextSubtitle(inputPath, type, subtitleStream.Index, offset, path, CancellationToken.None);
|
||||
|
||||
Task.WaitAll(task);
|
||||
|
@ -371,6 +378,13 @@ namespace MediaBrowser.Api.Playback
|
|||
{
|
||||
try
|
||||
{
|
||||
var parentPath = Path.GetDirectoryName(path);
|
||||
|
||||
if (!Directory.Exists(parentPath))
|
||||
{
|
||||
Directory.CreateDirectory(parentPath);
|
||||
}
|
||||
|
||||
var task = MediaEncoder.ConvertTextSubtitleToAss(subtitleStream.Path, path, offset, CancellationToken.None);
|
||||
|
||||
Task.WaitAll(task);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
@ -38,6 +37,29 @@ namespace MediaBrowser.Api
|
|||
/// <value>The limit.</value>
|
||||
[ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? Limit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fields to return within the items, in addition to basic information
|
||||
/// </summary>
|
||||
/// <value>The fields.</value>
|
||||
[ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: AudioInfo, Budget, Chapters, CriticRatingSummary, DateCreated, DisplayMediaType, EndDate, Genres, HomePageUrl, ItemCounts, IndexOptions, Locations, MediaStreams, Overview, OverviewHtml, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SeriesInfo, SortName, Studios, Taglines, TrailerUrls, UserData", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Fields { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the item fields.
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{ItemFields}.</returns>
|
||||
public IEnumerable<ItemFields> GetItemFields()
|
||||
{
|
||||
var val = Fields;
|
||||
|
||||
if (string.IsNullOrEmpty(val))
|
||||
{
|
||||
return new ItemFields[] { };
|
||||
}
|
||||
|
||||
return val.Split(',').Select(v => (ItemFields)Enum.Parse(typeof(ItemFields), v, true));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -64,8 +86,7 @@ namespace MediaBrowser.Api
|
|||
(request.UserId.HasValue ? user.RootFolder :
|
||||
(Folder)libraryManager.RootFolder) : DtoBuilder.GetItemByClientId(request.Id, userManager, libraryManager, request.UserId);
|
||||
|
||||
// Get everything
|
||||
var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
|
||||
var fields = request.GetItemFields().ToList();
|
||||
|
||||
var dtoBuilder = new DtoBuilder(logger, libraryManager, userDataRepository);
|
||||
|
||||
|
|
|
@ -123,9 +123,14 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||
{
|
||||
try
|
||||
{
|
||||
return JsonSerializer.DeserializeFromFile<TaskResult>(GetHistoryFilePath());
|
||||
return JsonSerializer.DeserializeFromFile<TaskResult>(GetHistoryFilePath(false));
|
||||
}
|
||||
catch (IOException)
|
||||
catch (DirectoryNotFoundException)
|
||||
{
|
||||
// File doesn't exist. No biggie
|
||||
return null;
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
// File doesn't exist. No biggie
|
||||
return null;
|
||||
|
@ -413,63 +418,46 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The _scheduled tasks configuration directory
|
||||
/// </summary>
|
||||
private string _scheduledTasksConfigurationDirectory;
|
||||
/// <summary>
|
||||
/// Gets the scheduled tasks configuration directory.
|
||||
/// </summary>
|
||||
/// <value>The scheduled tasks configuration directory.</value>
|
||||
private string ScheduledTasksConfigurationDirectory
|
||||
/// <param name="create">if set to <c>true</c> [create].</param>
|
||||
/// <returns>System.String.</returns>
|
||||
private string GetScheduledTasksConfigurationDirectory(bool create)
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_scheduledTasksConfigurationDirectory == null)
|
||||
{
|
||||
_scheduledTasksConfigurationDirectory = Path.Combine(ApplicationPaths.ConfigurationDirectoryPath, "ScheduledTasks");
|
||||
var path = Path.Combine(ApplicationPaths.ConfigurationDirectoryPath, "ScheduledTasks");
|
||||
|
||||
if (!Directory.Exists(_scheduledTasksConfigurationDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(_scheduledTasksConfigurationDirectory);
|
||||
}
|
||||
}
|
||||
return _scheduledTasksConfigurationDirectory;
|
||||
if (create && !Directory.Exists(path))
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The _scheduled tasks data directory
|
||||
/// </summary>
|
||||
private string _scheduledTasksDataDirectory;
|
||||
/// <summary>
|
||||
/// Gets the scheduled tasks data directory.
|
||||
/// </summary>
|
||||
/// <value>The scheduled tasks data directory.</value>
|
||||
private string ScheduledTasksDataDirectory
|
||||
/// <param name="create">if set to <c>true</c> [create].</param>
|
||||
/// <returns>System.String.</returns>
|
||||
private string GetScheduledTasksDataDirectory(bool create)
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_scheduledTasksDataDirectory == null)
|
||||
{
|
||||
_scheduledTasksDataDirectory = Path.Combine(ApplicationPaths.DataPath, "ScheduledTasks");
|
||||
var path = Path.Combine(ApplicationPaths.DataPath, "ScheduledTasks");
|
||||
|
||||
if (!Directory.Exists(_scheduledTasksDataDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(_scheduledTasksDataDirectory);
|
||||
}
|
||||
}
|
||||
return _scheduledTasksDataDirectory;
|
||||
if (create && !Directory.Exists(path))
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the history file path.
|
||||
/// </summary>
|
||||
/// <value>The history file path.</value>
|
||||
private string GetHistoryFilePath()
|
||||
private string GetHistoryFilePath(bool createDirectory)
|
||||
{
|
||||
return Path.Combine(ScheduledTasksDataDirectory, Id + ".js");
|
||||
return Path.Combine(GetScheduledTasksDataDirectory(createDirectory), Id + ".js");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -478,7 +466,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||
/// <returns>System.String.</returns>
|
||||
private string GetConfigurationFilePath()
|
||||
{
|
||||
return Path.Combine(ScheduledTasksConfigurationDirectory, Id + ".js");
|
||||
return Path.Combine(GetScheduledTasksConfigurationDirectory(false), Id + ".js");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -493,7 +481,12 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||
.Select(ScheduledTaskHelpers.GetTrigger)
|
||||
.ToList();
|
||||
}
|
||||
catch (IOException)
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
// File doesn't exist. No biggie. Return defaults.
|
||||
return ScheduledTask.GetDefaultTriggers();
|
||||
}
|
||||
catch (DirectoryNotFoundException)
|
||||
{
|
||||
// File doesn't exist. No biggie. Return defaults.
|
||||
return ScheduledTask.GetDefaultTriggers();
|
||||
|
@ -530,7 +523,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||
Id = Id
|
||||
};
|
||||
|
||||
JsonSerializer.SerializeToFile(result, GetHistoryFilePath());
|
||||
JsonSerializer.SerializeToFile(result, GetHistoryFilePath(true));
|
||||
|
||||
LastExecutionResult = result;
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using MediaBrowser.Common.Extensions;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
|
||||
namespace MediaBrowser.Common.IO
|
||||
|
@ -11,12 +10,6 @@ namespace MediaBrowser.Common.IO
|
|||
/// </summary>
|
||||
public class FileSystemRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the list of subfolders under the main directory
|
||||
/// The directory entry is created when the item is first added to the dictionary
|
||||
/// </summary>
|
||||
private readonly ConcurrentDictionary<string, string> _subFolderPaths = new ConcurrentDictionary<string, string>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path.
|
||||
/// </summary>
|
||||
|
@ -36,18 +29,6 @@ namespace MediaBrowser.Common.IO
|
|||
}
|
||||
|
||||
Path = path;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes this instance.
|
||||
/// </summary>
|
||||
protected void Initialize()
|
||||
{
|
||||
if (!Directory.Exists(Path))
|
||||
{
|
||||
Directory.CreateDirectory(Path);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -56,17 +37,18 @@ namespace MediaBrowser.Common.IO
|
|||
/// <param name="uniqueName">Name of the unique.</param>
|
||||
/// <param name="fileExtension">The file extension.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
/// <exception cref="System.ArgumentNullException"></exception>
|
||||
/// <exception cref="System.ArgumentNullException">
|
||||
/// </exception>
|
||||
public string GetResourcePath(string uniqueName, string fileExtension)
|
||||
{
|
||||
if (string.IsNullOrEmpty(uniqueName))
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
throw new ArgumentNullException("uniqueName");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(fileExtension))
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
throw new ArgumentNullException("fileExtension");
|
||||
}
|
||||
|
||||
var filename = uniqueName.GetMD5() + fileExtension;
|
||||
|
@ -75,7 +57,7 @@ namespace MediaBrowser.Common.IO
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the full path of where a file should be stored within the repository
|
||||
/// Gets the resource path.
|
||||
/// </summary>
|
||||
/// <param name="filename">The filename.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
|
@ -84,41 +66,14 @@ namespace MediaBrowser.Common.IO
|
|||
{
|
||||
if (string.IsNullOrEmpty(filename))
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
throw new ArgumentNullException("filename");
|
||||
}
|
||||
|
||||
return GetInternalResourcePath(filename);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes a filename and returns the full path of where it should be stored
|
||||
/// </summary>
|
||||
/// <param name="filename">The filename.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
private string GetInternalResourcePath(string filename)
|
||||
{
|
||||
var prefix = filename.Substring(0, 1);
|
||||
|
||||
var folder = _subFolderPaths.GetOrAdd(prefix, GetCachePath);
|
||||
|
||||
return System.IO.Path.Combine(folder, filename);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a subfolder under the image cache directory and returns the full path
|
||||
/// </summary>
|
||||
/// <param name="prefix">The prefix.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
private string GetCachePath(string prefix)
|
||||
{
|
||||
var path = System.IO.Path.Combine(Path, prefix);
|
||||
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
return path;
|
||||
return System.IO.Path.Combine(path, filename);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -145,7 +100,7 @@ namespace MediaBrowser.Common.IO
|
|||
throw new ArgumentNullException();
|
||||
}
|
||||
|
||||
return ContainsFilePath(GetInternalResourcePath(filename));
|
||||
return ContainsFilePath(GetResourcePath(filename));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -106,9 +106,10 @@ namespace MediaBrowser.Controller.Drawing
|
|||
/// <param name="maxWidth">Use if a max width is required. Aspect ratio will be preserved.</param>
|
||||
/// <param name="maxHeight">Use if a max height is required. Aspect ratio will be preserved.</param>
|
||||
/// <param name="quality">Quality level, from 0-100. Currently only applies to JPG. The default value should suffice.</param>
|
||||
/// <param name="enhancers">The enhancers.</param>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">entity</exception>
|
||||
public async Task ProcessImage(BaseItem entity, ImageType imageType, int imageIndex, bool cropWhitespace, DateTime dateModified, Stream toStream, int? width, int? height, int? maxWidth, int? maxHeight, int? quality)
|
||||
public async Task ProcessImage(BaseItem entity, ImageType imageType, int imageIndex, bool cropWhitespace, DateTime dateModified, Stream toStream, int? width, int? height, int? maxWidth, int? maxHeight, int? quality, List<IImageEnhancer> enhancers)
|
||||
{
|
||||
if (entity == null)
|
||||
{
|
||||
|
@ -127,28 +128,13 @@ namespace MediaBrowser.Controller.Drawing
|
|||
originalImagePath = await GetCroppedImage(originalImagePath, dateModified).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var supportedEnhancers = ImageEnhancers.Where(i =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return i.Supports(entity, imageType);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error in image enhancer: {0}", ex, i.GetType().Name);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}).ToList();
|
||||
|
||||
// No enhancement - don't cache
|
||||
if (supportedEnhancers.Count > 0)
|
||||
if (enhancers.Count > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Enhance if we have enhancers
|
||||
var ehnancedImagePath = await GetEnhancedImage(originalImagePath, dateModified, entity, imageType, imageIndex, supportedEnhancers).ConfigureAwait(false);
|
||||
var ehnancedImagePath = await GetEnhancedImage(originalImagePath, dateModified, entity, imageType, imageIndex, enhancers).ConfigureAwait(false);
|
||||
|
||||
// If the path changed update dateModified
|
||||
if (!ehnancedImagePath.Equals(originalImagePath, StringComparison.OrdinalIgnoreCase))
|
||||
|
@ -175,6 +161,19 @@ namespace MediaBrowser.Controller.Drawing
|
|||
|
||||
var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality.Value, dateModified);
|
||||
|
||||
try
|
||||
{
|
||||
using (var fileStream = new FileStream(cacheFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
|
||||
{
|
||||
await fileStream.CopyToAsync(toStream).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
// Cache file doesn't exist or is currently being written ro
|
||||
}
|
||||
|
||||
var semaphore = GetLock(cacheFilePath);
|
||||
|
||||
await semaphore.WaitAsync().ConfigureAwait(false);
|
||||
|
@ -262,6 +261,13 @@ namespace MediaBrowser.Controller.Drawing
|
|||
/// <param name="bytes">The bytes.</param>
|
||||
private async Task CacheResizedImage(string cacheFilePath, byte[] bytes)
|
||||
{
|
||||
var parentPath = Path.GetDirectoryName(cacheFilePath);
|
||||
|
||||
if (!Directory.Exists(parentPath))
|
||||
{
|
||||
Directory.CreateDirectory(parentPath);
|
||||
}
|
||||
|
||||
// Save to the cache location
|
||||
using (var cacheFileStream = new FileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
|
||||
{
|
||||
|
@ -335,25 +341,53 @@ namespace MediaBrowser.Controller.Drawing
|
|||
// Now check the file system cache
|
||||
var fullCachePath = ImageSizeCache.GetResourcePath(keyName, ".txt");
|
||||
|
||||
try
|
||||
{
|
||||
var result = File.ReadAllText(fullCachePath).Split('|').Select(i => double.Parse(i, UsCulture)).ToArray();
|
||||
|
||||
return new ImageSize { Width = result[0], Height = result[1] };
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
// Cache file doesn't exist or is currently being written to
|
||||
}
|
||||
|
||||
var semaphore = GetLock(fullCachePath);
|
||||
|
||||
await semaphore.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = File.ReadAllText(fullCachePath).Split('|').Select(i => double.Parse(i, UsCulture)).ToArray();
|
||||
var result = File.ReadAllText(fullCachePath).Split('|').Select(i => double.Parse(i, UsCulture)).ToArray();
|
||||
|
||||
return new ImageSize { Width = result[0], Height = result[1] };
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
// Cache file doesn't exist no biggie
|
||||
}
|
||||
return new ImageSize { Width = result[0], Height = result[1] };
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
// Cache file doesn't exist no biggie
|
||||
}
|
||||
catch (DirectoryNotFoundException)
|
||||
{
|
||||
// Cache file doesn't exist no biggie
|
||||
}
|
||||
catch
|
||||
{
|
||||
semaphore.Release();
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var size = await ImageHeader.GetDimensions(imagePath, _logger).ConfigureAwait(false);
|
||||
|
||||
var parentPath = Path.GetDirectoryName(fullCachePath);
|
||||
|
||||
if (!Directory.Exists(parentPath))
|
||||
{
|
||||
Directory.CreateDirectory(parentPath);
|
||||
}
|
||||
|
||||
// Update the file system cache
|
||||
File.WriteAllText(fullCachePath, size.Width.ToString(UsCulture) + @"|" + size.Height.ToString(UsCulture));
|
||||
|
||||
|
@ -490,7 +524,7 @@ namespace MediaBrowser.Controller.Drawing
|
|||
await semaphore.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
// Check again in case of contention
|
||||
if (CroppedImageCache.ContainsFilePath(croppedImagePath))
|
||||
if (File.Exists(croppedImagePath))
|
||||
{
|
||||
semaphore.Release();
|
||||
return croppedImagePath;
|
||||
|
@ -511,6 +545,13 @@ namespace MediaBrowser.Controller.Drawing
|
|||
|
||||
using (var croppedImage = originalImage.CropWhitespace())
|
||||
{
|
||||
var parentPath = Path.GetDirectoryName(croppedImagePath);
|
||||
|
||||
if (!Directory.Exists(parentPath))
|
||||
{
|
||||
Directory.CreateDirectory(parentPath);
|
||||
}
|
||||
|
||||
using (var outputStream = new FileStream(croppedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read))
|
||||
{
|
||||
croppedImage.Save(outputFormat, outputStream, 100);
|
||||
|
@ -568,7 +609,7 @@ namespace MediaBrowser.Controller.Drawing
|
|||
await semaphore.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
// Check again in case of contention
|
||||
if (EnhancedImageCache.ContainsFilePath(enhancedImagePath))
|
||||
if (File.Exists(enhancedImagePath))
|
||||
{
|
||||
semaphore.Release();
|
||||
return enhancedImagePath;
|
||||
|
@ -588,6 +629,13 @@ namespace MediaBrowser.Controller.Drawing
|
|||
//Pass the image through registered enhancers
|
||||
using (var newImage = await ExecuteImageEnhancers(supportedEnhancers, originalImage, item, imageType, imageIndex).ConfigureAwait(false))
|
||||
{
|
||||
var parentDirectory = Path.GetDirectoryName(enhancedImagePath);
|
||||
|
||||
if (!Directory.Exists(parentDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(parentDirectory);
|
||||
}
|
||||
|
||||
//And then save it in the cache
|
||||
using (var outputStream = new FileStream(enhancedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read))
|
||||
{
|
||||
|
|
|
@ -304,7 +304,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <summary>
|
||||
/// We attach these to the item so that we only ever have to hit the file system once
|
||||
/// (this includes the children of the containing folder)
|
||||
/// Use ResolveArgs.FileSystemDictionary to check for the existence of files instead of File.Exists
|
||||
/// </summary>
|
||||
/// <value>The resolve args.</value>
|
||||
[IgnoreDataMember]
|
||||
|
|
|
@ -19,10 +19,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
public static IUserManager UserManager { get; set; }
|
||||
public static IXmlSerializer XmlSerializer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The _root folder path
|
||||
/// </summary>
|
||||
private string _rootFolderPath;
|
||||
/// <summary>
|
||||
/// Gets the root folder path.
|
||||
/// </summary>
|
||||
|
@ -32,23 +28,19 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
get
|
||||
{
|
||||
if (_rootFolderPath == null)
|
||||
if (Configuration.UseCustomLibrary)
|
||||
{
|
||||
if (Configuration.UseCustomLibrary)
|
||||
{
|
||||
_rootFolderPath = GetRootFolderPath(Name);
|
||||
var rootFolderPath = GetRootFolderPath(Name);
|
||||
|
||||
if (!Directory.Exists(_rootFolderPath))
|
||||
{
|
||||
Directory.CreateDirectory(_rootFolderPath);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!Directory.Exists(rootFolderPath))
|
||||
{
|
||||
_rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
|
||||
Directory.CreateDirectory(rootFolderPath);
|
||||
}
|
||||
|
||||
return rootFolderPath;
|
||||
}
|
||||
return _rootFolderPath;
|
||||
|
||||
return ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -261,7 +253,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
// Force these to be lazy loaded again
|
||||
_configurationDirectoryPath = null;
|
||||
_rootFolderPath = null;
|
||||
RootFolder = null;
|
||||
|
||||
// Kick off a task to validate the media library
|
||||
|
@ -378,7 +369,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
// Force these to be lazy loaded again
|
||||
if (customLibraryChanged)
|
||||
{
|
||||
_rootFolderPath = null;
|
||||
RootFolder = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,10 +55,6 @@ namespace MediaBrowser.Controller.MediaInfo
|
|||
SubtitleCache = new FileSystemRepository(SubtitleCachePath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The _video images data path
|
||||
/// </summary>
|
||||
private string _videoImagesDataPath;
|
||||
/// <summary>
|
||||
/// Gets the video images data path.
|
||||
/// </summary>
|
||||
|
@ -67,24 +63,10 @@ namespace MediaBrowser.Controller.MediaInfo
|
|||
{
|
||||
get
|
||||
{
|
||||
if (_videoImagesDataPath == null)
|
||||
{
|
||||
_videoImagesDataPath = Path.Combine(_appPaths.DataPath, "extracted-video-images");
|
||||
|
||||
if (!Directory.Exists(_videoImagesDataPath))
|
||||
{
|
||||
Directory.CreateDirectory(_videoImagesDataPath);
|
||||
}
|
||||
}
|
||||
|
||||
return _videoImagesDataPath;
|
||||
return Path.Combine(_appPaths.DataPath, "extracted-video-images");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The _audio images data path
|
||||
/// </summary>
|
||||
private string _audioImagesDataPath;
|
||||
/// <summary>
|
||||
/// Gets the audio images data path.
|
||||
/// </summary>
|
||||
|
@ -93,24 +75,10 @@ namespace MediaBrowser.Controller.MediaInfo
|
|||
{
|
||||
get
|
||||
{
|
||||
if (_audioImagesDataPath == null)
|
||||
{
|
||||
_audioImagesDataPath = Path.Combine(_appPaths.DataPath, "extracted-audio-images");
|
||||
|
||||
if (!Directory.Exists(_audioImagesDataPath))
|
||||
{
|
||||
Directory.CreateDirectory(_audioImagesDataPath);
|
||||
}
|
||||
}
|
||||
|
||||
return _audioImagesDataPath;
|
||||
return Path.Combine(_appPaths.DataPath, "extracted-audio-images");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The _subtitle cache path
|
||||
/// </summary>
|
||||
private string _subtitleCachePath;
|
||||
/// <summary>
|
||||
/// Gets the subtitle cache path.
|
||||
/// </summary>
|
||||
|
@ -119,17 +87,7 @@ namespace MediaBrowser.Controller.MediaInfo
|
|||
{
|
||||
get
|
||||
{
|
||||
if (_subtitleCachePath == null)
|
||||
{
|
||||
_subtitleCachePath = Path.Combine(_appPaths.CachePath, "subtitles");
|
||||
|
||||
if (!Directory.Exists(_subtitleCachePath))
|
||||
{
|
||||
Directory.CreateDirectory(_subtitleCachePath);
|
||||
}
|
||||
}
|
||||
|
||||
return _subtitleCachePath;
|
||||
return Path.Combine(_appPaths.CachePath, "subtitles");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,7 +135,7 @@ namespace MediaBrowser.Controller.MediaInfo
|
|||
|
||||
var path = VideoImageCache.GetResourcePath(filename, ".jpg");
|
||||
|
||||
if (!VideoImageCache.ContainsFilePath(path))
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
if (extractImages)
|
||||
{
|
||||
|
@ -204,6 +162,13 @@ namespace MediaBrowser.Controller.MediaInfo
|
|||
|
||||
try
|
||||
{
|
||||
var parentPath = Path.GetDirectoryName(path);
|
||||
|
||||
if (!Directory.Exists(parentPath))
|
||||
{
|
||||
Directory.CreateDirectory(parentPath);
|
||||
}
|
||||
|
||||
await _encoder.ExtractImage(inputPath, type, time, path, cancellationToken).ConfigureAwait(false);
|
||||
chapter.ImagePath = path;
|
||||
changesMade = true;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using MediaBrowser.Common.IO;
|
||||
using System.IO;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Common.MediaInfo;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
|
@ -156,7 +157,7 @@ namespace MediaBrowser.Controller.Providers.MediaInfo
|
|||
|
||||
var path = ImageCache.GetResourcePath(filename + "_primary", ".jpg");
|
||||
|
||||
if (!ImageCache.ContainsFilePath(path))
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
var semaphore = GetLock(path);
|
||||
|
||||
|
@ -164,10 +165,17 @@ namespace MediaBrowser.Controller.Providers.MediaInfo
|
|||
await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// Check again
|
||||
if (!ImageCache.ContainsFilePath(path))
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
try
|
||||
{
|
||||
var parentPath = Path.GetDirectoryName(path);
|
||||
|
||||
if (!Directory.Exists(parentPath))
|
||||
{
|
||||
Directory.CreateDirectory(parentPath);
|
||||
}
|
||||
|
||||
await _mediaEncoder.ExtractImage(new[] { item.Path }, InputType.AudioFile, null, path, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
|
|
|
@ -244,6 +244,9 @@
|
|||
<Compile Include="..\MediaBrowser.Model\Querying\PersonsQuery.cs">
|
||||
<Link>Querying\PersonsQuery.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Querying\SimilarItemsQuery.cs">
|
||||
<Link>Querying\SimilarItemsQuery.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Querying\ThemeSongsResult.cs">
|
||||
<Link>Querying\ThemeSongsResult.cs</Link>
|
||||
</Compile>
|
||||
|
|
|
@ -72,6 +72,34 @@ namespace MediaBrowser.Model.ApiClient
|
|||
/// <exception cref="ArgumentNullException">query</exception>
|
||||
Task<ItemsResult> GetItemsAsync(ItemQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the similar movies async.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>Task{ItemsResult}.</returns>
|
||||
Task<ItemsResult> GetSimilarMoviesAsync(SimilarItemsQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the similar series async.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>Task{ItemsResult}.</returns>
|
||||
Task<ItemsResult> GetSimilarSeriesAsync(SimilarItemsQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the similar albums async.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>Task{ItemsResult}.</returns>
|
||||
Task<ItemsResult> GetSimilarAlbumsAsync(SimilarItemsQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the similar games async.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>Task{ItemsResult}.</returns>
|
||||
Task<ItemsResult> GetSimilarGamesAsync(SimilarItemsQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the people async.
|
||||
/// </summary>
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
<Compile Include="Querying\ItemReviewsResult.cs" />
|
||||
<Compile Include="Querying\ItemsByNameQuery.cs" />
|
||||
<Compile Include="Entities\BaseItemInfo.cs" />
|
||||
<Compile Include="Querying\SimilarItemsQuery.cs" />
|
||||
<Compile Include="Session\BrowseRequest.cs" />
|
||||
<Compile Include="Session\PlayRequest.cs" />
|
||||
<Compile Include="Session\PlaystateRequest.cs" />
|
||||
|
|
29
MediaBrowser.Model/Querying/SimilarItemsQuery.cs
Normal file
29
MediaBrowser.Model/Querying/SimilarItemsQuery.cs
Normal file
|
@ -0,0 +1,29 @@
|
|||
namespace MediaBrowser.Model.Querying
|
||||
{
|
||||
public class SimilarItemsQuery
|
||||
{
|
||||
/// <summary>
|
||||
/// The user to localize search results for
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
public string UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The maximum number of items to return
|
||||
/// </summary>
|
||||
/// <value>The limit.</value>
|
||||
public int? Limit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fields to return within the items, in addition to basic information
|
||||
/// </summary>
|
||||
/// <value>The fields.</value>
|
||||
public ItemFields[] Fields { get; set; }
|
||||
}
|
||||
}
|
|
@ -94,29 +94,20 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// The _media tools path
|
||||
/// Gets the media tools path.
|
||||
/// </summary>
|
||||
private string _mediaToolsPath;
|
||||
/// <summary>
|
||||
/// Gets the folder path to tools
|
||||
/// </summary>
|
||||
/// <value>The media tools path.</value>
|
||||
private string MediaToolsPath
|
||||
/// <param name="create">if set to <c>true</c> [create].</param>
|
||||
/// <returns>System.String.</returns>
|
||||
private string GetMediaToolsPath(bool create)
|
||||
{
|
||||
get
|
||||
var path = Path.Combine(_appPaths.ProgramDataPath, "ffmpeg");
|
||||
|
||||
if (create && !Directory.Exists(path))
|
||||
{
|
||||
if (_mediaToolsPath == null)
|
||||
{
|
||||
_mediaToolsPath = Path.Combine(_appPaths.ProgramDataPath, "ffmpeg");
|
||||
|
||||
if (!Directory.Exists(_mediaToolsPath))
|
||||
{
|
||||
Directory.CreateDirectory(_mediaToolsPath);
|
||||
}
|
||||
}
|
||||
|
||||
return _mediaToolsPath;
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -185,7 +176,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
|
|||
|
||||
var filename = resource.Substring(resource.IndexOf(prefix, StringComparison.OrdinalIgnoreCase) + prefix.Length);
|
||||
|
||||
var versionedDirectoryPath = Path.Combine(MediaToolsPath, Path.GetFileNameWithoutExtension(filename));
|
||||
var versionedDirectoryPath = Path.Combine(GetMediaToolsPath(true), Path.GetFileNameWithoutExtension(filename));
|
||||
|
||||
if (!Directory.Exists(versionedDirectoryPath))
|
||||
{
|
||||
|
|
|
@ -328,9 +328,7 @@ namespace MediaBrowser.Server.Implementations.Providers
|
|||
public async Task<string> SaveImage(BaseItem item, Stream source, string targetName, bool saveLocally, CancellationToken cancellationToken)
|
||||
{
|
||||
//download and save locally
|
||||
var localPath = (saveLocally && item.MetaLocation != null) ?
|
||||
Path.Combine(item.MetaLocation, targetName) :
|
||||
_remoteImageCache.GetResourcePath(item.GetType().FullName + item.Path.ToLower(), targetName);
|
||||
var localPath = GetSavePath(item, targetName, saveLocally);
|
||||
|
||||
if (saveLocally) // queue to media directories
|
||||
{
|
||||
|
@ -374,9 +372,18 @@ namespace MediaBrowser.Server.Implementations.Providers
|
|||
/// <returns>System.String.</returns>
|
||||
public string GetSavePath(BaseItem item, string targetFileName, bool saveLocally)
|
||||
{
|
||||
return (saveLocally && item.MetaLocation != null) ?
|
||||
var path = (saveLocally && item.MetaLocation != null) ?
|
||||
Path.Combine(item.MetaLocation, targetFileName) :
|
||||
_remoteImageCache.GetResourcePath(item.GetType().FullName + item.Id.ToString(), targetFileName);
|
||||
|
||||
var parentPath = Path.GetDirectoryName(path);
|
||||
|
||||
if (!Directory.Exists(parentPath))
|
||||
{
|
||||
Directory.CreateDirectory(parentPath);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -168,6 +168,14 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
|||
if (!success)
|
||||
{
|
||||
previouslyFailedImages.Add(key);
|
||||
|
||||
var parentPath = Path.GetDirectoryName(failHistoryPath);
|
||||
|
||||
if (!Directory.Exists(parentPath))
|
||||
{
|
||||
Directory.CreateDirectory(parentPath);
|
||||
}
|
||||
|
||||
_jsonSerializer.SerializeToFile(previouslyFailedImages, failHistoryPath);
|
||||
}
|
||||
|
||||
|
|
|
@ -176,13 +176,20 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
|||
/// <returns>IEnumerable{System.String}.</returns>
|
||||
private IEnumerable<string> GetFiles(string path)
|
||||
{
|
||||
return Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)
|
||||
.Where(i =>
|
||||
{
|
||||
var ext = Path.GetExtension(i);
|
||||
try
|
||||
{
|
||||
return Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)
|
||||
.Where(i =>
|
||||
{
|
||||
var ext = Path.GetExtension(i);
|
||||
|
||||
return !string.IsNullOrEmpty(ext) && BaseItem.SupportedImageExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase);
|
||||
});
|
||||
return !string.IsNullOrEmpty(ext) && BaseItem.SupportedImageExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase);
|
||||
});
|
||||
}
|
||||
catch (DirectoryNotFoundException)
|
||||
{
|
||||
return new string[] { };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -8,14 +8,15 @@ using MediaBrowser.Controller.Library;
|
|||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Providers.MediaInfo;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MoreLinq;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MoreLinq;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
||||
{
|
||||
|
@ -263,7 +264,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
|||
|
||||
var path = ImageCache.GetResourcePath(filename, ".jpg");
|
||||
|
||||
if (!ImageCache.ContainsFilePath(path))
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
var semaphore = GetLock(path);
|
||||
|
||||
|
@ -271,10 +272,17 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
|||
await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// Check again
|
||||
if (!ImageCache.ContainsFilePath(path))
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
try
|
||||
{
|
||||
var parentPath = Path.GetDirectoryName(path);
|
||||
|
||||
if (!Directory.Exists(parentPath))
|
||||
{
|
||||
Directory.CreateDirectory(parentPath);
|
||||
}
|
||||
|
||||
await ExtractImageInternal(item, path, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
|
|
|
@ -471,20 +471,18 @@ namespace MediaBrowser.Server.Implementations.Sqlite
|
|||
/// <summary>
|
||||
/// Gets the critic reviews path.
|
||||
/// </summary>
|
||||
/// <value>The critic reviews path.</value>
|
||||
private string CriticReviewsPath
|
||||
/// <param name="create">if set to <c>true</c> [create].</param>
|
||||
/// <returns>System.String.</returns>
|
||||
private string GetCriticReviewsPath(bool create)
|
||||
{
|
||||
get
|
||||
var path = Path.Combine(_appPaths.DataPath, "critic-reviews");
|
||||
|
||||
if (create && !Directory.Exists(path))
|
||||
{
|
||||
var path = Path.Combine(_appPaths.DataPath, "critic-reviews");
|
||||
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
return path;
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -499,10 +497,14 @@ namespace MediaBrowser.Server.Implementations.Sqlite
|
|||
|
||||
try
|
||||
{
|
||||
var path = Path.Combine(CriticReviewsPath, itemId + ".json");
|
||||
var path = Path.Combine(GetCriticReviewsPath(false), itemId + ".json");
|
||||
|
||||
return _jsonSerializer.DeserializeFromFile<List<ItemReview>>(path);
|
||||
}
|
||||
catch (DirectoryNotFoundException)
|
||||
{
|
||||
return new List<ItemReview>();
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
return new List<ItemReview>();
|
||||
|
@ -521,7 +523,7 @@ namespace MediaBrowser.Server.Implementations.Sqlite
|
|||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var path = Path.Combine(CriticReviewsPath, itemId + ".json");
|
||||
var path = Path.Combine(GetCriticReviewsPath(true), itemId + ".json");
|
||||
|
||||
_jsonSerializer.SerializeToFile(criticReviews.ToList(), path);
|
||||
});
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>MediaBrowser.Common.Internal</id>
|
||||
<version>3.0.112</version>
|
||||
<version>3.0.113</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.112" />
|
||||
<dependency id="MediaBrowser.Common" version="3.0.113" />
|
||||
<dependency id="NLog" version="2.0.1.2" />
|
||||
<dependency id="ServiceStack.Text" version="3.9.45" />
|
||||
<dependency id="SimpleInjector" version="2.2.3" />
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>MediaBrowser.Common</id>
|
||||
<version>3.0.112</version>
|
||||
<version>3.0.113</version>
|
||||
<title>MediaBrowser.Common</title>
|
||||
<authors>Media Browser Team</authors>
|
||||
<owners>ebr,Luke,scottisafool</owners>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>MediaBrowser.Server.Core</id>
|
||||
<version>3.0.112</version>
|
||||
<version>3.0.113</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.112" />
|
||||
<dependency id="MediaBrowser.Common" version="3.0.113" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
|
|
Loading…
Reference in New Issue
Block a user