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,
Request = request,
CropWhiteSpace = request.Type == ImageType.Logo || request.Type == ImageType.Art,
OriginalImageDateModified = originalFileImageDateModified
OriginalImageDateModified = originalFileImageDateModified,
Enhancers = supportedImageEnhancers
}, contentType);
}

View File

@ -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);
}
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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>
@ -144,8 +99,8 @@ namespace MediaBrowser.Common.IO
{
throw new ArgumentNullException();
}
return ContainsFilePath(GetInternalResourcePath(filename));
return ContainsFilePath(GetResourcePath(filename));
}
/// <summary>

View File

@ -31,7 +31,7 @@ namespace MediaBrowser.Controller.Drawing
/// </summary>
/// <value>The image enhancers.</value>
public IEnumerable<IImageEnhancer> ImageEnhancers { get; set; }
/// <summary>
/// Gets the image size cache.
/// </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))
{
@ -323,7 +329,7 @@ namespace MediaBrowser.Controller.Drawing
}
protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
/// <summary>
/// Gets the size of the image.
/// </summary>
@ -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,12 +524,12 @@ 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;
}
try
{
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())
{
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))
{

View File

@ -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]

View File

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

View File

@ -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;

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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" />

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>
/// 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))
{
@ -570,14 +561,14 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
}
var offsetParam = offset.Ticks > 0 ? "-ss " + offset.TotalSeconds + " " : string.Empty;
var process = new Process
{
StartInfo = new ProcessStartInfo
{
RedirectStandardOutput = false,
RedirectStandardError = true,
CreateNoWindow = true,
UseShellExecute = false,
FileName = FFMpegPath,
@ -744,7 +735,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
RedirectStandardOutput = false,
RedirectStandardError = true,
FileName = FFMpegPath,
Arguments = string.Format("{0}-i {1} -map 0:{2} -an -vn -c:s ass \"{3}\"", offsetParam, inputPath, subtitleStreamIndex, outputPath),
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 logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous);
try
{
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)
{
//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>

View File

@ -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);
}

View File

@ -165,7 +165,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
var specialFeattures = _itemRepo.GetItems(movie.SpecialFeatureIds).ToList();
images = specialFeattures.Aggregate(images, (current, subItem) => current.Concat(GetPathsInUse(subItem)));
}
return images;
}
@ -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>

View File

@ -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

View File

@ -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);
});

View File

@ -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" />

View File

@ -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>

View File

@ -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>