re-factored some file system access

This commit is contained in:
Luke Pulverenti 2013-06-03 22:02:49 -04:00
parent 08d9004d8f
commit 02fedead11
24 changed files with 339 additions and 258 deletions

View File

@ -696,7 +696,8 @@ namespace MediaBrowser.Api.Images
Item = item, Item = item,
Request = request, Request = request,
CropWhiteSpace = request.Type == ImageType.Logo || request.Type == ImageType.Art, CropWhiteSpace = request.Type == ImageType.Logo || request.Type == ImageType.Art,
OriginalImageDateModified = originalFileImageDateModified OriginalImageDateModified = originalFileImageDateModified,
Enhancers = supportedImageEnhancers
}, contentType); }, contentType);
} }

View File

@ -1,5 +1,6 @@
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
using ServiceStack.Service; using ServiceStack.Service;
using ServiceStack.ServiceHost; using ServiceStack.ServiceHost;
using System; using System;
@ -14,6 +15,8 @@ namespace MediaBrowser.Api.Images
/// </summary> /// </summary>
public class ImageWriter : IStreamWriter, IHasOptions public class ImageWriter : IStreamWriter, IHasOptions
{ {
public List<IImageEnhancer> Enhancers;
/// <summary> /// <summary>
/// Gets or sets the request. /// Gets or sets the request.
/// </summary> /// </summary>
@ -67,7 +70,7 @@ namespace MediaBrowser.Api.Images
{ {
return Kernel.Instance.ImageManager.ProcessImage(Item, Request.Type, Request.Index ?? 0, CropWhiteSpace, return Kernel.Instance.ImageManager.ProcessImage(Item, Request.Type, Request.Index ?? 0, CropWhiteSpace,
OriginalImageDateModified, responseStream, Request.Width, Request.Height, Request.MaxWidth, OriginalImageDateModified, responseStream, Request.Width, Request.Height, Request.MaxWidth,
Request.MaxHeight, Request.Quality); Request.MaxHeight, Request.Quality, Enhancers);
} }
} }
} }

View File

@ -340,6 +340,13 @@ namespace MediaBrowser.Api.Playback
try 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); var task = MediaEncoder.ExtractTextSubtitle(inputPath, type, subtitleStream.Index, offset, path, CancellationToken.None);
Task.WaitAll(task); Task.WaitAll(task);
@ -371,6 +378,13 @@ namespace MediaBrowser.Api.Playback
{ {
try try
{ {
var parentPath = Path.GetDirectoryName(path);
if (!Directory.Exists(parentPath))
{
Directory.CreateDirectory(parentPath);
}
var task = MediaEncoder.ConvertTextSubtitleToAss(subtitleStream.Path, path, offset, CancellationToken.None); var task = MediaEncoder.ConvertTextSubtitleToAss(subtitleStream.Path, path, offset, CancellationToken.None);
Task.WaitAll(task); Task.WaitAll(task);

View File

@ -1,6 +1,5 @@
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
@ -38,6 +37,29 @@ namespace MediaBrowser.Api
/// <value>The limit.</value> /// <value>The limit.</value>
[ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] [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; } 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> /// <summary>
@ -64,8 +86,7 @@ namespace MediaBrowser.Api
(request.UserId.HasValue ? user.RootFolder : (request.UserId.HasValue ? user.RootFolder :
(Folder)libraryManager.RootFolder) : DtoBuilder.GetItemByClientId(request.Id, userManager, libraryManager, request.UserId); (Folder)libraryManager.RootFolder) : DtoBuilder.GetItemByClientId(request.Id, userManager, libraryManager, request.UserId);
// Get everything var fields = request.GetItemFields().ToList();
var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
var dtoBuilder = new DtoBuilder(logger, libraryManager, userDataRepository); var dtoBuilder = new DtoBuilder(logger, libraryManager, userDataRepository);

View File

@ -123,9 +123,14 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
{ {
try 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 // File doesn't exist. No biggie
return null; return null;
@ -413,63 +418,46 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
} }
} }
/// <summary>
/// The _scheduled tasks configuration directory
/// </summary>
private string _scheduledTasksConfigurationDirectory;
/// <summary> /// <summary>
/// Gets the scheduled tasks configuration directory. /// Gets the scheduled tasks configuration directory.
/// </summary> /// </summary>
/// <value>The scheduled tasks configuration directory.</value> /// <param name="create">if set to <c>true</c> [create].</param>
private string ScheduledTasksConfigurationDirectory /// <returns>System.String.</returns>
private string GetScheduledTasksConfigurationDirectory(bool create)
{ {
get var path = Path.Combine(ApplicationPaths.ConfigurationDirectoryPath, "ScheduledTasks");
{
if (_scheduledTasksConfigurationDirectory == null)
{
_scheduledTasksConfigurationDirectory = Path.Combine(ApplicationPaths.ConfigurationDirectoryPath, "ScheduledTasks");
if (!Directory.Exists(_scheduledTasksConfigurationDirectory)) if (create && !Directory.Exists(path))
{ {
Directory.CreateDirectory(_scheduledTasksConfigurationDirectory); Directory.CreateDirectory(path);
}
}
return _scheduledTasksConfigurationDirectory;
} }
return path;
} }
/// <summary>
/// The _scheduled tasks data directory
/// </summary>
private string _scheduledTasksDataDirectory;
/// <summary> /// <summary>
/// Gets the scheduled tasks data directory. /// Gets the scheduled tasks data directory.
/// </summary> /// </summary>
/// <value>The scheduled tasks data directory.</value> /// <param name="create">if set to <c>true</c> [create].</param>
private string ScheduledTasksDataDirectory /// <returns>System.String.</returns>
private string GetScheduledTasksDataDirectory(bool create)
{ {
get var path = Path.Combine(ApplicationPaths.DataPath, "ScheduledTasks");
{
if (_scheduledTasksDataDirectory == null)
{
_scheduledTasksDataDirectory = Path.Combine(ApplicationPaths.DataPath, "ScheduledTasks");
if (!Directory.Exists(_scheduledTasksDataDirectory)) if (create && !Directory.Exists(path))
{ {
Directory.CreateDirectory(_scheduledTasksDataDirectory); Directory.CreateDirectory(path);
}
}
return _scheduledTasksDataDirectory;
} }
return path;
} }
/// <summary> /// <summary>
/// Gets the history file path. /// Gets the history file path.
/// </summary> /// </summary>
/// <value>The history file path.</value> /// <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> /// <summary>
@ -478,7 +466,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
/// <returns>System.String.</returns> /// <returns>System.String.</returns>
private string GetConfigurationFilePath() private string GetConfigurationFilePath()
{ {
return Path.Combine(ScheduledTasksConfigurationDirectory, Id + ".js"); return Path.Combine(GetScheduledTasksConfigurationDirectory(false), Id + ".js");
} }
/// <summary> /// <summary>
@ -493,7 +481,12 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
.Select(ScheduledTaskHelpers.GetTrigger) .Select(ScheduledTaskHelpers.GetTrigger)
.ToList(); .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. // File doesn't exist. No biggie. Return defaults.
return ScheduledTask.GetDefaultTriggers(); return ScheduledTask.GetDefaultTriggers();
@ -530,7 +523,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
Id = Id Id = Id
}; };
JsonSerializer.SerializeToFile(result, GetHistoryFilePath()); JsonSerializer.SerializeToFile(result, GetHistoryFilePath(true));
LastExecutionResult = result; LastExecutionResult = result;

View File

@ -1,6 +1,5 @@
using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Extensions;
using System; using System;
using System.Collections.Concurrent;
using System.IO; using System.IO;
namespace MediaBrowser.Common.IO namespace MediaBrowser.Common.IO
@ -11,12 +10,6 @@ namespace MediaBrowser.Common.IO
/// </summary> /// </summary>
public class FileSystemRepository 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> /// <summary>
/// Gets or sets the path. /// Gets or sets the path.
/// </summary> /// </summary>
@ -36,18 +29,6 @@ namespace MediaBrowser.Common.IO
} }
Path = path; Path = path;
Initialize();
}
/// <summary>
/// Initializes this instance.
/// </summary>
protected void Initialize()
{
if (!Directory.Exists(Path))
{
Directory.CreateDirectory(Path);
}
} }
/// <summary> /// <summary>
@ -56,17 +37,18 @@ namespace MediaBrowser.Common.IO
/// <param name="uniqueName">Name of the unique.</param> /// <param name="uniqueName">Name of the unique.</param>
/// <param name="fileExtension">The file extension.</param> /// <param name="fileExtension">The file extension.</param>
/// <returns>System.String.</returns> /// <returns>System.String.</returns>
/// <exception cref="System.ArgumentNullException"></exception> /// <exception cref="System.ArgumentNullException">
/// </exception>
public string GetResourcePath(string uniqueName, string fileExtension) public string GetResourcePath(string uniqueName, string fileExtension)
{ {
if (string.IsNullOrEmpty(uniqueName)) if (string.IsNullOrEmpty(uniqueName))
{ {
throw new ArgumentNullException(); throw new ArgumentNullException("uniqueName");
} }
if (string.IsNullOrEmpty(fileExtension)) if (string.IsNullOrEmpty(fileExtension))
{ {
throw new ArgumentNullException(); throw new ArgumentNullException("fileExtension");
} }
var filename = uniqueName.GetMD5() + fileExtension; var filename = uniqueName.GetMD5() + fileExtension;
@ -75,7 +57,7 @@ namespace MediaBrowser.Common.IO
} }
/// <summary> /// <summary>
/// Gets the full path of where a file should be stored within the repository /// Gets the resource path.
/// </summary> /// </summary>
/// <param name="filename">The filename.</param> /// <param name="filename">The filename.</param>
/// <returns>System.String.</returns> /// <returns>System.String.</returns>
@ -84,41 +66,14 @@ namespace MediaBrowser.Common.IO
{ {
if (string.IsNullOrEmpty(filename)) 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 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); var path = System.IO.Path.Combine(Path, prefix);
if (!Directory.Exists(path)) return System.IO.Path.Combine(path, filename);
{
Directory.CreateDirectory(path);
}
return path;
} }
/// <summary> /// <summary>
@ -144,8 +99,8 @@ namespace MediaBrowser.Common.IO
{ {
throw new ArgumentNullException(); throw new ArgumentNullException();
} }
return ContainsFilePath(GetInternalResourcePath(filename)); return ContainsFilePath(GetResourcePath(filename));
} }
/// <summary> /// <summary>

View File

@ -31,7 +31,7 @@ namespace MediaBrowser.Controller.Drawing
/// </summary> /// </summary>
/// <value>The image enhancers.</value> /// <value>The image enhancers.</value>
public IEnumerable<IImageEnhancer> ImageEnhancers { get; set; } public IEnumerable<IImageEnhancer> ImageEnhancers { get; set; }
/// <summary> /// <summary>
/// Gets the image size cache. /// Gets the image size cache.
/// </summary> /// </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="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="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="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> /// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">entity</exception> /// <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) if (entity == null)
{ {
@ -127,28 +128,13 @@ namespace MediaBrowser.Controller.Drawing
originalImagePath = await GetCroppedImage(originalImagePath, dateModified).ConfigureAwait(false); 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 // No enhancement - don't cache
if (supportedEnhancers.Count > 0) if (enhancers.Count > 0)
{ {
try try
{ {
// Enhance if we have enhancers // 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 the path changed update dateModified
if (!ehnancedImagePath.Equals(originalImagePath, StringComparison.OrdinalIgnoreCase)) if (!ehnancedImagePath.Equals(originalImagePath, StringComparison.OrdinalIgnoreCase))
@ -175,6 +161,19 @@ namespace MediaBrowser.Controller.Drawing
var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality.Value, dateModified); 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); var semaphore = GetLock(cacheFilePath);
await semaphore.WaitAsync().ConfigureAwait(false); await semaphore.WaitAsync().ConfigureAwait(false);
@ -262,6 +261,13 @@ namespace MediaBrowser.Controller.Drawing
/// <param name="bytes">The bytes.</param> /// <param name="bytes">The bytes.</param>
private async Task CacheResizedImage(string cacheFilePath, byte[] bytes) 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 // Save to the cache location
using (var cacheFileStream = new FileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous)) using (var cacheFileStream = new FileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
{ {
@ -323,7 +329,7 @@ namespace MediaBrowser.Controller.Drawing
} }
protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
/// <summary> /// <summary>
/// Gets the size of the image. /// Gets the size of the image.
/// </summary> /// </summary>
@ -335,25 +341,53 @@ namespace MediaBrowser.Controller.Drawing
// Now check the file system cache // Now check the file system cache
var fullCachePath = ImageSizeCache.GetResourcePath(keyName, ".txt"); 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); var semaphore = GetLock(fullCachePath);
await semaphore.WaitAsync().ConfigureAwait(false); await semaphore.WaitAsync().ConfigureAwait(false);
try 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] }; return new ImageSize { Width = result[0], Height = result[1] };
} }
catch (FileNotFoundException) catch (FileNotFoundException)
{ {
// Cache file doesn't exist no biggie // 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 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 // Update the file system cache
File.WriteAllText(fullCachePath, size.Width.ToString(UsCulture) + @"|" + size.Height.ToString(UsCulture)); File.WriteAllText(fullCachePath, size.Width.ToString(UsCulture) + @"|" + size.Height.ToString(UsCulture));
@ -490,12 +524,12 @@ namespace MediaBrowser.Controller.Drawing
await semaphore.WaitAsync().ConfigureAwait(false); await semaphore.WaitAsync().ConfigureAwait(false);
// Check again in case of contention // Check again in case of contention
if (CroppedImageCache.ContainsFilePath(croppedImagePath)) if (File.Exists(croppedImagePath))
{ {
semaphore.Release(); semaphore.Release();
return croppedImagePath; return croppedImagePath;
} }
try try
{ {
using (var fileStream = new FileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true)) using (var fileStream = new FileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true))
@ -511,6 +545,13 @@ namespace MediaBrowser.Controller.Drawing
using (var croppedImage = originalImage.CropWhitespace()) 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)) using (var outputStream = new FileStream(croppedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read))
{ {
croppedImage.Save(outputFormat, outputStream, 100); croppedImage.Save(outputFormat, outputStream, 100);
@ -568,7 +609,7 @@ namespace MediaBrowser.Controller.Drawing
await semaphore.WaitAsync().ConfigureAwait(false); await semaphore.WaitAsync().ConfigureAwait(false);
// Check again in case of contention // Check again in case of contention
if (EnhancedImageCache.ContainsFilePath(enhancedImagePath)) if (File.Exists(enhancedImagePath))
{ {
semaphore.Release(); semaphore.Release();
return enhancedImagePath; return enhancedImagePath;
@ -588,6 +629,13 @@ namespace MediaBrowser.Controller.Drawing
//Pass the image through registered enhancers //Pass the image through registered enhancers
using (var newImage = await ExecuteImageEnhancers(supportedEnhancers, originalImage, item, imageType, imageIndex).ConfigureAwait(false)) 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 //And then save it in the cache
using (var outputStream = new FileStream(enhancedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read)) using (var outputStream = new FileStream(enhancedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read))
{ {

View File

@ -304,7 +304,6 @@ namespace MediaBrowser.Controller.Entities
/// <summary> /// <summary>
/// We attach these to the item so that we only ever have to hit the file system once /// 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) /// (this includes the children of the containing folder)
/// Use ResolveArgs.FileSystemDictionary to check for the existence of files instead of File.Exists
/// </summary> /// </summary>
/// <value>The resolve args.</value> /// <value>The resolve args.</value>
[IgnoreDataMember] [IgnoreDataMember]

View File

@ -19,10 +19,6 @@ namespace MediaBrowser.Controller.Entities
public static IUserManager UserManager { get; set; } public static IUserManager UserManager { get; set; }
public static IXmlSerializer XmlSerializer { get; set; } public static IXmlSerializer XmlSerializer { get; set; }
/// <summary>
/// The _root folder path
/// </summary>
private string _rootFolderPath;
/// <summary> /// <summary>
/// Gets the root folder path. /// Gets the root folder path.
/// </summary> /// </summary>
@ -32,23 +28,19 @@ namespace MediaBrowser.Controller.Entities
{ {
get get
{ {
if (_rootFolderPath == null) if (Configuration.UseCustomLibrary)
{ {
if (Configuration.UseCustomLibrary) var rootFolderPath = GetRootFolderPath(Name);
{
_rootFolderPath = GetRootFolderPath(Name);
if (!Directory.Exists(_rootFolderPath)) if (!Directory.Exists(rootFolderPath))
{
Directory.CreateDirectory(_rootFolderPath);
}
}
else
{ {
_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 // Force these to be lazy loaded again
_configurationDirectoryPath = null; _configurationDirectoryPath = null;
_rootFolderPath = null;
RootFolder = null; RootFolder = null;
// Kick off a task to validate the media library // Kick off a task to validate the media library
@ -378,7 +369,6 @@ namespace MediaBrowser.Controller.Entities
// Force these to be lazy loaded again // Force these to be lazy loaded again
if (customLibraryChanged) if (customLibraryChanged)
{ {
_rootFolderPath = null;
RootFolder = null; RootFolder = null;
} }
} }

View File

@ -55,10 +55,6 @@ namespace MediaBrowser.Controller.MediaInfo
SubtitleCache = new FileSystemRepository(SubtitleCachePath); SubtitleCache = new FileSystemRepository(SubtitleCachePath);
} }
/// <summary>
/// The _video images data path
/// </summary>
private string _videoImagesDataPath;
/// <summary> /// <summary>
/// Gets the video images data path. /// Gets the video images data path.
/// </summary> /// </summary>
@ -67,24 +63,10 @@ namespace MediaBrowser.Controller.MediaInfo
{ {
get get
{ {
if (_videoImagesDataPath == null) return Path.Combine(_appPaths.DataPath, "extracted-video-images");
{
_videoImagesDataPath = Path.Combine(_appPaths.DataPath, "extracted-video-images");
if (!Directory.Exists(_videoImagesDataPath))
{
Directory.CreateDirectory(_videoImagesDataPath);
}
}
return _videoImagesDataPath;
} }
} }
/// <summary>
/// The _audio images data path
/// </summary>
private string _audioImagesDataPath;
/// <summary> /// <summary>
/// Gets the audio images data path. /// Gets the audio images data path.
/// </summary> /// </summary>
@ -93,24 +75,10 @@ namespace MediaBrowser.Controller.MediaInfo
{ {
get get
{ {
if (_audioImagesDataPath == null) return Path.Combine(_appPaths.DataPath, "extracted-audio-images");
{
_audioImagesDataPath = Path.Combine(_appPaths.DataPath, "extracted-audio-images");
if (!Directory.Exists(_audioImagesDataPath))
{
Directory.CreateDirectory(_audioImagesDataPath);
}
}
return _audioImagesDataPath;
} }
} }
/// <summary>
/// The _subtitle cache path
/// </summary>
private string _subtitleCachePath;
/// <summary> /// <summary>
/// Gets the subtitle cache path. /// Gets the subtitle cache path.
/// </summary> /// </summary>
@ -119,17 +87,7 @@ namespace MediaBrowser.Controller.MediaInfo
{ {
get get
{ {
if (_subtitleCachePath == null) return Path.Combine(_appPaths.CachePath, "subtitles");
{
_subtitleCachePath = Path.Combine(_appPaths.CachePath, "subtitles");
if (!Directory.Exists(_subtitleCachePath))
{
Directory.CreateDirectory(_subtitleCachePath);
}
}
return _subtitleCachePath;
} }
} }
@ -177,7 +135,7 @@ namespace MediaBrowser.Controller.MediaInfo
var path = VideoImageCache.GetResourcePath(filename, ".jpg"); var path = VideoImageCache.GetResourcePath(filename, ".jpg");
if (!VideoImageCache.ContainsFilePath(path)) if (!File.Exists(path))
{ {
if (extractImages) if (extractImages)
{ {
@ -204,6 +162,13 @@ namespace MediaBrowser.Controller.MediaInfo
try try
{ {
var parentPath = Path.GetDirectoryName(path);
if (!Directory.Exists(parentPath))
{
Directory.CreateDirectory(parentPath);
}
await _encoder.ExtractImage(inputPath, type, time, path, cancellationToken).ConfigureAwait(false); await _encoder.ExtractImage(inputPath, type, time, path, cancellationToken).ConfigureAwait(false);
chapter.ImagePath = path; chapter.ImagePath = path;
changesMade = true; changesMade = true;

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.IO; using System.IO;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.MediaInfo; using MediaBrowser.Common.MediaInfo;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
@ -156,7 +157,7 @@ namespace MediaBrowser.Controller.Providers.MediaInfo
var path = ImageCache.GetResourcePath(filename + "_primary", ".jpg"); var path = ImageCache.GetResourcePath(filename + "_primary", ".jpg");
if (!ImageCache.ContainsFilePath(path)) if (!File.Exists(path))
{ {
var semaphore = GetLock(path); var semaphore = GetLock(path);
@ -164,10 +165,17 @@ namespace MediaBrowser.Controller.Providers.MediaInfo
await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false); await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
// Check again // Check again
if (!ImageCache.ContainsFilePath(path)) if (!File.Exists(path))
{ {
try 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); await _mediaEncoder.ExtractImage(new[] { item.Path }, InputType.AudioFile, null, path, cancellationToken).ConfigureAwait(false);
} }
finally finally

View File

@ -244,6 +244,9 @@
<Compile Include="..\MediaBrowser.Model\Querying\PersonsQuery.cs"> <Compile Include="..\MediaBrowser.Model\Querying\PersonsQuery.cs">
<Link>Querying\PersonsQuery.cs</Link> <Link>Querying\PersonsQuery.cs</Link>
</Compile> </Compile>
<Compile Include="..\MediaBrowser.Model\Querying\SimilarItemsQuery.cs">
<Link>Querying\SimilarItemsQuery.cs</Link>
</Compile>
<Compile Include="..\MediaBrowser.Model\Querying\ThemeSongsResult.cs"> <Compile Include="..\MediaBrowser.Model\Querying\ThemeSongsResult.cs">
<Link>Querying\ThemeSongsResult.cs</Link> <Link>Querying\ThemeSongsResult.cs</Link>
</Compile> </Compile>

View File

@ -72,6 +72,34 @@ namespace MediaBrowser.Model.ApiClient
/// <exception cref="ArgumentNullException">query</exception> /// <exception cref="ArgumentNullException">query</exception>
Task<ItemsResult> GetItemsAsync(ItemQuery query); 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> /// <summary>
/// Gets the people async. /// Gets the people async.
/// </summary> /// </summary>

View File

@ -60,6 +60,7 @@
<Compile Include="Querying\ItemReviewsResult.cs" /> <Compile Include="Querying\ItemReviewsResult.cs" />
<Compile Include="Querying\ItemsByNameQuery.cs" /> <Compile Include="Querying\ItemsByNameQuery.cs" />
<Compile Include="Entities\BaseItemInfo.cs" /> <Compile Include="Entities\BaseItemInfo.cs" />
<Compile Include="Querying\SimilarItemsQuery.cs" />
<Compile Include="Session\BrowseRequest.cs" /> <Compile Include="Session\BrowseRequest.cs" />
<Compile Include="Session\PlayRequest.cs" /> <Compile Include="Session\PlayRequest.cs" />
<Compile Include="Session\PlaystateRequest.cs" /> <Compile Include="Session\PlaystateRequest.cs" />

View 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; }
}
}

View File

@ -94,29 +94,20 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
} }
/// <summary> /// <summary>
/// The _media tools path /// Gets the media tools path.
/// </summary> /// </summary>
private string _mediaToolsPath; /// <param name="create">if set to <c>true</c> [create].</param>
/// <summary> /// <returns>System.String.</returns>
/// Gets the folder path to tools private string GetMediaToolsPath(bool create)
/// </summary>
/// <value>The media tools path.</value>
private string MediaToolsPath
{ {
get var path = Path.Combine(_appPaths.ProgramDataPath, "ffmpeg");
if (create && !Directory.Exists(path))
{ {
if (_mediaToolsPath == null) Directory.CreateDirectory(path);
{
_mediaToolsPath = Path.Combine(_appPaths.ProgramDataPath, "ffmpeg");
if (!Directory.Exists(_mediaToolsPath))
{
Directory.CreateDirectory(_mediaToolsPath);
}
}
return _mediaToolsPath;
} }
return path;
} }
/// <summary> /// <summary>
@ -185,7 +176,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
var filename = resource.Substring(resource.IndexOf(prefix, StringComparison.OrdinalIgnoreCase) + prefix.Length); 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)) if (!Directory.Exists(versionedDirectoryPath))
{ {
@ -570,14 +561,14 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
} }
var offsetParam = offset.Ticks > 0 ? "-ss " + offset.TotalSeconds + " " : string.Empty; var offsetParam = offset.Ticks > 0 ? "-ss " + offset.TotalSeconds + " " : string.Empty;
var process = new Process var process = new Process
{ {
StartInfo = new ProcessStartInfo StartInfo = new ProcessStartInfo
{ {
RedirectStandardOutput = false, RedirectStandardOutput = false,
RedirectStandardError = true, RedirectStandardError = true,
CreateNoWindow = true, CreateNoWindow = true,
UseShellExecute = false, UseShellExecute = false,
FileName = FFMpegPath, FileName = FFMpegPath,
@ -744,7 +735,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
RedirectStandardOutput = false, RedirectStandardOutput = false,
RedirectStandardError = true, RedirectStandardError = true,
FileName = FFMpegPath, FileName = FFMpegPath,
Arguments = string.Format("{0}-i {1} -map 0:{2} -an -vn -c:s ass \"{3}\"", offsetParam, inputPath, subtitleStreamIndex, outputPath), Arguments = string.Format("{0}-i {1} -map 0:{2} -an -vn -c:s ass \"{3}\"", offsetParam, inputPath, subtitleStreamIndex, outputPath),
WindowStyle = ProcessWindowStyle.Hidden, WindowStyle = ProcessWindowStyle.Hidden,
@ -759,7 +750,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "ffmpeg-sub-extract-" + Guid.NewGuid() + ".txt"); var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "ffmpeg-sub-extract-" + Guid.NewGuid() + ".txt");
var logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous); var logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous);
try try
{ {
process.Start(); process.Start();

View File

@ -328,9 +328,7 @@ namespace MediaBrowser.Server.Implementations.Providers
public async Task<string> SaveImage(BaseItem item, Stream source, string targetName, bool saveLocally, CancellationToken cancellationToken) public async Task<string> SaveImage(BaseItem item, Stream source, string targetName, bool saveLocally, CancellationToken cancellationToken)
{ {
//download and save locally //download and save locally
var localPath = (saveLocally && item.MetaLocation != null) ? var localPath = GetSavePath(item, targetName, saveLocally);
Path.Combine(item.MetaLocation, targetName) :
_remoteImageCache.GetResourcePath(item.GetType().FullName + item.Path.ToLower(), targetName);
if (saveLocally) // queue to media directories if (saveLocally) // queue to media directories
{ {
@ -374,9 +372,18 @@ namespace MediaBrowser.Server.Implementations.Providers
/// <returns>System.String.</returns> /// <returns>System.String.</returns>
public string GetSavePath(BaseItem item, string targetFileName, bool saveLocally) 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) : Path.Combine(item.MetaLocation, targetFileName) :
_remoteImageCache.GetResourcePath(item.GetType().FullName + item.Id.ToString(), 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> /// <summary>

View File

@ -168,6 +168,14 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
if (!success) if (!success)
{ {
previouslyFailedImages.Add(key); previouslyFailedImages.Add(key);
var parentPath = Path.GetDirectoryName(failHistoryPath);
if (!Directory.Exists(parentPath))
{
Directory.CreateDirectory(parentPath);
}
_jsonSerializer.SerializeToFile(previouslyFailedImages, failHistoryPath); _jsonSerializer.SerializeToFile(previouslyFailedImages, failHistoryPath);
} }

View File

@ -165,7 +165,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
var specialFeattures = _itemRepo.GetItems(movie.SpecialFeatureIds).ToList(); var specialFeattures = _itemRepo.GetItems(movie.SpecialFeatureIds).ToList();
images = specialFeattures.Aggregate(images, (current, subItem) => current.Concat(GetPathsInUse(subItem))); images = specialFeattures.Aggregate(images, (current, subItem) => current.Concat(GetPathsInUse(subItem)));
} }
return images; return images;
} }
@ -176,13 +176,20 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
/// <returns>IEnumerable{System.String}.</returns> /// <returns>IEnumerable{System.String}.</returns>
private IEnumerable<string> GetFiles(string path) private IEnumerable<string> GetFiles(string path)
{ {
return Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories) try
.Where(i => {
{ return Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)
var ext = Path.GetExtension(i); .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> /// <summary>

View File

@ -8,14 +8,15 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers.MediaInfo; using MediaBrowser.Controller.Providers.MediaInfo;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MoreLinq;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Logging;
using MoreLinq;
namespace MediaBrowser.Server.Implementations.ScheduledTasks namespace MediaBrowser.Server.Implementations.ScheduledTasks
{ {
@ -263,7 +264,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
var path = ImageCache.GetResourcePath(filename, ".jpg"); var path = ImageCache.GetResourcePath(filename, ".jpg");
if (!ImageCache.ContainsFilePath(path)) if (!File.Exists(path))
{ {
var semaphore = GetLock(path); var semaphore = GetLock(path);
@ -271,10 +272,17 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false); await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
// Check again // Check again
if (!ImageCache.ContainsFilePath(path)) if (!File.Exists(path))
{ {
try try
{ {
var parentPath = Path.GetDirectoryName(path);
if (!Directory.Exists(parentPath))
{
Directory.CreateDirectory(parentPath);
}
await ExtractImageInternal(item, path, cancellationToken).ConfigureAwait(false); await ExtractImageInternal(item, path, cancellationToken).ConfigureAwait(false);
} }
finally finally

View File

@ -471,20 +471,18 @@ namespace MediaBrowser.Server.Implementations.Sqlite
/// <summary> /// <summary>
/// Gets the critic reviews path. /// Gets the critic reviews path.
/// </summary> /// </summary>
/// <value>The critic reviews path.</value> /// <param name="create">if set to <c>true</c> [create].</param>
private string CriticReviewsPath /// <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"); Directory.CreateDirectory(path);
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
return path;
} }
return path;
} }
/// <summary> /// <summary>
@ -499,10 +497,14 @@ namespace MediaBrowser.Server.Implementations.Sqlite
try try
{ {
var path = Path.Combine(CriticReviewsPath, itemId + ".json"); var path = Path.Combine(GetCriticReviewsPath(false), itemId + ".json");
return _jsonSerializer.DeserializeFromFile<List<ItemReview>>(path); return _jsonSerializer.DeserializeFromFile<List<ItemReview>>(path);
} }
catch (DirectoryNotFoundException)
{
return new List<ItemReview>();
}
catch (FileNotFoundException) catch (FileNotFoundException)
{ {
return new List<ItemReview>(); return new List<ItemReview>();
@ -521,7 +523,7 @@ namespace MediaBrowser.Server.Implementations.Sqlite
{ {
return Task.Run(() => return Task.Run(() =>
{ {
var path = Path.Combine(CriticReviewsPath, itemId + ".json"); var path = Path.Combine(GetCriticReviewsPath(true), itemId + ".json");
_jsonSerializer.SerializeToFile(criticReviews.ToList(), path); _jsonSerializer.SerializeToFile(criticReviews.ToList(), path);
}); });

View File

@ -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.112</version> <version>3.0.113</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.112" /> <dependency id="MediaBrowser.Common" version="3.0.113" />
<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.3" /> <dependency id="SimpleInjector" version="2.2.3" />

View File

@ -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.112</version> <version>3.0.113</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>

View File

@ -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.112</version> <version>3.0.113</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.112" /> <dependency id="MediaBrowser.Common" version="3.0.113" />
</dependencies> </dependencies>
</metadata> </metadata>
<files> <files>