This commit is contained in:
Sven Van den brande 2013-10-31 21:46:03 +01:00
commit e8f8d6651c
117 changed files with 1879 additions and 816 deletions

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
using System;
@ -12,20 +13,27 @@ namespace MediaBrowser.Api.Library
/// </summary>
public static class LibraryHelpers
{
/// <summary>
/// The shortcut file extension
/// </summary>
private const string ShortcutFileExtension = ".mblink";
/// <summary>
/// The shortcut file search
/// </summary>
private const string ShortcutFileSearch = "*" + ShortcutFileExtension;
/// <summary>
/// Adds the virtual folder.
/// </summary>
/// <param name="fileSystem">The file system.</param>
/// <param name="name">The name.</param>
/// <param name="collectionType">Type of the collection.</param>
/// <param name="user">The user.</param>
/// <param name="appPaths">The app paths.</param>
/// <exception cref="System.ArgumentException">There is already a media collection with the name + name + .</exception>
public static void AddVirtualFolder(string name, string collectionType, User user, IServerApplicationPaths appPaths)
public static void AddVirtualFolder(IFileSystem fileSystem, string name, string collectionType, User user, IServerApplicationPaths appPaths)
{
name = FileSystem.GetValidFilename(name);
name = fileSystem.GetValidFilename(name);
var rootFolderPath = user != null ? user.RootFolderPath : appPaths.DefaultUserViewsPath;
var virtualFolderPath = Path.Combine(rootFolderPath, name);
@ -106,12 +114,13 @@ namespace MediaBrowser.Api.Library
/// <summary>
/// Deletes a shortcut from within a virtual folder, within either the default view or a user view
/// </summary>
/// <param name="fileSystem">The file system.</param>
/// <param name="virtualFolderName">Name of the virtual folder.</param>
/// <param name="mediaPath">The media path.</param>
/// <param name="user">The user.</param>
/// <param name="appPaths">The app paths.</param>
/// <exception cref="System.IO.DirectoryNotFoundException">The media folder does not exist</exception>
public static void RemoveMediaPath(string virtualFolderName, string mediaPath, User user, IServerApplicationPaths appPaths)
public static void RemoveMediaPath(IFileSystem fileSystem, string virtualFolderName, string mediaPath, User user, IServerApplicationPaths appPaths)
{
var rootFolderPath = user != null ? user.RootFolderPath : appPaths.DefaultUserViewsPath;
var path = Path.Combine(rootFolderPath, virtualFolderName);
@ -121,7 +130,7 @@ namespace MediaBrowser.Api.Library
throw new DirectoryNotFoundException(string.Format("The media collection {0} does not exist", virtualFolderName));
}
var shortcut = Directory.EnumerateFiles(path, ShortcutFileSearch, SearchOption.AllDirectories).FirstOrDefault(f => FileSystem.ResolveShortcut(f).Equals(mediaPath, StringComparison.OrdinalIgnoreCase));
var shortcut = Directory.EnumerateFiles(path, ShortcutFileSearch, SearchOption.AllDirectories).FirstOrDefault(f => fileSystem.ResolveShortcut(f).Equals(mediaPath, StringComparison.OrdinalIgnoreCase));
if (!string.IsNullOrEmpty(shortcut))
{
@ -132,13 +141,14 @@ namespace MediaBrowser.Api.Library
/// <summary>
/// Adds an additional mediaPath to an existing virtual folder, within either the default view or a user view
/// </summary>
/// <param name="fileSystem">The file system.</param>
/// <param name="virtualFolderName">Name of the virtual folder.</param>
/// <param name="path">The path.</param>
/// <param name="user">The user.</param>
/// <param name="appPaths">The app paths.</param>
/// <exception cref="System.ArgumentException">The path is not valid.</exception>
/// <exception cref="System.IO.DirectoryNotFoundException">The path does not exist.</exception>
public static void AddMediaPath(string virtualFolderName, string path, User user, IServerApplicationPaths appPaths)
public static void AddMediaPath(IFileSystem fileSystem, string virtualFolderName, string path, User user, IServerApplicationPaths appPaths)
{
if (!Path.IsPathRooted(path))
{
@ -160,7 +170,7 @@ namespace MediaBrowser.Api.Library
var rootFolderPath = user != null ? user.RootFolderPath : appPaths.DefaultUserViewsPath;
var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
ValidateNewMediaPath(rootFolderPath, path, appPaths);
ValidateNewMediaPath(fileSystem, rootFolderPath, path, appPaths);
var shortcutFilename = Path.GetFileNameWithoutExtension(path);
@ -172,20 +182,22 @@ namespace MediaBrowser.Api.Library
lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension);
}
FileSystem.CreateShortcut(lnk, path);
fileSystem.CreateShortcut(lnk, path);
}
/// <summary>
/// Validates that a new media path can be added
/// </summary>
/// <param name="fileSystem">The file system.</param>
/// <param name="currentViewRootFolderPath">The current view root folder path.</param>
/// <param name="mediaPath">The media path.</param>
/// <param name="appPaths">The app paths.</param>
/// <exception cref="System.ArgumentException"></exception>
private static void ValidateNewMediaPath(string currentViewRootFolderPath, string mediaPath, IServerApplicationPaths appPaths)
/// <exception cref="System.ArgumentException">
/// </exception>
private static void ValidateNewMediaPath(IFileSystem fileSystem, string currentViewRootFolderPath, string mediaPath, IServerApplicationPaths appPaths)
{
var duplicate = Directory.EnumerateFiles(appPaths.RootFolderPath, ShortcutFileSearch, SearchOption.AllDirectories)
.Select(FileSystem.ResolveShortcut)
.Select(fileSystem.ResolveShortcut)
.FirstOrDefault(p => !IsNewPathValid(mediaPath, p, false));
if (!string.IsNullOrEmpty(duplicate))
@ -196,7 +208,7 @@ namespace MediaBrowser.Api.Library
// Don't allow duplicate sub-paths within the same user library, or it will result in duplicate items
// See comments in IsNewPathValid
duplicate = Directory.EnumerateFiles(currentViewRootFolderPath, ShortcutFileSearch, SearchOption.AllDirectories)
.Select(FileSystem.ResolveShortcut)
.Select(fileSystem.ResolveShortcut)
.FirstOrDefault(p => !IsNewPathValid(mediaPath, p, true));
if (!string.IsNullOrEmpty(duplicate))
@ -206,7 +218,7 @@ namespace MediaBrowser.Api.Library
// Make sure the current root folder doesn't already have a shortcut to the same path
duplicate = Directory.EnumerateFiles(currentViewRootFolderPath, ShortcutFileSearch, SearchOption.AllDirectories)
.Select(FileSystem.ResolveShortcut)
.Select(fileSystem.ResolveShortcut)
.FirstOrDefault(p => mediaPath.Equals(p, StringComparison.OrdinalIgnoreCase));
if (!string.IsNullOrEmpty(duplicate))

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities;
@ -186,6 +187,8 @@ namespace MediaBrowser.Api.Library
private readonly IDirectoryWatchers _directoryWatchers;
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="LibraryStructureService"/> class.
/// </summary>
@ -193,7 +196,7 @@ namespace MediaBrowser.Api.Library
/// <param name="userManager">The user manager.</param>
/// <param name="libraryManager">The library manager.</param>
/// <exception cref="System.ArgumentNullException">appPaths</exception>
public LibraryStructureService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IDirectoryWatchers directoryWatchers)
public LibraryStructureService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IDirectoryWatchers directoryWatchers, IFileSystem fileSystem)
{
if (appPaths == null)
{
@ -204,6 +207,7 @@ namespace MediaBrowser.Api.Library
_appPaths = appPaths;
_libraryManager = libraryManager;
_directoryWatchers = directoryWatchers;
_fileSystem = fileSystem;
}
/// <summary>
@ -241,13 +245,13 @@ namespace MediaBrowser.Api.Library
{
if (string.IsNullOrEmpty(request.UserId))
{
LibraryHelpers.AddVirtualFolder(request.Name, request.CollectionType, null, _appPaths);
LibraryHelpers.AddVirtualFolder(_fileSystem, request.Name, request.CollectionType, null, _appPaths);
}
else
{
var user = _userManager.GetUserById(new Guid(request.UserId));
LibraryHelpers.AddVirtualFolder(request.Name, request.CollectionType, user, _appPaths);
LibraryHelpers.AddVirtualFolder(_fileSystem, request.Name, request.CollectionType, user, _appPaths);
}
// Need to add a delay here or directory watchers may still pick up the changes
@ -352,13 +356,13 @@ namespace MediaBrowser.Api.Library
{
if (string.IsNullOrEmpty(request.UserId))
{
LibraryHelpers.AddMediaPath(request.Name, request.Path, null, _appPaths);
LibraryHelpers.AddMediaPath(_fileSystem, request.Name, request.Path, null, _appPaths);
}
else
{
var user = _userManager.GetUserById(new Guid(request.UserId));
LibraryHelpers.AddMediaPath(request.Name, request.Path, user, _appPaths);
LibraryHelpers.AddMediaPath(_fileSystem, request.Name, request.Path, user, _appPaths);
}
// Need to add a delay here or directory watchers may still pick up the changes
@ -389,13 +393,13 @@ namespace MediaBrowser.Api.Library
{
if (string.IsNullOrEmpty(request.UserId))
{
LibraryHelpers.RemoveMediaPath(request.Name, request.Path, null, _appPaths);
LibraryHelpers.RemoveMediaPath(_fileSystem, request.Name, request.Path, null, _appPaths);
}
else
{
var user = _userManager.GetUserById(new Guid(request.UserId));
LibraryHelpers.RemoveMediaPath(request.Name, request.Path, user, _appPaths);
LibraryHelpers.RemoveMediaPath(_fileSystem, request.Name, request.Path, user, _appPaths);
}
// Need to add a delay here or directory watchers may still pick up the changes

View File

@ -5,8 +5,10 @@ using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Querying;
using ServiceStack.ServiceHost;
using System;
@ -32,6 +34,21 @@ namespace MediaBrowser.Api
public string Id { get; set; }
}
[Route("/Items/{Id}/RemoteImages/{Type}", "GET")]
[Api(Description = "Gets available remote images for an item")]
public class GetRemoteImages : IReturn<List<RemoteImageInfo>>
{
/// <summary>
/// Gets or sets the id.
/// </summary>
/// <value>The id.</value>
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Id { get; set; }
[ApiMember(Name = "Type", Description = "The image type", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public ImageType Type { get; set; }
}
/// <summary>
/// Class GetCriticReviews
/// </summary>
@ -208,6 +225,7 @@ namespace MediaBrowser.Api
private readonly ILibraryManager _libraryManager;
private readonly IUserManager _userManager;
private readonly IUserDataManager _userDataManager;
private readonly IProviderManager _providerManager;
private readonly IDtoService _dtoService;
@ -215,13 +233,14 @@ namespace MediaBrowser.Api
/// Initializes a new instance of the <see cref="LibraryService" /> class.
/// </summary>
public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager,
IDtoService dtoService, IUserDataManager userDataManager)
IDtoService dtoService, IUserDataManager userDataManager, IProviderManager providerManager)
{
_itemRepo = itemRepo;
_libraryManager = libraryManager;
_userManager = userManager;
_dtoService = dtoService;
_userDataManager = userDataManager;
_providerManager = providerManager;
}
public object Get(GetFile request)
@ -240,6 +259,15 @@ namespace MediaBrowser.Api
return ToStaticFileResult(item.Path);
}
public object Get(GetRemoteImages request)
{
var item = _dtoService.GetItemByDtoId(request.Id);
var result = _providerManager.GetAvailableRemoteImages(item, request.Type, CancellationToken.None).Result;
return ToOptimizedResult(result);
}
/// <summary>
/// Gets the specified request.
/// </summary>
@ -335,7 +363,9 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns>
public object Get(GetItemCounts request)
{
var items = GetAllLibraryItems(request.UserId, _userManager, _libraryManager).ToList();
var items = GetAllLibraryItems(request.UserId, _userManager, _libraryManager)
.Where(i => i.LocationType != LocationType.Virtual)
.ToList();
var filteredItems = request.UserId.HasValue ? FilterItems(items, request, request.UserId.Value).ToList() : items;

View File

@ -59,6 +59,8 @@ namespace MediaBrowser.Api.Playback
protected IMediaEncoder MediaEncoder { get; private set; }
protected IDtoService DtoService { get; private set; }
protected IFileSystem FileSystem { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
/// </summary>
@ -67,8 +69,9 @@ namespace MediaBrowser.Api.Playback
/// <param name="libraryManager">The library manager.</param>
/// <param name="isoManager">The iso manager.</param>
/// <param name="mediaEncoder">The media encoder.</param>
protected BaseStreamingService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService)
protected BaseStreamingService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem)
{
FileSystem = fileSystem;
DtoService = dtoService;
ApplicationPaths = appPaths;
UserManager = userManager;
@ -269,7 +272,7 @@ namespace MediaBrowser.Api.Playback
// If fixed dimensions were supplied
if (request.Width.HasValue && request.Height.HasValue)
{
return string.Format(" -vf \"scale={0}:{1}{2}\"", request.Width.Value, request.Height.Value, assSubtitleParam);
return string.Format(" -vf \"scale=trunc({0}/2)*2:trunc({1}/2)*2{2}\"", request.Width.Value, request.Height.Value, assSubtitleParam);
}
var isH264Output = outputVideoCodec.Equals("libx264", StringComparison.OrdinalIgnoreCase);
@ -653,7 +656,7 @@ namespace MediaBrowser.Api.Playback
var logFilePath = Path.Combine(ApplicationPaths.LogDirectoryPath, "ffmpeg-" + Guid.NewGuid() + ".txt");
// FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory.
state.LogFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous);
state.LogFileStream = FileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true);
process.Exited += (sender, args) => OnFfMpegProcessExited(process, state);

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.MediaInfo;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.MediaInfo;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library;
@ -32,8 +33,8 @@ namespace MediaBrowser.Api.Playback.Hls
/// <param name="libraryManager">The library manager.</param>
/// <param name="isoManager">The iso manager.</param>
/// <param name="mediaEncoder">The media encoder.</param>
public AudioHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService)
: base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService)
public AudioHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem)
: base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem)
{
}

View File

@ -38,8 +38,8 @@ namespace MediaBrowser.Api.Playback.Hls
/// <param name="libraryManager">The library manager.</param>
/// <param name="isoManager">The iso manager.</param>
/// <param name="mediaEncoder">The media encoder.</param>
protected BaseHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService)
: base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService)
protected BaseHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem)
: base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem)
{
}
@ -209,7 +209,7 @@ namespace MediaBrowser.Api.Playback.Hls
string fileText;
// Need to use FileShare.ReadWrite because we're reading the file at the same time it's being written
using (var fileStream = new FileStream(playlist, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
using (var fileStream = FileSystem.GetFileStream(playlist, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
{
using (var reader = new StreamReader(fileStream))
{

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.MediaInfo;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.MediaInfo;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library;
@ -39,8 +40,8 @@ namespace MediaBrowser.Api.Playback.Hls
/// <param name="isoManager">The iso manager.</param>
/// <param name="mediaEncoder">The media encoder.</param>
/// <param name="dtoService">The dto service.</param>
public VideoHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService)
: base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService)
public VideoHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem)
: base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem)
{
}

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.MediaInfo;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.MediaInfo;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
@ -40,8 +41,8 @@ namespace MediaBrowser.Api.Playback.Progressive
/// </summary>
public class AudioService : BaseProgressiveStreamingService
{
public AudioService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IDtoService dtoService, IImageProcessor imageProcessor)
: base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, itemRepo, dtoService, imageProcessor)
public AudioService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IDtoService dtoService, IImageProcessor imageProcessor, IFileSystem fileSystem)
: base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, itemRepo, dtoService, imageProcessor, fileSystem)
{
}

View File

@ -1,4 +1,5 @@
using MediaBrowser.Api.Images;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.MediaInfo;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
@ -27,8 +28,8 @@ namespace MediaBrowser.Api.Playback.Progressive
protected readonly IItemRepository ItemRepository;
protected readonly IImageProcessor ImageProcessor;
protected BaseProgressiveStreamingService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepository, IDtoService dtoService, IImageProcessor imageProcessor) :
base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService)
protected BaseProgressiveStreamingService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepository, IDtoService dtoService, IImageProcessor imageProcessor, IFileSystem fileSystem) :
base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem)
{
ItemRepository = itemRepository;
ImageProcessor = imageProcessor;
@ -346,7 +347,7 @@ namespace MediaBrowser.Api.Playback.Progressive
ApiEntryPoint.Instance.OnTranscodeBeginRequest(outputPath, TranscodingJobType.Progressive);
}
var result = new ProgressiveStreamWriter(outputPath, Logger);
var result = new ProgressiveStreamWriter(outputPath, Logger, FileSystem);
result.Options["Accept-Ranges"] = "none";
result.Options["Content-Type"] = contentType;

View File

@ -13,6 +13,7 @@ namespace MediaBrowser.Api.Playback.Progressive
{
private string Path { get; set; }
private ILogger Logger { get; set; }
private readonly IFileSystem _fileSystem;
/// <summary>
/// The _options
@ -32,10 +33,11 @@ namespace MediaBrowser.Api.Playback.Progressive
/// </summary>
/// <param name="path">The path.</param>
/// <param name="logger">The logger.</param>
public ProgressiveStreamWriter(string path, ILogger logger)
public ProgressiveStreamWriter(string path, ILogger logger, IFileSystem fileSystem)
{
Path = path;
Logger = logger;
_fileSystem = fileSystem;
}
/// <summary>
@ -83,7 +85,7 @@ namespace MediaBrowser.Api.Playback.Progressive
var eofCount = 0;
long position = 0;
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
{
while (eofCount < 15)
{

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.MediaInfo;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.MediaInfo;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
@ -54,8 +55,8 @@ namespace MediaBrowser.Api.Playback.Progressive
/// </summary>
public class VideoService : BaseProgressiveStreamingService
{
public VideoService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IDtoService dtoService, IImageProcessor imageProcessor)
: base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, itemRepo, dtoService, imageProcessor)
public VideoService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IDtoService dtoService, IImageProcessor imageProcessor, IFileSystem fileSystem)
: base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, itemRepo, dtoService, imageProcessor, fileSystem)
{
}

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Session;
using ServiceStack.ServiceHost;
@ -182,16 +183,18 @@ namespace MediaBrowser.Api
private readonly ISessionManager _sessionManager;
private readonly IDtoService _dtoService;
private readonly IUserManager _userManager;
/// <summary>
/// Initializes a new instance of the <see cref="SessionsService" /> class.
/// </summary>
/// <param name="sessionManager">The session manager.</param>
/// <param name="dtoService">The dto service.</param>
public SessionsService(ISessionManager sessionManager, IDtoService dtoService)
public SessionsService(ISessionManager sessionManager, IDtoService dtoService, IUserManager userManager)
{
_sessionManager = sessionManager;
_dtoService = dtoService;
_userManager = userManager;
}
/// <summary>
@ -208,6 +211,16 @@ namespace MediaBrowser.Api
result = result.Where(i => i.SupportsRemoteControl == request.SupportsRemoteControl.Value);
}
if (request.ControllableByUserId.HasValue)
{
var user = _userManager.GetUserById(request.ControllableByUserId.Value);
if (!user.Configuration.EnableRemoteControlOfOtherUsers)
{
result = result.Where(i => i.User == null || i.User.Id == request.ControllableByUserId.Value);
}
}
return ToOptimizedResult(result.Select(_dtoService.GetSessionInfoDto).ToList());
}

View File

@ -1,6 +1,8 @@
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.System;
@ -75,6 +77,9 @@ namespace MediaBrowser.Api
/// </summary>
private readonly IServerConfigurationManager _configurationManager;
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="SystemService" /> class.
/// </summary>
@ -82,7 +87,7 @@ namespace MediaBrowser.Api
/// <param name="appHost">The app host.</param>
/// <param name="configurationManager">The configuration manager.</param>
/// <exception cref="System.ArgumentNullException">jsonSerializer</exception>
public SystemService(IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IServerConfigurationManager configurationManager)
public SystemService(IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
: base()
{
if (jsonSerializer == null)
@ -96,6 +101,7 @@ namespace MediaBrowser.Api
_appHost = appHost;
_configurationManager = configurationManager;
_fileSystem = fileSystem;
_jsonSerializer = jsonSerializer;
}
@ -118,7 +124,7 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns>
public object Get(GetConfiguration request)
{
var dateModified = File.GetLastWriteTimeUtc(_configurationManager.ApplicationPaths.SystemConfigurationFilePath);
var dateModified = _fileSystem.GetLastWriteTimeUtc(_configurationManager.ApplicationPaths.SystemConfigurationFilePath);
var cacheKey = (_configurationManager.ApplicationPaths.SystemConfigurationFilePath + dateModified.Ticks).GetMD5();

View File

@ -1,10 +1,9 @@
using System.Collections;
using System.Globalization;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
using ServiceStack.ServiceHost;
using System;
@ -48,18 +47,9 @@ namespace MediaBrowser.Api
[ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, OverviewHtml, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
public string Fields { get; set; }
[ApiMember(Name = "ExcludeLocationTypes", Description = "Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
public string ExcludeLocationTypes { get; set; }
[ApiMember(Name = "SeriesId", Description = "Optional. Filter by series id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string SeriesId { get; set; }
[ApiMember(Name = "MinPremiereDate", Description = "Optional. The minimum premiere date. Format = yyyyMMddHHmmss", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
public string MinPremiereDate { get; set; }
[ApiMember(Name = "MaxPremiereDate", Description = "Optional. The maximum premiere date. Format = yyyyMMddHHmmss", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
public string MaxPremiereDate { get; set; }
[ApiMember(Name = "HasPremiereDate", Description = "Optional filter by items with premiere dates.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public bool? HasPremiereDate { get; set; }
/// <summary>
/// Gets the item fields.
/// </summary>
@ -170,10 +160,15 @@ namespace MediaBrowser.Api
{
var user = _userManager.GetUserById(request.UserId);
var itemsList = user.RootFolder
.GetRecursiveChildren(user, i => i is Series)
var items = user.RootFolder
.GetRecursiveChildren(user)
.OfType<Series>();
items = FilterSeries(request, items);
var itemsList = items
.AsParallel()
.Select(i => GetNextUp((Series)i, user, request))
.Select(i => GetNextUp(i, user, request))
.ToList();
itemsList = itemsList
@ -264,35 +259,19 @@ namespace MediaBrowser.Api
private IEnumerable<Episode> FilterItems(GetNextUpEpisodes request, IEnumerable<Episode> items)
{
// ExcludeLocationTypes
if (!string.IsNullOrEmpty(request.ExcludeLocationTypes))
// Make this configurable when needed
items = items.Where(i => i.LocationType != LocationType.Virtual);
return items;
}
private IEnumerable<Series> FilterSeries(GetNextUpEpisodes request, IEnumerable<Series> items)
{
if (!string.IsNullOrWhiteSpace(request.SeriesId))
{
var vals = request.ExcludeLocationTypes.Split(',');
var id = new Guid(request.SeriesId);
items = items
.Where(f => !vals.Contains(f.LocationType.ToString(), StringComparer.OrdinalIgnoreCase))
.ToList();
}
if (!string.IsNullOrEmpty(request.MinPremiereDate))
{
var date = DateTime.ParseExact(request.MinPremiereDate, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
items = items.Where(i => !i.PremiereDate.HasValue || i.PremiereDate.Value >= date);
}
if (!string.IsNullOrEmpty(request.MaxPremiereDate))
{
var date = DateTime.ParseExact(request.MaxPremiereDate, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
items = items.Where(i => !i.PremiereDate.HasValue || i.PremiereDate.Value <= date);
}
if (request.HasPremiereDate.HasValue)
{
var val = request.HasPremiereDate.Value;
items = items.Where(i => i.PremiereDate.HasValue == val);
items = items.Where(i => i.Id == id);
}
return items;

View File

@ -1,5 +1,4 @@
using System.Globalization;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies;
@ -181,22 +180,22 @@ namespace MediaBrowser.Api.UserLibrary
[ApiMember(Name = "IsHD", Description = "Optional filter by items that are HD or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool? IsHD { get; set; }
[ApiMember(Name = "ExcludeLocationTypes", Description = "Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
public string ExcludeLocationTypes { get; set; }
[ApiMember(Name = "LocationTypes", Description = "Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
public string LocationTypes { get; set; }
[ApiMember(Name = "MinPremiereDate", Description = "Optional. The minimum premiere date. Format = yyyyMMddHHmmss", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
public string MinPremiereDate { get; set; }
[ApiMember(Name = "MaxPremiereDate", Description = "Optional. The maximum premiere date. Format = yyyyMMddHHmmss", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
public string MaxPremiereDate { get; set; }
[ApiMember(Name = "HasPremiereDate", Description = "Optional filter by items with premiere dates.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public bool? HasPremiereDate { get; set; }
[ApiMember(Name = "ExcludeLocationTypes", Description = "Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
public string ExcludeLocationTypes { get; set; }
public bool IncludeIndexContainers { get; set; }
[ApiMember(Name = "IsMissing", Description = "Optional filter by items that are missing episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool? IsMissing { get; set; }
[ApiMember(Name = "IsUnaired", Description = "Optional filter by items that are unaired episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool? IsUnaired { get; set; }
[ApiMember(Name = "IsVirtualUnaired", Description = "Optional filter by items that are virtual unaired episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool? IsVirtualUnaired { get; set; }
}
/// <summary>
@ -270,6 +269,8 @@ namespace MediaBrowser.Api.UserLibrary
items = ApplyFilter(items, filter, user, _userDataRepository);
}
items = FilterVirtualEpisodes(request, items, user);
items = items.AsEnumerable();
items = ApplySearchTerm(request, items);
@ -440,6 +441,121 @@ namespace MediaBrowser.Api.UserLibrary
return items;
}
private IEnumerable<BaseItem> FilterVirtualEpisodes(GetItems request, IEnumerable<BaseItem> items, User user)
{
items = FilterVirtualSeasons(request, items, user);
if (request.IsMissing.HasValue)
{
var val = request.IsMissing.Value;
items = items.Where(i =>
{
var e = i as Episode;
if (e != null)
{
return e.IsMissingEpisode == val;
}
return true;
});
}
if (request.IsUnaired.HasValue)
{
var val = request.IsUnaired.Value;
items = items.Where(i =>
{
var e = i as Episode;
if (e != null)
{
return e.IsUnaired == val;
}
return true;
});
}
if (request.IsVirtualUnaired.HasValue)
{
var val = request.IsVirtualUnaired.Value;
items = items.Where(i =>
{
var e = i as Episode;
if (e != null)
{
return e.IsVirtualUnaired == val;
}
return true;
});
}
return items;
}
private IEnumerable<BaseItem> FilterVirtualSeasons(GetItems request, IEnumerable<BaseItem> items, User user)
{
if (request.IsMissing.HasValue && request.IsUnaired.HasValue)
{
var isMissing = request.IsMissing.Value;
var isUnaired = request.IsUnaired.Value;
if (!isMissing && !isUnaired)
{
return items.Where(i =>
{
var e = i as Season;
if (e != null)
{
return !e.IsMissingOrVirtualUnaired;
}
return true;
});
}
}
if (request.IsMissing.HasValue)
{
var val = request.IsMissing.Value;
items = items.Where(i =>
{
var e = i as Season;
if (e != null)
{
return e.IsMissingSeason == val;
}
return true;
});
}
if (request.IsUnaired.HasValue)
{
var val = request.IsUnaired.Value;
items = items.Where(i =>
{
var e = i as Season;
if (e != null)
{
return e.IsUnaired == val;
}
return true;
});
}
if (request.IsVirtualUnaired.HasValue)
{
var val = request.IsVirtualUnaired.Value;
items = items.Where(i =>
{
var e = i as Season;
if (e != null)
{
return e.IsVirtualUnaired == val;
}
return true;
});
}
return items;
}
/// <summary>
/// Applies the additional filters.
/// </summary>
@ -593,13 +709,6 @@ namespace MediaBrowser.Api.UserLibrary
items = items.Where(f => vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase));
}
// ExcludeLocationTypes
if (!string.IsNullOrEmpty(request.ExcludeLocationTypes))
{
var vals = request.ExcludeLocationTypes.Split(',');
items = items.Where(f => !vals.Contains(f.LocationType.ToString(), StringComparer.OrdinalIgnoreCase));
}
// LocationTypes
if (!string.IsNullOrEmpty(request.LocationTypes))
{
@ -607,6 +716,13 @@ namespace MediaBrowser.Api.UserLibrary
items = items.Where(f => vals.Contains(f.LocationType.ToString(), StringComparer.OrdinalIgnoreCase));
}
// ExcludeLocationTypes
if (!string.IsNullOrEmpty(request.ExcludeLocationTypes))
{
var vals = request.ExcludeLocationTypes.Split(',');
items = items.Where(f => !vals.Contains(f.LocationType.ToString(), StringComparer.OrdinalIgnoreCase));
}
if (!string.IsNullOrEmpty(request.NameStartsWithOrGreater))
{
items = items.Where(i => string.Compare(request.NameStartsWithOrGreater, i.SortName, StringComparison.CurrentCultureIgnoreCase) < 1);
@ -826,7 +942,8 @@ namespace MediaBrowser.Api.UserLibrary
if (request.IsHD.HasValue)
{
items = items.OfType<Video>().Where(i => i.IsHD == request.IsHD.Value);
var val = request.IsHD.Value;
items = items.OfType<Video>().Where(i => i.IsHD == val);
}
if (request.ParentIndexNumber.HasValue)
@ -853,27 +970,6 @@ namespace MediaBrowser.Api.UserLibrary
});
}
if (!string.IsNullOrEmpty(request.MinPremiereDate))
{
var date = DateTime.ParseExact(request.MinPremiereDate, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
items = items.Where(i => !i.PremiereDate.HasValue || i.PremiereDate.Value >= date);
}
if (!string.IsNullOrEmpty(request.MaxPremiereDate))
{
var date = DateTime.ParseExact(request.MaxPremiereDate, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
items = items.Where(i => !i.PremiereDate.HasValue || i.PremiereDate.Value <= date);
}
if (request.HasPremiereDate.HasValue)
{
var val = request.HasPremiereDate.Value;
items = items.Where(i => i.PremiereDate.HasValue == val);
}
return items;
}

View File

@ -1,5 +1,6 @@
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
@ -27,16 +28,18 @@ namespace MediaBrowser.Api.WebSocket
/// The _kernel
/// </summary>
private readonly ILogManager _logManager;
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="LogFileWebSocketListener" /> class.
/// </summary>
/// <param name="logger">The logger.</param>
/// <param name="logManager">The log manager.</param>
public LogFileWebSocketListener(ILogger logger, ILogManager logManager)
public LogFileWebSocketListener(ILogger logger, ILogManager logManager, IFileSystem fileSystem)
: base(logger)
{
_logManager = logManager;
_fileSystem = fileSystem;
_logManager.LoggerLoaded += kernel_LoggerLoaded;
}
@ -53,7 +56,7 @@ namespace MediaBrowser.Api.WebSocket
state.StartLine = 0;
}
var lines = await GetLogLines(state.LastLogFilePath, state.StartLine).ConfigureAwait(false);
var lines = await GetLogLines(state.LastLogFilePath, state.StartLine, _fileSystem).ConfigureAwait(false);
state.StartLine += lines.Count;
@ -96,11 +99,11 @@ namespace MediaBrowser.Api.WebSocket
/// <param name="logFilePath">The log file path.</param>
/// <param name="startLine">The start line.</param>
/// <returns>Task{IEnumerable{System.String}}.</returns>
internal static async Task<List<string>> GetLogLines(string logFilePath, int startLine)
internal static async Task<List<string>> GetLogLines(string logFilePath, int startLine, IFileSystem fileSystem)
{
var lines = new List<string>();
using (var fs = new FileStream(logFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, StreamDefaults.DefaultFileStreamBufferSize, true))
using (var fs = fileSystem.GetFileStream(logFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
{
using (var reader = new StreamReader(fs))
{

View File

@ -1,5 +1,4 @@
using System.Net;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Events;
using MediaBrowser.Common.Implementations.Archiving;
using MediaBrowser.Common.Implementations.IO;
@ -7,6 +6,7 @@ using MediaBrowser.Common.Implementations.ScheduledTasks;
using MediaBrowser.Common.Implementations.Security;
using MediaBrowser.Common.Implementations.Serialization;
using MediaBrowser.Common.Implementations.Updates;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.ScheduledTasks;
@ -21,6 +21,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Threading;
@ -150,15 +151,17 @@ namespace MediaBrowser.Common.Implementations
/// Gets or sets the installation manager.
/// </summary>
/// <value>The installation manager.</value>
protected IInstallationManager InstallationManager { get; set; }
protected IInstallationManager InstallationManager { get; private set; }
protected IFileSystem FileSystemManager { get; private set; }
/// <summary>
/// Gets or sets the zip client.
/// </summary>
/// <value>The zip client.</value>
protected IZipClient ZipClient { get; set; }
protected IZipClient ZipClient { get; private set; }
protected IIsoManager IsoManager { get; set; }
protected IIsoManager IsoManager { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="BaseApplicationHost{TApplicationPathsType}"/> class.
@ -347,7 +350,10 @@ namespace MediaBrowser.Common.Implementations
RegisterSingleInstance(TaskManager);
HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, Logger, CreateHttpClient);
FileSystemManager = CreateFileSystemManager();
RegisterSingleInstance(FileSystemManager);
HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, Logger, CreateHttpClient, FileSystemManager);
RegisterSingleInstance(HttpClient);
NetworkManager = CreateNetworkManager();
@ -367,6 +373,11 @@ namespace MediaBrowser.Common.Implementations
});
}
protected virtual IFileSystem CreateFileSystemManager()
{
return new CommonFileSystem(Logger, true);
}
protected abstract HttpClient CreateHttpClient(bool enableHttpCompression);
/// <summary>

View File

@ -34,6 +34,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
public delegate HttpClient GetHttpClientHandler(bool enableHttpCompression);
private readonly GetHttpClientHandler _getHttpClientHandler;
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="HttpClientManager"/> class.
@ -46,7 +47,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
/// or
/// logger
/// </exception>
public HttpClientManager(IApplicationPaths appPaths, ILogger logger, GetHttpClientHandler getHttpClientHandler)
public HttpClientManager(IApplicationPaths appPaths, ILogger logger, GetHttpClientHandler getHttpClientHandler, IFileSystem fileSystem)
{
if (appPaths == null)
{
@ -59,6 +60,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
_logger = logger;
_getHttpClientHandler = getHttpClientHandler;
_fileSystem = fileSystem;
_appPaths = appPaths;
}
@ -417,7 +419,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
// We're not able to track progress
using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
{
using (var fs = new FileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
using (var fs = _fileSystem.GetFileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, true))
{
await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false);
}
@ -427,7 +429,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
{
using (var stream = ProgressStream.CreateReadProgressStream(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), options.Progress.Report, contentLength.Value))
{
using (var fs = new FileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
using (var fs = _fileSystem.GetFileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, true))
{
await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false);
}

View File

@ -1,24 +1,96 @@
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Common.IO;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Specialized;
using System.IO;
using System.Text;
namespace MediaBrowser.Controller.IO
namespace MediaBrowser.Common.Implementations.IO
{
/// <summary>
/// Class FileSystem
/// Class CommonFileSystem
/// </summary>
public static class FileSystem
public class CommonFileSystem : IFileSystem
{
protected ILogger Logger;
private readonly bool _supportsAsyncFileStreams;
public CommonFileSystem(ILogger logger, bool supportsAsyncFileStreams)
{
Logger = logger;
_supportsAsyncFileStreams = supportsAsyncFileStreams;
}
/// <summary>
/// Determines whether the specified filename is shortcut.
/// </summary>
/// <param name="filename">The filename.</param>
/// <returns><c>true</c> if the specified filename is shortcut; otherwise, <c>false</c>.</returns>
/// <exception cref="System.ArgumentNullException">filename</exception>
public virtual bool IsShortcut(string filename)
{
if (string.IsNullOrEmpty(filename))
{
throw new ArgumentNullException("filename");
}
var extension = Path.GetExtension(filename);
return string.Equals(extension, ".mblink", StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// Resolves the shortcut.
/// </summary>
/// <param name="filename">The filename.</param>
/// <returns>System.String.</returns>
/// <exception cref="System.ArgumentNullException">filename</exception>
public virtual string ResolveShortcut(string filename)
{
if (string.IsNullOrEmpty(filename))
{
throw new ArgumentNullException("filename");
}
if (string.Equals(Path.GetExtension(filename), ".mblink", StringComparison.OrdinalIgnoreCase))
{
return File.ReadAllText(filename);
}
return null;
}
/// <summary>
/// Creates the shortcut.
/// </summary>
/// <param name="shortcutPath">The shortcut path.</param>
/// <param name="target">The target.</param>
/// <exception cref="System.ArgumentNullException">
/// shortcutPath
/// or
/// target
/// </exception>
public void CreateShortcut(string shortcutPath, string target)
{
if (string.IsNullOrEmpty(shortcutPath))
{
throw new ArgumentNullException("shortcutPath");
}
if (string.IsNullOrEmpty(target))
{
throw new ArgumentNullException("target");
}
File.WriteAllText(shortcutPath, target);
}
/// <summary>
/// Gets the file system info.
/// </summary>
/// <param name="path">The path.</param>
/// <returns>FileSystemInfo.</returns>
public static FileSystemInfo GetFileSystemInfo(string path)
public FileSystemInfo GetFileSystemInfo(string path)
{
// Take a guess to try and avoid two file system hits, but we'll double-check by calling Exists
if (Path.HasExtension(path))
@ -45,48 +117,6 @@ namespace MediaBrowser.Controller.IO
}
}
/// <summary>
/// Gets the creation time UTC.
/// </summary>
/// <param name="info">The info.</param>
/// <param name="logger">The logger.</param>
/// <returns>DateTime.</returns>
public static DateTime GetLastWriteTimeUtc(FileSystemInfo info, ILogger logger)
{
// This could throw an error on some file systems that have dates out of range
try
{
return info.LastWriteTimeUtc;
}
catch (Exception ex)
{
logger.ErrorException("Error determining LastAccessTimeUtc for {0}", ex, info.FullName);
return DateTime.MinValue;
}
}
/// <summary>
/// Gets the creation time UTC.
/// </summary>
/// <param name="info">The info.</param>
/// <param name="logger">The logger.</param>
/// <returns>DateTime.</returns>
public static DateTime GetCreationTimeUtc(FileSystemInfo info, ILogger logger)
{
// This could throw an error on some file systems that have dates out of range
try
{
return info.CreationTimeUtc;
}
catch (Exception ex)
{
logger.ErrorException("Error determining CreationTimeUtc for {0}", ex, info.FullName);
return DateTime.MinValue;
}
}
/// <summary>
/// The space char
/// </summary>
@ -102,7 +132,7 @@ namespace MediaBrowser.Controller.IO
/// <param name="filename">The filename.</param>
/// <returns>System.String.</returns>
/// <exception cref="System.ArgumentNullException">filename</exception>
public static string GetValidFilename(string filename)
public string GetValidFilename(string filename)
{
if (string.IsNullOrEmpty(filename))
{
@ -120,144 +150,71 @@ namespace MediaBrowser.Controller.IO
}
/// <summary>
/// Resolves the shortcut.
/// Gets the creation time UTC.
/// </summary>
/// <param name="filename">The filename.</param>
/// <returns>System.String.</returns>
/// <exception cref="System.ArgumentNullException">filename</exception>
public static string ResolveShortcut(string filename)
/// <param name="info">The info.</param>
/// <returns>DateTime.</returns>
public DateTime GetCreationTimeUtc(FileSystemInfo info)
{
if (string.IsNullOrEmpty(filename))
// This could throw an error on some file systems that have dates out of range
try
{
throw new ArgumentNullException("filename");
return info.CreationTimeUtc;
}
if (string.Equals(Path.GetExtension(filename), ".mblink", StringComparison.OrdinalIgnoreCase))
catch (Exception ex)
{
return File.ReadAllText(filename);
}
//return new WindowsShortcut(filename).ResolvedPath;
var link = new ShellLink();
((IPersistFile)link).Load(filename, NativeMethods.STGM_READ);
// TODO: if I can get hold of the hwnd call resolve first. This handles moved and renamed files.
// ((IShellLinkW)link).Resolve(hwnd, 0)
var sb = new StringBuilder(NativeMethods.MAX_PATH);
WIN32_FIND_DATA data;
((IShellLinkW)link).GetPath(sb, sb.Capacity, out data, 0);
return sb.ToString();
}
/// <summary>
/// Creates a shortcut file pointing to a specified path
/// </summary>
/// <param name="shortcutPath">The shortcut path.</param>
/// <param name="target">The target.</param>
/// <exception cref="System.ArgumentNullException">shortcutPath</exception>
public static void CreateShortcut(string shortcutPath, string target)
{
if (string.IsNullOrEmpty(shortcutPath))
{
throw new ArgumentNullException("shortcutPath");
}
if (string.IsNullOrEmpty(target))
{
throw new ArgumentNullException("target");
}
File.WriteAllText(shortcutPath, target);
//var link = new ShellLink();
//((IShellLinkW)link).SetPath(target);
//((IPersistFile)link).Save(shortcutPath, true);
}
private static readonly Dictionary<string, string> ShortcutExtensionsDictionary = new[] { ".mblink", ".lnk" }
.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
/// <summary>
/// Determines whether the specified filename is shortcut.
/// </summary>
/// <param name="filename">The filename.</param>
/// <returns><c>true</c> if the specified filename is shortcut; otherwise, <c>false</c>.</returns>
/// <exception cref="System.ArgumentNullException">filename</exception>
public static bool IsShortcut(string filename)
{
if (string.IsNullOrEmpty(filename))
{
throw new ArgumentNullException("filename");
}
var extension = Path.GetExtension(filename);
return !string.IsNullOrEmpty(extension) && ShortcutExtensionsDictionary.ContainsKey(extension);
}
/// <summary>
/// Copies all.
/// </summary>
/// <param name="source">The source.</param>
/// <param name="target">The target.</param>
/// <exception cref="System.ArgumentNullException">source</exception>
/// <exception cref="System.ArgumentException">The source and target directories are the same</exception>
public static void CopyAll(string source, string target)
{
if (string.IsNullOrEmpty(source))
{
throw new ArgumentNullException("source");
}
if (string.IsNullOrEmpty(target))
{
throw new ArgumentNullException("target");
}
if (source.Equals(target, StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException("The source and target directories are the same");
}
// Check if the target directory exists, if not, create it.
Directory.CreateDirectory(target);
foreach (var file in Directory.EnumerateFiles(source))
{
File.Copy(file, Path.Combine(target, Path.GetFileName(file)), true);
}
// Copy each subdirectory using recursion.
foreach (var dir in Directory.EnumerateDirectories(source))
{
CopyAll(dir, Path.Combine(target, Path.GetFileName(dir)));
Logger.ErrorException("Error determining CreationTimeUtc for {0}", ex, info.FullName);
return DateTime.MinValue;
}
}
/// <summary>
/// Parses the ini file.
/// Gets the creation time UTC.
/// </summary>
/// <param name="info">The info.</param>
/// <param name="logger">The logger.</param>
/// <returns>DateTime.</returns>
public DateTime GetLastWriteTimeUtc(FileSystemInfo info)
{
// This could throw an error on some file systems that have dates out of range
try
{
return info.LastWriteTimeUtc;
}
catch (Exception ex)
{
Logger.ErrorException("Error determining LastAccessTimeUtc for {0}", ex, info.FullName);
return DateTime.MinValue;
}
}
/// <summary>
/// Gets the last write time UTC.
/// </summary>
/// <param name="path">The path.</param>
/// <returns>NameValueCollection.</returns>
public static NameValueCollection ParseIniFile(string path)
/// <returns>DateTime.</returns>
public DateTime GetLastWriteTimeUtc(string path)
{
var values = new NameValueCollection();
return GetLastWriteTimeUtc(GetFileSystemInfo(path));
}
foreach (var line in File.ReadAllLines(path))
/// <summary>
/// Gets the file stream.
/// </summary>
/// <param name="path">The path.</param>
/// <param name="mode">The mode.</param>
/// <param name="access">The access.</param>
/// <param name="share">The share.</param>
/// <param name="isAsync">if set to <c>true</c> [is asynchronous].</param>
/// <returns>FileStream.</returns>
public FileStream GetFileStream(string path, FileMode mode, FileAccess access, FileShare share, bool isAsync = false)
{
if (_supportsAsyncFileStreams && isAsync)
{
var data = line.Split('=');
if (data.Length < 2) continue;
var key = data[0];
var value = data.Length == 2 ? data[1] : string.Join(string.Empty, data, 1, data.Length - 1);
values[key] = value;
return new FileStream(path, mode, access, share, 4096, true);
}
return values;
return new FileStream(path, mode, access, share);
}
}
@ -381,4 +338,5 @@ namespace MediaBrowser.Controller.IO
}
}
}

View File

@ -44,6 +44,10 @@
<Reference Include="SharpCompress">
<HintPath>..\packages\sharpcompress.0.10.1.3\lib\net40\SharpCompress.dll</HintPath>
</Reference>
<Reference Include="SimpleInjector, Version=2.3.6.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\SimpleInjector.2.3.6\lib\net40-client\SimpleInjector.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
@ -54,9 +58,6 @@
<Reference Include="ServiceStack.Text">
<HintPath>..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll</HintPath>
</Reference>
<Reference Include="SimpleInjector">
<HintPath>..\packages\SimpleInjector.2.3.5\lib\net40-client\SimpleInjector.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\SharedVersion.cs">
@ -68,6 +69,7 @@
<Compile Include="Configuration\BaseConfigurationManager.cs" />
<Compile Include="HttpClientManager\HttpClientInfo.cs" />
<Compile Include="HttpClientManager\HttpClientManager.cs" />
<Compile Include="IO\CommonFileSystem.cs" />
<Compile Include="IO\IsoManager.cs" />
<Compile Include="Logging\LogHelper.cs" />
<Compile Include="Logging\NLogger.cs" />

View File

@ -1,12 +1,13 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Logging;
namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
{
@ -23,14 +24,17 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="DeleteCacheFileTask" /> class.
/// </summary>
/// <param name="appPaths">The app paths.</param>
public DeleteCacheFileTask(IApplicationPaths appPaths, ILogger logger)
public DeleteCacheFileTask(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem)
{
ApplicationPaths = appPaths;
_logger = logger;
_fileSystem = fileSystem;
}
/// <summary>
@ -94,7 +98,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
private void DeleteCacheFilesFromDirectory(CancellationToken cancellationToken, string directory, DateTime minDateModified, IProgress<double> progress)
{
var filesToDelete = new DirectoryInfo(directory).EnumerateFiles("*", SearchOption.AllDirectories)
.Where(f => f.LastWriteTimeUtc < minDateModified)
.Where(f => _fileSystem.GetLastWriteTimeUtc(f) < minDateModified)
.ToList();
var index = 0;

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.ScheduledTasks;
using System;
using System.Collections.Generic;
@ -20,13 +21,16 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
/// <value>The configuration manager.</value>
private IConfigurationManager ConfigurationManager { get; set; }
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="DeleteLogFileTask" /> class.
/// </summary>
/// <param name="configurationManager">The configuration manager.</param>
public DeleteLogFileTask(IConfigurationManager configurationManager)
public DeleteLogFileTask(IConfigurationManager configurationManager, IFileSystem fileSystem)
{
ConfigurationManager = configurationManager;
_fileSystem = fileSystem;
}
/// <summary>
@ -58,7 +62,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
var minDateModified = DateTime.UtcNow.AddDays(-(ConfigurationManager.CommonConfiguration.LogFileRetentionDays));
var filesToDelete = new DirectoryInfo(ConfigurationManager.CommonApplicationPaths.LogDirectoryPath).EnumerateFileSystemInfos("*", SearchOption.AllDirectories)
.Where(f => f.LastWriteTimeUtc < minDateModified)
.Where(f => _fileSystem.GetLastWriteTimeUtc(f) < minDateModified)
.ToList();
var index = 0;

View File

@ -3,5 +3,5 @@
<package id="NLog" version="2.1.0" targetFramework="net45" />
<package id="ServiceStack.Text" version="3.9.62" targetFramework="net45" />
<package id="sharpcompress" version="0.10.1.3" targetFramework="net45" />
<package id="SimpleInjector" version="2.3.5" targetFramework="net45" />
<package id="SimpleInjector" version="2.3.6" targetFramework="net45" />
</packages>

View File

@ -0,0 +1,78 @@
using System;
using System.IO;
namespace MediaBrowser.Common.IO
{
/// <summary>
/// Interface IFileSystem
/// </summary>
public interface IFileSystem
{
/// <summary>
/// Determines whether the specified filename is shortcut.
/// </summary>
/// <param name="filename">The filename.</param>
/// <returns><c>true</c> if the specified filename is shortcut; otherwise, <c>false</c>.</returns>
bool IsShortcut(string filename);
/// <summary>
/// Resolves the shortcut.
/// </summary>
/// <param name="filename">The filename.</param>
/// <returns>System.String.</returns>
string ResolveShortcut(string filename);
/// <summary>
/// Creates the shortcut.
/// </summary>
/// <param name="shortcutPath">The shortcut path.</param>
/// <param name="target">The target.</param>
void CreateShortcut(string shortcutPath, string target);
/// <summary>
/// Gets the file system info.
/// </summary>
/// <param name="path">The path.</param>
/// <returns>FileSystemInfo.</returns>
FileSystemInfo GetFileSystemInfo(string path);
/// <summary>
/// Gets the valid filename.
/// </summary>
/// <param name="filename">The filename.</param>
/// <returns>System.String.</returns>
string GetValidFilename(string filename);
/// <summary>
/// Gets the creation time UTC.
/// </summary>
/// <param name="info">The info.</param>
/// <returns>DateTime.</returns>
DateTime GetCreationTimeUtc(FileSystemInfo info);
/// <summary>
/// Gets the last write time UTC.
/// </summary>
/// <param name="info">The information.</param>
/// <returns>DateTime.</returns>
DateTime GetLastWriteTimeUtc(FileSystemInfo info);
/// <summary>
/// Gets the last write time UTC.
/// </summary>
/// <param name="path">The path.</param>
/// <returns>DateTime.</returns>
DateTime GetLastWriteTimeUtc(string path);
/// <summary>
/// Gets the file stream.
/// </summary>
/// <param name="path">The path.</param>
/// <param name="mode">The mode.</param>
/// <param name="access">The access.</param>
/// <param name="share">The share.</param>
/// <param name="isAsync">if set to <c>true</c> [is asynchronous].</param>
/// <returns>FileStream.</returns>
FileStream GetFileStream(string path, FileMode mode, FileAccess access, FileShare share, bool isAsync = false);
}
}

View File

@ -60,6 +60,7 @@
<Compile Include="Events\GenericEventArgs.cs" />
<Compile Include="Extensions\ResourceNotFoundException.cs" />
<Compile Include="IO\FileSystemRepository.cs" />
<Compile Include="IO\IFileSystem.cs" />
<Compile Include="IO\ProgressStream.cs" />
<Compile Include="IO\StreamDefaults.cs" />
<Compile Include="MediaInfo\MediaInfoResult.cs" />

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.IO;
@ -212,6 +213,7 @@ namespace MediaBrowser.Controller.Entities
public static IProviderManager ProviderManager { get; set; }
public static ILocalizationManager LocalizationManager { get; set; }
public static IItemRepository ItemRepository { get; set; }
public static IFileSystem FileSystem { get; set; }
/// <summary>
/// Returns a <see cref="System.String" /> that represents this instance.
@ -395,7 +397,7 @@ namespace MediaBrowser.Controller.Entities
// When resolving the root, we need it's grandchildren (children of user views)
var flattenFolderDepth = isPhysicalRoot ? 2 : 0;
args.FileSystemDictionary = FileData.GetFilteredFileSystemEntries(args.Path, Logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf);
args.FileSystemDictionary = FileData.GetFilteredFileSystemEntries(args.Path, FileSystem, Logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf);
// Need to remove subpaths that may have been resolved from shortcuts
// Example: if \\server\movies exists, then strip out \\server\movies\action
@ -413,7 +415,7 @@ namespace MediaBrowser.Controller.Entities
}
//update our dates
EntityResolutionHelper.EnsureDates(this, args, false);
EntityResolutionHelper.EnsureDates(FileSystem, this, args, false);
IsOffline = false;
@ -1337,6 +1339,13 @@ namespace MediaBrowser.Controller.Entities
var data = userManager.GetUserData(user.Id, key);
if (datePlayed.HasValue)
{
// Incremenet
data.PlayCount++;
}
// Ensure it's at least one
data.PlayCount = Math.Max(data.PlayCount, 1);
data.LastPlayedDate = datePlayed ?? data.LastPlayedDate;
@ -1530,7 +1539,8 @@ namespace MediaBrowser.Controller.Entities
}
// Refresh metadata
return RefreshMetadata(CancellationToken.None, forceSave: true);
// Need to disable slow providers or the image might get re-downloaded
return RefreshMetadata(CancellationToken.None, forceSave: true, allowSlowProviders: false);
}
/// <summary>
@ -1728,7 +1738,7 @@ namespace MediaBrowser.Controller.Entities
if (locationType == LocationType.Remote ||
locationType == LocationType.Virtual)
{
return File.GetLastWriteTimeUtc(imagePath);
return FileSystem.GetLastWriteTimeUtc(imagePath);
}
var metaFileEntry = ResolveArgs.GetMetaFileByPath(imagePath);
@ -1745,7 +1755,7 @@ namespace MediaBrowser.Controller.Entities
}
// See if we can avoid a file system lookup by looking for the file in ResolveArgs
return metaFileEntry == null ? File.GetLastWriteTimeUtc(imagePath) : metaFileEntry.LastWriteTimeUtc;
return metaFileEntry == null ? FileSystem.GetLastWriteTimeUtc(imagePath) : FileSystem.GetLastWriteTimeUtc(metaFileEntry);
}
}
}

View File

@ -693,7 +693,7 @@ namespace MediaBrowser.Controller.Entities
//existing item - check if it has changed
if (currentChild.HasChanged(child))
{
EntityResolutionHelper.EnsureDates(currentChild, child.ResolveArgs, false);
EntityResolutionHelper.EnsureDates(FileSystem, currentChild, child.ResolveArgs, false);
validChildren.Add(new Tuple<BaseItem, bool>(currentChild, true));
}

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
@ -191,5 +192,23 @@ namespace MediaBrowser.Controller.Entities.TV
return false;
}
public bool IsMissingEpisode
{
get
{
return LocationType == Model.Entities.LocationType.Virtual && PremiereDate.HasValue && PremiereDate.Value < DateTime.UtcNow;
}
}
public bool IsUnaired
{
get { return PremiereDate.HasValue && PremiereDate.Value.ToLocalTime().Date >= DateTime.Now.Date; }
}
public bool IsVirtualUnaired
{
get { return LocationType == Model.Entities.LocationType.Virtual && IsUnaired; }
}
}
}

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Library;
using System.Linq;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Localization;
using System;
using System.Collections.Generic;
@ -147,5 +148,25 @@ namespace MediaBrowser.Controller.Entities.TV
{
return IndexNumber != null ? IndexNumber.Value.ToString("0000") : Name;
}
public bool IsMissingSeason
{
get { return LocationType == Model.Entities.LocationType.Virtual && Children.OfType<Episode>().All(i => i.IsMissingEpisode); }
}
public bool IsUnaired
{
get { return Children.OfType<Episode>().All(i => i.IsUnaired); }
}
public bool IsVirtualUnaired
{
get { return LocationType == Model.Entities.LocationType.Virtual && IsUnaired; }
}
public bool IsMissingOrVirtualUnaired
{
get { return LocationType == Model.Entities.LocationType.Virtual && Children.OfType<Episode>().All(i => i.IsVirtualUnaired || i.IsMissingEpisode); }
}
}
}

View File

@ -165,7 +165,7 @@ namespace MediaBrowser.Controller.Entities
// Ensure it's been lazy loaded
var config = Configuration;
return File.GetLastWriteTimeUtc(ConfigurationFilePath);
return FileSystem.GetLastWriteTimeUtc(ConfigurationFilePath);
}
}

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Library;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
@ -15,6 +16,7 @@ namespace MediaBrowser.Controller.IO
/// Gets the filtered file system entries.
/// </summary>
/// <param name="path">The path.</param>
/// <param name="fileSystem">The file system.</param>
/// <param name="logger">The logger.</param>
/// <param name="args">The args.</param>
/// <param name="searchPattern">The search pattern.</param>
@ -22,7 +24,7 @@ namespace MediaBrowser.Controller.IO
/// <param name="resolveShortcuts">if set to <c>true</c> [resolve shortcuts].</param>
/// <returns>Dictionary{System.StringFileSystemInfo}.</returns>
/// <exception cref="System.ArgumentNullException">path</exception>
public static Dictionary<string, FileSystemInfo> GetFilteredFileSystemEntries(string path, ILogger logger, ItemResolveArgs args, string searchPattern = "*", int flattenFolderDepth = 0, bool resolveShortcuts = true)
public static Dictionary<string, FileSystemInfo> GetFilteredFileSystemEntries(string path, IFileSystem fileSystem, ILogger logger, ItemResolveArgs args, string searchPattern = "*", int flattenFolderDepth = 0, bool resolveShortcuts = true)
{
if (string.IsNullOrEmpty(path))
{
@ -56,9 +58,9 @@ namespace MediaBrowser.Controller.IO
var fullName = entry.FullName;
if (resolveShortcuts && FileSystem.IsShortcut(fullName))
if (resolveShortcuts && fileSystem.IsShortcut(fullName))
{
var newPath = FileSystem.ResolveShortcut(fullName);
var newPath = fileSystem.ResolveShortcut(fullName);
if (string.IsNullOrWhiteSpace(newPath))
{
@ -77,7 +79,7 @@ namespace MediaBrowser.Controller.IO
}
else if (flattenFolderDepth > 0 && isDirectory)
{
foreach (var child in GetFilteredFileSystemEntries(fullName, logger, args, flattenFolderDepth: flattenFolderDepth - 1, resolveShortcuts: resolveShortcuts))
foreach (var child in GetFilteredFileSystemEntries(fullName, fileSystem, logger, args, flattenFolderDepth: flattenFolderDepth - 1, resolveShortcuts: resolveShortcuts))
{
dict[child.Key] = child.Value;
}

View File

@ -108,6 +108,7 @@
<Compile Include="Notifications\INotificationsRepository.cs" />
<Compile Include="Notifications\NotificationUpdateEventArgs.cs" />
<Compile Include="Providers\IDynamicInfoProvider.cs" />
<Compile Include="Providers\IImageProvider.cs" />
<Compile Include="Session\ISessionManager.cs" />
<Compile Include="Drawing\ImageExtensions.cs" />
<Compile Include="Entities\AggregateFolder.cs" />
@ -139,9 +140,7 @@
<Compile Include="Entities\Video.cs" />
<Compile Include="Entities\CollectionFolder.cs" />
<Compile Include="Entities\Year.cs" />
<Compile Include="IO\FileSystem.cs" />
<Compile Include="IO\IDirectoryWatchers.cs" />
<Compile Include="IO\NativeMethods.cs" />
<Compile Include="IServerApplicationHost.cs" />
<Compile Include="IServerApplicationPaths.cs" />
<Compile Include="Library\SearchHintInfo.cs" />

View File

@ -1,6 +1,7 @@
using MediaBrowser.Common.IO;
using MediaBrowser.Common.MediaInfo;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
@ -35,6 +36,8 @@ namespace MediaBrowser.Controller.MediaInfo
private readonly ILogger _logger;
private readonly IItemRepository _itemRepo;
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="FFMpegManager" /> class.
/// </summary>
@ -43,12 +46,13 @@ namespace MediaBrowser.Controller.MediaInfo
/// <param name="logger">The logger.</param>
/// <param name="itemRepo">The item repo.</param>
/// <exception cref="System.ArgumentNullException">zipClient</exception>
public FFMpegManager(IServerApplicationPaths appPaths, IMediaEncoder encoder, ILogger logger, IItemRepository itemRepo)
public FFMpegManager(IServerApplicationPaths appPaths, IMediaEncoder encoder, ILogger logger, IItemRepository itemRepo, IFileSystem fileSystem)
{
_appPaths = appPaths;
_encoder = encoder;
_logger = logger;
_itemRepo = itemRepo;
_fileSystem = fileSystem;
VideoImageCache = new FileSystemRepository(VideoImagesDataPath);
SubtitleCache = new FileSystemRepository(SubtitleCachePath);
@ -203,7 +207,7 @@ namespace MediaBrowser.Controller.MediaInfo
if (stream.IsExternal)
{
ticksParam += File.GetLastWriteTimeUtc(stream.Path).Ticks;
ticksParam += _fileSystem.GetLastWriteTimeUtc(stream.Path).Ticks;
}
return SubtitleCache.GetResourcePath(input.Id + "_" + subtitleStreamIndex + "_" + input.DateModified.Ticks + ticksParam, outputExtension);

View File

@ -552,32 +552,6 @@ namespace MediaBrowser.Controller.Providers
}
break;
case "GamesDbId":
var gamesdbId = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(gamesdbId))
{
item.SetProviderId(MetadataProviders.Gamesdb, gamesdbId);
}
break;
case "Players":
{
var val = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(val))
{
int num;
if (int.TryParse(val, NumberStyles.Integer, _usCulture, out num))
{
var game = item as Game;
if (game != null)
{
game.PlayersSupported = num;
}
}
}
break;
}
case "VoteCount":
{
var val = reader.ReadElementContentAsString();
@ -592,19 +566,6 @@ namespace MediaBrowser.Controller.Providers
}
break;
}
case "GameSystem":
{
var val = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(val))
{
var game = item as Game;
if (game != null)
{
game.GameSystem = val;
}
}
break;
}
case "MusicbrainzId":
{
var mbz = reader.ReadElementContentAsString();

View File

@ -0,0 +1,38 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.Providers
{
/// <summary>
/// Interface IImageProvider
/// </summary>
public interface IImageProvider
{
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name.</value>
string Name { get; }
/// <summary>
/// Supportses the specified item.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="imageType">Type of the image.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
bool Supports(BaseItem item, ImageType imageType);
/// <summary>
/// Gets the available images.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="imageType">Type of the image.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{IEnumerable{RemoteImageInfo}}.</returns>
Task<IEnumerable<RemoteImageInfo>> GetAvailableImages(BaseItem item, ImageType imageType, CancellationToken cancellationToken);
}
}

View File

@ -1,6 +1,7 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using System.Collections.Generic;
using System.IO;
using System.Threading;
@ -52,6 +53,16 @@ namespace MediaBrowser.Controller.Providers
/// Adds the metadata providers.
/// </summary>
/// <param name="providers">The providers.</param>
void AddParts(IEnumerable<BaseMetadataProvider> providers);
/// <param name="imageProviders">The image providers.</param>
void AddParts(IEnumerable<BaseMetadataProvider> providers, IEnumerable<IImageProvider> imageProviders);
/// <summary>
/// Gets the available remote images.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="type">The type.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{IEnumerable{RemoteImageInfo}}.</returns>
Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(BaseItem item, ImageType type, CancellationToken cancellationToken);
}
}

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using System;
@ -44,7 +45,8 @@ namespace MediaBrowser.Controller.Resolvers
".f4v",
".3gp",
".webm",
".mts"
".mts",
".rec"
};
private static readonly Dictionary<string, string> VideoFileExtensionsDictionary = VideoFileExtensions.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
@ -125,10 +127,11 @@ namespace MediaBrowser.Controller.Resolvers
/// <summary>
/// Ensures DateCreated and DateModified have values
/// </summary>
/// <param name="fileSystem">The file system.</param>
/// <param name="item">The item.</param>
/// <param name="args">The args.</param>
/// <param name="includeCreationTime">if set to <c>true</c> [include creation time].</param>
public static void EnsureDates(BaseItem item, ItemResolveArgs args, bool includeCreationTime)
public static void EnsureDates(IFileSystem fileSystem, BaseItem item, ItemResolveArgs args, bool includeCreationTime)
{
if (!Path.IsPathRooted(item.Path))
{
@ -144,22 +147,22 @@ namespace MediaBrowser.Controller.Resolvers
{
if (includeCreationTime)
{
item.DateCreated = childData.CreationTimeUtc;
item.DateCreated = fileSystem.GetCreationTimeUtc(childData);
}
item.DateModified = childData.LastWriteTimeUtc;
item.DateModified = fileSystem.GetLastWriteTimeUtc(childData);
}
else
{
var fileData = FileSystem.GetFileSystemInfo(item.Path);
var fileData = fileSystem.GetFileSystemInfo(item.Path);
if (fileData.Exists)
{
if (includeCreationTime)
{
item.DateCreated = fileData.CreationTimeUtc;
item.DateCreated = fileSystem.GetCreationTimeUtc(fileData);
}
item.DateModified = fileData.LastWriteTimeUtc;
item.DateModified = fileSystem.GetLastWriteTimeUtc(fileData);
}
}
}
@ -167,9 +170,9 @@ namespace MediaBrowser.Controller.Resolvers
{
if (includeCreationTime)
{
item.DateCreated = args.FileInfo.CreationTimeUtc;
item.DateCreated = fileSystem.GetCreationTimeUtc(args.FileInfo);
}
item.DateModified = args.FileInfo.LastWriteTimeUtc;
item.DateModified = fileSystem.GetLastWriteTimeUtc(args.FileInfo);
}
}
}

View File

@ -290,6 +290,9 @@
<Compile Include="..\MediaBrowser.Model\Plugins\PluginInfo.cs">
<Link>Plugins\PluginInfo.cs</Link>
</Compile>
<Compile Include="..\MediaBrowser.Model\Providers\RemoteImageInfo.cs">
<Link>Providers\RemoteImageInfo.cs</Link>
</Compile>
<Compile Include="..\MediaBrowser.Model\Querying\ArtistsQuery.cs">
<Link>Querying\ArtistsQuery.cs</Link>
</Compile>

View File

@ -277,6 +277,9 @@
<Compile Include="..\MediaBrowser.Model\Plugins\PluginInfo.cs">
<Link>Plugins\PluginInfo.cs</Link>
</Compile>
<Compile Include="..\MediaBrowser.Model\Providers\RemoteImageInfo.cs">
<Link>Providers\RemoteImageInfo.cs</Link>
</Compile>
<Compile Include="..\MediaBrowser.Model\Querying\ArtistsQuery.cs">
<Link>Querying\ArtistsQuery.cs</Link>
</Compile>

View File

@ -56,16 +56,18 @@ namespace MediaBrowser.Model.Configuration
public bool IsDisabled { get; set; }
public bool DisplayVirtualEpisodes { get; set; }
public bool DisplayMissingEpisodes { get; set; }
public bool DisplayUnairedEpisodes { get; set; }
public bool EnableRemoteControlOfOtherUsers { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="UserConfiguration" /> class.
/// </summary>
public UserConfiguration()
{
IsAdministrator = true;
EnableRemoteControlOfOtherUsers = true;
BlockNotRated = false;
DisplayVirtualEpisodes = true;
}
}
}

View File

@ -36,6 +36,8 @@ namespace MediaBrowser.Model.Entities
/// </summary>
TmdbCollection,
MusicBrainzReleaseGroup,
Zap2It
Zap2It,
NesBox,
NesBoxRom
}
}

View File

@ -59,6 +59,7 @@
<Compile Include="Dto\ItemByNameCounts.cs" />
<Compile Include="Dto\ItemCounts.cs" />
<Compile Include="Dto\ItemIndex.cs" />
<Compile Include="Providers\RemoteImageInfo.cs" />
<Compile Include="Dto\StudioDto.cs" />
<Compile Include="Entities\CollectionType.cs" />
<Compile Include="Entities\ItemReview.cs" />

View File

@ -0,0 +1,59 @@

using MediaBrowser.Model.Entities;
namespace MediaBrowser.Model.Providers
{
/// <summary>
/// Class RemoteImageInfo
/// </summary>
public class RemoteImageInfo
{
/// <summary>
/// Gets or sets the name of the provider.
/// </summary>
/// <value>The name of the provider.</value>
public string ProviderName { get; set; }
/// <summary>
/// Gets or sets the URL.
/// </summary>
/// <value>The URL.</value>
public string Url { get; set; }
/// <summary>
/// Gets or sets the height.
/// </summary>
/// <value>The height.</value>
public int? Height { get; set; }
/// <summary>
/// Gets or sets the width.
/// </summary>
/// <value>The width.</value>
public int? Width { get; set; }
/// <summary>
/// Gets or sets the community rating.
/// </summary>
/// <value>The community rating.</value>
public double? CommunityRating { get; set; }
/// <summary>
/// Gets or sets the vote count.
/// </summary>
/// <value>The vote count.</value>
public int? VoteCount { get; set; }
/// <summary>
/// Gets or sets the language.
/// </summary>
/// <value>The language.</value>
public string Language { get; set; }
/// <summary>
/// Gets or sets the type.
/// </summary>
/// <value>The type.</value>
public ImageType Type { get; set; }
}
}

View File

@ -241,16 +241,27 @@ namespace MediaBrowser.Model.Querying
/// </summary>
/// <value>The location types.</value>
public LocationType[] LocationTypes { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is missing episode.
/// </summary>
/// <value><c>null</c> if [is missing episode] contains no value, <c>true</c> if [is missing episode]; otherwise, <c>false</c>.</value>
public bool? IsMissing { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is unaired episode.
/// </summary>
/// <value><c>null</c> if [is unaired episode] contains no value, <c>true</c> if [is unaired episode]; otherwise, <c>false</c>.</value>
public bool? IsUnaired { get; set; }
public bool? IsVirtualUnaired { get; set; }
/// <summary>
/// Gets or sets the exclude location types.
/// </summary>
/// <value>The exclude location types.</value>
public LocationType[] ExcludeLocationTypes { get; set; }
public bool? HasPremiereDate { get; set; }
public DateTime? MinPremiereDate { get; set; }
public DateTime? MaxPremiereDate { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="ItemQuery" /> class.
/// </summary>

View File

@ -1,6 +1,4 @@
using MediaBrowser.Model.Entities;
using System;

namespace MediaBrowser.Model.Querying
{
public class NextUpQuery
@ -11,6 +9,12 @@ namespace MediaBrowser.Model.Querying
/// <value>The user id.</value>
public string UserId { get; set; }
/// <summary>
/// Gets or sets the series id.
/// </summary>
/// <value>The series id.</value>
public string SeriesId { get; set; }
/// <summary>
/// Skips over a given number of items within the results. Use for paging.
/// </summary>
@ -28,20 +32,5 @@ namespace MediaBrowser.Model.Querying
/// </summary>
/// <value>The fields.</value>
public ItemFields[] Fields { get; set; }
/// <summary>
/// Gets or sets the exclude location types.
/// </summary>
/// <value>The exclude location types.</value>
public LocationType[] ExcludeLocationTypes { get; set; }
public bool? HasPremiereDate { get; set; }
public DateTime? MinPremiereDate { get; set; }
public DateTime? MaxPremiereDate { get; set; }
public NextUpQuery()
{
ExcludeLocationTypes = new LocationType[] { };
}
}
}

View File

@ -1,25 +1,24 @@
<Properties>
<MonoDevelop.Ide.Workspace ActiveConfiguration="Release|x86" />
<MonoDevelop.Ide.Workspace ActiveConfiguration="Debug|x86" />
<MonoDevelop.Ide.Workbench ActiveDocument="MediaBrowser.Server.Mono\Program.cs">
<Files>
<File FileName="MediaBrowser.Server.Mono\Program.cs" Line="60" Column="5" />
<File FileName="MediaBrowser.Server.Mono\Program.cs" Line="259" Column="4" />
<File FileName="MediaBrowser.ServerApplication\ApplicationHost.cs" Line="58" Column="12" />
<File FileName="MediaBrowser.Server.Mono\IO\FileSystemFactory.cs" Line="22" Column="1" />
</Files>
<Pads>
<Pad Id="ProjectPad">
<State expanded="True">
<Node name="MediaBrowser.Common.Implementations" expanded="True">
<Node name="HttpClientManager" expanded="True" />
</Node>
<Node name="MediaBrowser.Controller" expanded="True">
<Node name="Drawing" expanded="True" />
</Node>
<Node name="MediaBrowser.Common" expanded="True" />
<Node name="MediaBrowser.Common.Implementations" expanded="True" />
<Node name="MediaBrowser.Controller" expanded="True" />
<Node name="MediaBrowser.Model" expanded="True">
<Node name="References" expanded="True" />
<Node name="Web" expanded="True" />
</Node>
<Node name="MediaBrowser.Server.Implementations" expanded="True" />
<Node name="MediaBrowser.Server.Mono" expanded="True">
<Node name="FFMpeg" expanded="True" />
<Node name="IO" expanded="True" />
<Node name="Program.cs" selected="True" />
</Node>
</State>

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Providers;
@ -17,10 +18,12 @@ namespace MediaBrowser.Providers
public class FolderProviderFromXml : BaseMetadataProvider
{
public static FolderProviderFromXml Current;
private readonly IFileSystem _fileSystem;
public FolderProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager)
public FolderProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
_fileSystem = fileSystem;
Current = this;
}
@ -53,7 +56,7 @@ namespace MediaBrowser.Providers
return false;
}
return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed;
return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
}
/// <summary>

View File

@ -1,27 +1,30 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Savers;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Providers.Savers;
namespace MediaBrowser.Providers.Games
{
public class GameProviderFromXml : BaseMetadataProvider
{
private readonly IFileSystem _fileSystem;
/// <summary>
///
/// </summary>
/// <param name="logManager"></param>
/// <param name="configurationManager"></param>
public GameProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager)
public GameProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
_fileSystem = fileSystem;
}
/// <summary>
@ -45,7 +48,7 @@ namespace MediaBrowser.Providers.Games
return false;
}
return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed;
return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
}
/// <summary>
@ -78,7 +81,7 @@ namespace MediaBrowser.Providers.Games
try
{
new BaseItemXmlParser<Game>(Logger).Fetch(game, metaFile, cancellationToken);
new GameXmlParser(Logger).Fetch(game, metaFile, cancellationToken);
}
finally
{

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Providers;
@ -14,10 +15,12 @@ namespace MediaBrowser.Providers.Games
public class GameSystemProviderFromXml : BaseMetadataProvider
{
internal static GameSystemProviderFromXml Current { get; private set; }
private readonly IFileSystem _fileSystem;
public GameSystemProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager)
public GameSystemProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
_fileSystem = fileSystem;
Current = this;
}
@ -50,7 +53,7 @@ namespace MediaBrowser.Providers.Games
return false;
}
return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed;
return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
}
/// <summary>

View File

@ -0,0 +1,110 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
namespace MediaBrowser.Providers.Games
{
/// <summary>
/// Class EpisodeXmlParser
/// </summary>
public class GameXmlParser : BaseItemXmlParser<Game>
{
private Task _chaptersTask = null;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
public GameXmlParser(ILogger logger)
: base(logger)
{
}
public async Task FetchAsync(Game item, string metadataFile, CancellationToken cancellationToken)
{
_chaptersTask = null;
Fetch(item, metadataFile, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
if (_chaptersTask != null)
{
await _chaptersTask.ConfigureAwait(false);
}
}
/// <summary>
/// Fetches the data from XML node.
/// </summary>
/// <param name="reader">The reader.</param>
/// <param name="item">The item.</param>
protected override void FetchDataFromXmlNode(XmlReader reader, Game item)
{
switch (reader.Name)
{
case "GameSystem":
{
var val = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(val))
{
item.GameSystem = val;
}
break;
}
case "GamesDbId":
{
var val = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(val))
{
item.SetProviderId(MetadataProviders.Gamesdb, val);
}
break;
}
case "NesBox":
{
var val = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(val))
{
item.SetProviderId(MetadataProviders.NesBox, val);
}
break;
}
case "NesBoxRom":
{
var val = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(val))
{
item.SetProviderId(MetadataProviders.NesBoxRom, val);
}
break;
}
case "Players":
{
var val = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(val))
{
int num;
if (int.TryParse(val, NumberStyles.Integer, _usCulture, out num))
{
item.PlayersSupported = num;
}
}
break;
}
default:
base.FetchDataFromXmlNode(reader, item);
break;
}
}
}
}

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
@ -18,9 +19,12 @@ namespace MediaBrowser.Providers
/// </summary>
public class ImagesByNameProvider : ImageFromMediaLocationProvider
{
public ImagesByNameProvider(ILogManager logManager, IServerConfigurationManager configurationManager)
private readonly IFileSystem _fileSystem;
public ImagesByNameProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
_fileSystem = fileSystem;
}
public override ItemUpdateType ItemUpdateType
@ -110,8 +114,8 @@ namespace MediaBrowser.Providers
return files.Select(f =>
{
var lastWriteTime = FileSystem.GetLastWriteTimeUtc(f, Logger);
var creationTime = FileSystem.GetCreationTimeUtc(f, Logger);
var lastWriteTime = _fileSystem.GetLastWriteTimeUtc(f);
var creationTime = _fileSystem.GetCreationTimeUtc(f);
return creationTime > lastWriteTime ? creationTime : lastWriteTime;
@ -150,7 +154,7 @@ namespace MediaBrowser.Providers
/// <returns>System.String.</returns>
protected string GetLocation(BaseItem item)
{
var name = FileSystem.GetValidFilename(item.Name);
var name = _fileSystem.GetValidFilename(item.Name);
return Path.Combine(ConfigurationManager.ApplicationPaths.GeneralPath, name);
}

View File

@ -49,6 +49,7 @@
<ItemGroup>
<Compile Include="FanartBaseProvider.cs" />
<Compile Include="FolderProviderFromXml.cs" />
<Compile Include="Games\GameXmlParser.cs" />
<Compile Include="Games\GameProviderFromXml.cs" />
<Compile Include="Games\GameSystemProviderFromXml.cs" />
<Compile Include="ImageFromMediaLocationProvider.cs" />
@ -59,6 +60,7 @@
<Compile Include="MediaInfo\FFProbeVideoInfoProvider.cs" />
<Compile Include="MediaInfo\VideoImageProvider.cs" />
<Compile Include="Movies\BoxSetProviderFromXml.cs" />
<Compile Include="Movies\ManualMovieDbImageProvider.cs" />
<Compile Include="Movies\MovieUpdatesPrescanTask.cs" />
<Compile Include="Movies\MovieXmlParser.cs" />
<Compile Include="Movies\FanArtMovieProvider.cs" />

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.IO;
@ -18,10 +19,12 @@ namespace MediaBrowser.Providers.Movies
public class BoxSetProviderFromXml : BaseMetadataProvider
{
public static BoxSetProviderFromXml Current;
private readonly IFileSystem _fileSystem;
public BoxSetProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager)
public BoxSetProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
_fileSystem = fileSystem;
Current = this;
}
@ -54,7 +57,7 @@ namespace MediaBrowser.Providers.Movies
return false;
}
return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed;
return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
}
/// <summary>

View File

@ -4,6 +4,7 @@ using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
@ -40,6 +41,7 @@ namespace MediaBrowser.Providers.Movies
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
internal static FanArtMovieProvider Current { get; private set; }
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="FanArtMovieProvider" /> class.
@ -49,7 +51,7 @@ namespace MediaBrowser.Providers.Movies
/// <param name="configurationManager">The configuration manager.</param>
/// <param name="providerManager">The provider manager.</param>
/// <exception cref="System.ArgumentNullException">httpClient</exception>
public FanArtMovieProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
public FanArtMovieProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
if (httpClient == null)
@ -58,6 +60,7 @@ namespace MediaBrowser.Providers.Movies
}
HttpClient = httpClient;
_providerManager = providerManager;
_fileSystem = fileSystem;
Current = this;
}
@ -174,7 +177,7 @@ namespace MediaBrowser.Providers.Movies
{
var files = new DirectoryInfo(path)
.EnumerateFiles("*.xml", SearchOption.TopDirectoryOnly)
.Select(i => i.LastWriteTimeUtc)
.Select(i => _fileSystem.GetLastWriteTimeUtc(i))
.ToList();
if (files.Count > 0)
@ -275,7 +278,7 @@ namespace MediaBrowser.Providers.Movies
}).ConfigureAwait(false))
{
using (var xmlFileStream = new FileStream(xmlPath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
using (var xmlFileStream = _fileSystem.GetFileStream(xmlPath, FileMode.Create, FileAccess.Write, FileShare.Read, true))
{
await response.CopyToAsync(xmlFileStream).ConfigureAwait(false);
}
@ -300,14 +303,14 @@ namespace MediaBrowser.Providers.Movies
string path;
if (ConfigurationManager.Configuration.DownloadMovieImages.Disc && !item.HasImage(ImageType.Disc))
if (ConfigurationManager.Configuration.DownloadMovieImages.Primary && !item.HasImage(ImageType.Primary))
{
var node = doc.SelectSingleNode("//fanart/movie/movieposters/movieposter[@lang = \"" + language + "\"]/@url") ??
doc.SelectSingleNode("//fanart/movie/movieposters/movieposter/@url");
path = node != null ? node.Value : null;
if (!string.IsNullOrEmpty(path))
{
await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Disc, null, cancellationToken)
await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Primary, null, cancellationToken)
.ConfigureAwait(false);
}
}

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Logging;
@ -32,15 +33,17 @@ namespace MediaBrowser.Providers.Movies
/// </summary>
private readonly IServerConfigurationManager _config;
private readonly IJsonSerializer _jsonSerializer;
private readonly IFileSystem _fileSystem;
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
public FanArtMovieUpdatesPrescanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient)
public FanArtMovieUpdatesPrescanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient, IFileSystem fileSystem)
{
_jsonSerializer = jsonSerializer;
_config = config;
_logger = logger;
_httpClient = httpClient;
_fileSystem = fileSystem;
}
/// <summary>
@ -66,7 +69,7 @@ namespace MediaBrowser.Providers.Movies
var timestampFileInfo = new FileInfo(timestampFile);
// Don't check for tvdb updates anymore frequently than 24 hours
if (timestampFileInfo.Exists && (DateTime.UtcNow - timestampFileInfo.LastWriteTimeUtc).TotalDays < 1)
if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 1)
{
return;
}

View File

@ -0,0 +1,168 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Serialization;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Providers.Movies
{
class ManualMovieDbImageProvider : IImageProvider
{
private readonly IJsonSerializer _jsonSerializer;
private readonly IServerConfigurationManager _config;
public ManualMovieDbImageProvider(IJsonSerializer jsonSerializer, IServerConfigurationManager config)
{
_jsonSerializer = jsonSerializer;
_config = config;
}
public string Name
{
get { return "TheMovieDB"; }
}
public bool Supports(BaseItem item, ImageType imageType)
{
if (MovieDbImagesProvider.SupportsItem(item))
{
return imageType == ImageType.Primary || imageType == ImageType.Backdrop;
}
return false;
}
public async Task<IEnumerable<RemoteImageInfo>> GetAvailableImages(BaseItem item, ImageType imageType, CancellationToken cancellationToken)
{
var images = await GetAllImages(item, cancellationToken).ConfigureAwait(false);
return images.Where(i => i.Type == imageType);
}
public async Task<IEnumerable<RemoteImageInfo>> GetAllImages(BaseItem item, CancellationToken cancellationToken)
{
var list = new List<RemoteImageInfo>();
var results = FetchImages(item, _jsonSerializer);
if (results == null)
{
return list;
}
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
var tmdbImageUrl = tmdbSettings.images.base_url + "original";
list.AddRange(GetPosters(results, item).Select(i => new RemoteImageInfo
{
Url = tmdbImageUrl + i.file_path,
CommunityRating = i.vote_average,
VoteCount = i.vote_count,
Width = i.width,
Height = i.height,
Language = i.iso_639_1,
ProviderName = Name,
Type = ImageType.Primary
}));
list.AddRange(GetBackdrops(results, item).Select(i => new RemoteImageInfo
{
Url = tmdbImageUrl + i.file_path,
CommunityRating = i.vote_average,
VoteCount = i.vote_count,
Width = i.width,
Height = i.height,
ProviderName = Name,
Type = ImageType.Backdrop
}));
return list;
}
/// <summary>
/// Gets the posters.
/// </summary>
/// <param name="images">The images.</param>
/// <param name="item">The item.</param>
/// <returns>IEnumerable{MovieDbProvider.Poster}.</returns>
private IEnumerable<MovieDbProvider.Poster> GetPosters(MovieDbProvider.Images images, BaseItem item)
{
var language = _config.Configuration.PreferredMetadataLanguage;
var isLanguageEn = string.Equals(language, "en", StringComparison.OrdinalIgnoreCase);
var eligiblePosters = images.posters == null ?
new List<MovieDbProvider.Poster>() :
images.posters.Where(i => i.width >= _config.Configuration.MinMoviePosterWidth)
.ToList();
return eligiblePosters.OrderByDescending(i =>
{
if (string.Equals(language, i.iso_639_1, StringComparison.OrdinalIgnoreCase))
{
return 3;
}
if (!isLanguageEn)
{
if (string.Equals("en", i.iso_639_1, StringComparison.OrdinalIgnoreCase))
{
return 2;
}
}
if (string.IsNullOrEmpty(i.iso_639_1))
{
return isLanguageEn ? 3 : 2;
}
return 0;
})
.ThenByDescending(i => i.vote_average)
.ToList();
}
/// <summary>
/// Gets the backdrops.
/// </summary>
/// <param name="images">The images.</param>
/// <param name="item">The item.</param>
/// <returns>IEnumerable{MovieDbProvider.Backdrop}.</returns>
private IEnumerable<MovieDbProvider.Backdrop> GetBackdrops(MovieDbProvider.Images images, BaseItem item)
{
var eligibleBackdrops = images.backdrops == null ? new List<MovieDbProvider.Backdrop>() :
images.backdrops.Where(i => i.width >= _config.Configuration.MinMovieBackdropWidth)
.ToList();
return eligibleBackdrops.OrderByDescending(i => i.vote_average);
}
/// <summary>
/// Fetches the images.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="jsonSerializer">The json serializer.</param>
/// <returns>Task{MovieImages}.</returns>
private MovieDbProvider.Images FetchImages(BaseItem item, IJsonSerializer jsonSerializer)
{
var path = MovieDbProvider.Current.GetDataFilePath(item, "default");
if (!string.IsNullOrEmpty(path))
{
var fileInfo = new FileInfo(path);
if (fileInfo.Exists)
{
return jsonSerializer.DeserializeFromFile<MovieDbProvider.CompleteMovieData>(path).images;
}
}
return null;
}
}
}

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
@ -6,6 +7,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Serialization;
using System;
using System.Collections.Generic;
@ -21,11 +23,6 @@ namespace MediaBrowser.Providers.Movies
/// </summary>
public class MovieDbImagesProvider : BaseMetadataProvider
{
/// <summary>
/// The get images
/// </summary>
private const string GetImages = @"http://api.themoviedb.org/3/{2}/{0}/images?api_key={1}";
/// <summary>
/// The _provider manager
/// </summary>
@ -35,6 +32,7 @@ namespace MediaBrowser.Providers.Movies
/// The _json serializer
/// </summary>
private readonly IJsonSerializer _jsonSerializer;
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="MovieDbImagesProvider"/> class.
@ -43,11 +41,12 @@ namespace MediaBrowser.Providers.Movies
/// <param name="configurationManager">The configuration manager.</param>
/// <param name="providerManager">The provider manager.</param>
/// <param name="jsonSerializer">The json serializer.</param>
public MovieDbImagesProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IJsonSerializer jsonSerializer)
public MovieDbImagesProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IJsonSerializer jsonSerializer, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
_providerManager = providerManager;
_jsonSerializer = jsonSerializer;
_fileSystem = fileSystem;
}
/// <summary>
@ -65,6 +64,11 @@ namespace MediaBrowser.Providers.Movies
/// <param name="item">The item.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
public override bool Supports(BaseItem item)
{
return SupportsItem(item);
}
public static bool SupportsItem(BaseItem item)
{
var trailer = item as Trailer;
@ -149,7 +153,7 @@ namespace MediaBrowser.Providers.Movies
{
return false;
}
var path = MovieDbProvider.Current.GetDataFilePath(item, "default");
if (!string.IsNullOrEmpty(path))
@ -158,7 +162,7 @@ namespace MediaBrowser.Providers.Movies
if (fileInfo.Exists)
{
return fileInfo.LastWriteTimeUtc > providerInfo.LastRefreshed;
return _fileSystem.GetLastWriteTimeUtc(fileInfo) > providerInfo.LastRefreshed;
}
}
@ -176,44 +180,18 @@ namespace MediaBrowser.Providers.Movies
{
var id = item.GetProviderId(MetadataProviders.Tmdb);
var status = ProviderRefreshStatus.Success;
if (!string.IsNullOrEmpty(id))
{
var images = FetchImages(item);
var images = await new ManualMovieDbImageProvider(_jsonSerializer, ConfigurationManager).GetAllImages(item,
cancellationToken).ConfigureAwait(false);
if (images != null)
{
status = await ProcessImages(item, images, cancellationToken).ConfigureAwait(false);
}
await ProcessImages(item, images.ToList(), cancellationToken).ConfigureAwait(false);
}
SetLastRefreshed(item, DateTime.UtcNow, status);
SetLastRefreshed(item, DateTime.UtcNow);
return true;
}
/// <summary>
/// Fetches the images.
/// </summary>
/// <param name="item">The item.</param>
/// <returns>Task{MovieImages}.</returns>
private MovieDbProvider.Images FetchImages(BaseItem item)
{
var path = MovieDbProvider.Current.GetDataFilePath(item, "default");
if (!string.IsNullOrEmpty(path))
{
var fileInfo = new FileInfo(path);
if (fileInfo.Exists)
{
return _jsonSerializer.DeserializeFromFile<MovieDbProvider.CompleteMovieData>(path).images;
}
}
return null;
}
/// <summary>
/// Processes the images.
/// </summary>
@ -221,68 +199,36 @@ namespace MediaBrowser.Providers.Movies
/// <param name="images">The images.</param>
/// <param name="cancellationToken">The cancellation token</param>
/// <returns>Task.</returns>
private async Task<ProviderRefreshStatus> ProcessImages(BaseItem item, MovieDbProvider.Images images, CancellationToken cancellationToken)
private async Task ProcessImages(BaseItem item, List<RemoteImageInfo> images, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var status = ProviderRefreshStatus.Success;
var eligiblePosters = images.posters == null ?
new List<MovieDbProvider.Poster>() :
images.posters.Where(i => i.width >= ConfigurationManager.Configuration.MinMoviePosterWidth)
var eligiblePosters = images
.Where(i => i.Type == ImageType.Primary)
.ToList();
eligiblePosters = eligiblePosters.OrderByDescending(i => i.vote_average).ToList();
// poster
if (eligiblePosters.Count > 0 && !item.HasImage(ImageType.Primary))
{
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
var poster = eligiblePosters[0];
var tmdbImageUrl = tmdbSettings.images.base_url + "original";
// get highest rated poster for our language
var url = poster.Url;
var poster = eligiblePosters.FirstOrDefault(p => string.Equals(p.iso_639_1, ConfigurationManager.Configuration.PreferredMetadataLanguage, StringComparison.OrdinalIgnoreCase));
if (poster == null)
var img = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions
{
// couldn't find our specific language, find english
poster = eligiblePosters.FirstOrDefault(p => string.Equals(p.iso_639_1, "en", StringComparison.OrdinalIgnoreCase));
}
Url = url,
CancellationToken = cancellationToken
if (poster == null)
{
//still couldn't find it - try highest rated null one
poster = eligiblePosters.FirstOrDefault(p => p.iso_639_1 == null);
}
}).ConfigureAwait(false);
if (poster == null)
{
//finally - just get the highest rated one
poster = eligiblePosters.FirstOrDefault();
}
if (poster != null)
{
var url = tmdbImageUrl + poster.file_path;
var img = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions
{
Url = url,
CancellationToken = cancellationToken
}).ConfigureAwait(false);
await _providerManager.SaveImage(item, img, MimeTypes.GetMimeType(poster.file_path), ImageType.Primary, null, url, cancellationToken)
.ConfigureAwait(false);
}
await _providerManager.SaveImage(item, img, MimeTypes.GetMimeType(url), ImageType.Primary, null, url, cancellationToken)
.ConfigureAwait(false);
}
cancellationToken.ThrowIfCancellationRequested();
var eligibleBackdrops = images.backdrops == null ? new List<MovieDbProvider.Backdrop>() :
images.backdrops.Where(i => i.width >= ConfigurationManager.Configuration.MinMovieBackdropWidth)
var eligibleBackdrops = images
.Where(i => i.Type == ImageType.Backdrop)
.ToList();
var backdropLimit = ConfigurationManager.Configuration.MaxBackdrops;
@ -290,13 +236,9 @@ namespace MediaBrowser.Providers.Movies
// backdrops - only download if earlier providers didn't find any (fanart)
if (eligibleBackdrops.Count > 0 && ConfigurationManager.Configuration.DownloadMovieImages.Backdrops && item.BackdropImagePaths.Count < backdropLimit)
{
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
var tmdbImageUrl = tmdbSettings.images.base_url + "original";
for (var i = 0; i < eligibleBackdrops.Count; i++)
{
var url = tmdbImageUrl + eligibleBackdrops[i].file_path;
var url = eligibleBackdrops[i].Url;
if (!item.ContainsImageWithSourceUrl(url))
{
@ -307,7 +249,7 @@ namespace MediaBrowser.Providers.Movies
}).ConfigureAwait(false);
await _providerManager.SaveImage(item, img, MimeTypes.GetMimeType(eligibleBackdrops[i].file_path), ImageType.Backdrop, item.BackdropImagePaths.Count, url, cancellationToken)
await _providerManager.SaveImage(item, img, MimeTypes.GetMimeType(url), ImageType.Backdrop, item.BackdropImagePaths.Count, url, cancellationToken)
.ConfigureAwait(false);
}
@ -317,8 +259,6 @@ namespace MediaBrowser.Providers.Movies
}
}
}
return status;
}
}
}

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
@ -47,6 +48,7 @@ namespace MediaBrowser.Providers.Movies
/// </summary>
/// <value>The HTTP client.</value>
protected IHttpClient HttpClient { get; private set; }
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="MovieDbProvider" /> class.
@ -56,12 +58,13 @@ namespace MediaBrowser.Providers.Movies
/// <param name="jsonSerializer">The json serializer.</param>
/// <param name="httpClient">The HTTP client.</param>
/// <param name="providerManager">The provider manager.</param>
public MovieDbProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IHttpClient httpClient, IProviderManager providerManager)
public MovieDbProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IHttpClient httpClient, IProviderManager providerManager, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
JsonSerializer = jsonSerializer;
HttpClient = httpClient;
ProviderManager = providerManager;
_fileSystem = fileSystem;
Current = this;
}
@ -189,6 +192,7 @@ namespace MediaBrowser.Providers.Movies
static readonly Regex[] NameMatches = new[] {
new Regex(@"(?<name>.*)\((?<year>\d{4})\)"), // matches "My Movie (2001)" and gives us the name and the year
new Regex(@"(?<name>.*)(\.(?<year>\d{4})(\.|$)).*$"),
new Regex(@"(?<name>.*)") // last resort matches the whole string as the name
};
@ -215,7 +219,7 @@ namespace MediaBrowser.Providers.Movies
if (fileInfo.Exists)
{
return fileInfo.LastWriteTimeUtc > providerInfo.LastRefreshed;
return _fileSystem.GetLastWriteTimeUtc(fileInfo) > providerInfo.LastRefreshed;
}
return true;
@ -320,7 +324,7 @@ namespace MediaBrowser.Providers.Movies
/// <param name="name">The name.</param>
/// <param name="justName">Name of the just.</param>
/// <param name="year">The year.</param>
protected void ParseName(string name, out string justName, out int? year)
public static void ParseName(string name, out string justName, out int? year)
{
justName = null;
year = null;

View File

@ -1,7 +1,7 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
@ -21,11 +21,13 @@ namespace MediaBrowser.Providers.Movies
{
internal static MovieProviderFromXml Current { get; private set; }
private readonly IItemRepository _itemRepo;
private readonly IFileSystem _fileSystem;
public MovieProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IItemRepository itemRepo)
public MovieProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IItemRepository itemRepo, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
_itemRepo = itemRepo;
_fileSystem = fileSystem;
Current = this;
}
@ -71,7 +73,7 @@ namespace MediaBrowser.Providers.Movies
return false;
}
return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed;
return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
}
/// <summary>

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Progress;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
@ -35,6 +36,7 @@ namespace MediaBrowser.Providers.Movies
/// </summary>
private readonly IServerConfigurationManager _config;
private readonly IJsonSerializer _json;
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="MovieUpdatesPreScanTask"/> class.
@ -43,12 +45,13 @@ namespace MediaBrowser.Providers.Movies
/// <param name="httpClient">The HTTP client.</param>
/// <param name="config">The config.</param>
/// <param name="json">The json.</param>
public MovieUpdatesPreScanTask(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config, IJsonSerializer json)
public MovieUpdatesPreScanTask(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config, IJsonSerializer json, IFileSystem fileSystem)
{
_logger = logger;
_httpClient = httpClient;
_config = config;
_json = json;
_fileSystem = fileSystem;
}
protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
@ -100,7 +103,7 @@ namespace MediaBrowser.Providers.Movies
var refreshDays = _config.Configuration.EnableTmdbUpdates ? 1 : 7;
// Don't check for tvdb updates anymore frequently than 24 hours
if (timestampFileInfo.Exists && (DateTime.UtcNow - timestampFileInfo.LastWriteTimeUtc).TotalDays < refreshDays)
if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < refreshDays)
{
return;
}

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Providers;
@ -13,10 +14,12 @@ namespace MediaBrowser.Providers.Movies
class PersonProviderFromXml : BaseMetadataProvider
{
internal static PersonProviderFromXml Current { get; private set; }
private readonly IFileSystem _fileSystem;
public PersonProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager)
public PersonProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
_fileSystem = fileSystem;
Current = this;
}
@ -49,7 +52,7 @@ namespace MediaBrowser.Providers.Movies
return false;
}
return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed;
return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
}
/// <summary>

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Logging;
@ -34,6 +35,7 @@ namespace MediaBrowser.Providers.Movies
/// </summary>
private readonly IServerConfigurationManager _config;
private readonly IJsonSerializer _json;
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="PersonUpdatesPreScanTask"/> class.
@ -41,12 +43,13 @@ namespace MediaBrowser.Providers.Movies
/// <param name="logger">The logger.</param>
/// <param name="httpClient">The HTTP client.</param>
/// <param name="config">The config.</param>
public PersonUpdatesPreScanTask(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config, IJsonSerializer json)
public PersonUpdatesPreScanTask(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config, IJsonSerializer json, IFileSystem fileSystem)
{
_logger = logger;
_httpClient = httpClient;
_config = config;
_json = json;
_fileSystem = fileSystem;
}
protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
@ -74,7 +77,7 @@ namespace MediaBrowser.Providers.Movies
var timestampFileInfo = new FileInfo(timestampFile);
// Don't check for tvdb updates anymore frequently than 24 hours
if (timestampFileInfo.Exists && (DateTime.UtcNow - timestampFileInfo.LastWriteTimeUtc).TotalDays < 1)
if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 1)
{
return;
}

View File

@ -30,8 +30,9 @@ namespace MediaBrowser.Providers.Movies
internal static TmdbPersonProvider Current { get; private set; }
const string DataFileName = "info.json";
private readonly IFileSystem _fileSystem;
public TmdbPersonProvider(IJsonSerializer jsonSerializer, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
public TmdbPersonProvider(IJsonSerializer jsonSerializer, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
if (jsonSerializer == null)
@ -40,6 +41,7 @@ namespace MediaBrowser.Providers.Movies
}
JsonSerializer = jsonSerializer;
ProviderManager = providerManager;
_fileSystem = fileSystem;
Current = this;
}
@ -105,7 +107,7 @@ namespace MediaBrowser.Providers.Movies
if (fileInfo.Exists)
{
return fileInfo.LastWriteTimeUtc > providerInfo.LastRefreshed;
return _fileSystem.GetLastWriteTimeUtc(fileInfo) > providerInfo.LastRefreshed;
}
return true;
@ -270,7 +272,7 @@ namespace MediaBrowser.Providers.Movies
{
Directory.CreateDirectory(personDataPath);
using (var fs = new FileStream(Path.Combine(personDataPath, DataFileName), FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true))
using (var fs = _fileSystem.GetFileStream(Path.Combine(personDataPath, DataFileName), FileMode.Create, FileAccess.Write, FileShare.Read, true))
{
await json.CopyToAsync(fs).ConfigureAwait(false);
}

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.IO;
@ -15,10 +16,12 @@ namespace MediaBrowser.Providers.Music
class ArtistProviderFromXml : BaseMetadataProvider
{
public static ArtistProviderFromXml Current;
private readonly IFileSystem _fileSystem;
public ArtistProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager)
public ArtistProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
_fileSystem = fileSystem;
Current = this;
}
@ -51,7 +54,7 @@ namespace MediaBrowser.Providers.Music
return false;
}
return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed;
return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
}
/// <summary>

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
@ -37,6 +38,7 @@ namespace MediaBrowser.Providers.Music
protected IHttpClient HttpClient { get; private set; }
internal static FanArtAlbumProvider Current { get; private set; }
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="FanArtAlbumProvider"/> class.
@ -45,10 +47,11 @@ namespace MediaBrowser.Providers.Music
/// <param name="logManager">The log manager.</param>
/// <param name="configurationManager">The configuration manager.</param>
/// <param name="providerManager">The provider manager.</param>
public FanArtAlbumProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
public FanArtAlbumProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
_providerManager = providerManager;
_fileSystem = fileSystem;
HttpClient = httpClient;
Current = this;
@ -140,7 +143,7 @@ namespace MediaBrowser.Providers.Music
if (file.Exists)
{
return file.LastWriteTimeUtc;
return _fileSystem.GetLastWriteTimeUtc(file);
}
}

View File

@ -1,7 +1,9 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Logging;
@ -15,12 +17,8 @@ namespace MediaBrowser.Providers.Music
/// <summary>
/// Initializes a new instance of the <see cref="FanArtArtistByNameProvider" /> class.
/// </summary>
/// <param name="httpClient">The HTTP client.</param>
/// <param name="logManager">The log manager.</param>
/// <param name="configurationManager">The configuration manager.</param>
/// <param name="providerManager">The provider manager.</param>
public FanArtArtistByNameProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
: base(httpClient, logManager, configurationManager, providerManager)
public FanArtArtistByNameProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
: base(httpClient, logManager, configurationManager, providerManager, fileSystem)
{
}

View File

@ -1,24 +1,23 @@
using System.Net;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using MediaBrowser.Model.Net;
namespace MediaBrowser.Providers.Music
{
@ -39,6 +38,7 @@ namespace MediaBrowser.Providers.Music
private readonly IProviderManager _providerManager;
internal static FanArtArtistProvider Current;
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="FanArtArtistProvider"/> class.
@ -48,7 +48,7 @@ namespace MediaBrowser.Providers.Music
/// <param name="configurationManager">The configuration manager.</param>
/// <param name="providerManager">The provider manager.</param>
/// <exception cref="System.ArgumentNullException">httpClient</exception>
public FanArtArtistProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
public FanArtArtistProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
if (httpClient == null)
@ -57,6 +57,7 @@ namespace MediaBrowser.Providers.Music
}
HttpClient = httpClient;
_providerManager = providerManager;
_fileSystem = fileSystem;
Current = this;
}
@ -167,7 +168,7 @@ namespace MediaBrowser.Providers.Music
{
var files = new DirectoryInfo(path)
.EnumerateFiles("*.xml", SearchOption.TopDirectoryOnly)
.Select(i => i.LastWriteTimeUtc)
.Select(i => _fileSystem.GetLastWriteTimeUtc(i))
.ToList();
if (files.Count > 0)
@ -284,7 +285,7 @@ namespace MediaBrowser.Providers.Music
}).ConfigureAwait(false))
{
using (var xmlFileStream = new FileStream(xmlPath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
using (var xmlFileStream = _fileSystem.GetFileStream(xmlPath, FileMode.Create, FileAccess.Write, FileShare.Read, true))
{
await response.CopyToAsync(xmlFileStream).ConfigureAwait(false);
}

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Logging;
@ -31,15 +32,17 @@ namespace MediaBrowser.Providers.Music
/// </summary>
private readonly IServerConfigurationManager _config;
private readonly IJsonSerializer _jsonSerializer;
private readonly IFileSystem _fileSystem;
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
public FanArtUpdatesPrescanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient)
public FanArtUpdatesPrescanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient, IFileSystem fileSystem)
{
_jsonSerializer = jsonSerializer;
_config = config;
_logger = logger;
_httpClient = httpClient;
_fileSystem = fileSystem;
}
/// <summary>
@ -65,7 +68,7 @@ namespace MediaBrowser.Providers.Music
var timestampFileInfo = new FileInfo(timestampFile);
// Don't check for tvdb updates anymore frequently than 24 hours
if (timestampFileInfo.Exists && (DateTime.UtcNow - timestampFileInfo.LastWriteTimeUtc).TotalDays < 1)
if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 1)
{
return;
}

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.IO;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Logging;
using System;
@ -22,15 +23,18 @@ namespace MediaBrowser.Providers
/// </summary>
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="RefreshIntrosTask"/> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
public RefreshIntrosTask(ILibraryManager libraryManager, ILogger logger)
public RefreshIntrosTask(ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem)
{
_libraryManager = libraryManager;
_logger = logger;
_fileSystem = fileSystem;
}
/// <summary>
@ -77,7 +81,7 @@ namespace MediaBrowser.Providers
/// <returns>Task.</returns>
private async Task RefreshIntro(string path, CancellationToken cancellationToken)
{
var item = _libraryManager.ResolvePath(FileSystem.GetFileSystemInfo(path));
var item = _libraryManager.ResolvePath(_fileSystem.GetFileSystemInfo(path));
if (item == null)
{

View File

@ -1,6 +1,7 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities;
using MediaBrowser.Providers.Movies;
using System;
using System.Collections.Generic;
@ -70,6 +71,20 @@ namespace MediaBrowser.Providers.Savers
builder.Append("<GameSystem>" + SecurityElement.Escape(game.GameSystem) + "</GameSystem>");
}
var val = game.GetProviderId(MetadataProviders.NesBox);
if (!string.IsNullOrEmpty(val))
{
builder.Append("<NesBox>" + SecurityElement.Escape(val) + "</NesBox>");
}
val = game.GetProviderId(MetadataProviders.NesBoxRom);
if (!string.IsNullOrEmpty(val))
{
builder.Append("<NesBoxRom>" + SecurityElement.Escape(val) + "</NesBoxRom>");
}
XmlSaverHelpers.AddCommonNodes(item, builder);
builder.Append("</Item>");
@ -79,7 +94,9 @@ namespace MediaBrowser.Providers.Savers
XmlSaverHelpers.Save(builder, xmlFilePath, new List<string>
{
"Players",
"GameSystem"
"GameSystem",
"NesBox",
"NesBoxRom"
});
// Set last refreshed so that the provider doesn't trigger after the file save

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.IO;
@ -20,11 +21,13 @@ namespace MediaBrowser.Providers.TV
{
internal static EpisodeProviderFromXml Current { get; private set; }
private readonly IItemRepository _itemRepo;
private readonly IFileSystem _fileSystem;
public EpisodeProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IItemRepository itemRepo)
public EpisodeProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IItemRepository itemRepo, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
_itemRepo = itemRepo;
_fileSystem = fileSystem;
Current = this;
}
@ -76,7 +79,7 @@ namespace MediaBrowser.Providers.TV
return false;
}
return FileSystem.GetLastWriteTimeUtc(file, Logger) > providerInfo.LastRefreshed;
return _fileSystem.GetLastWriteTimeUtc(file) > providerInfo.LastRefreshed;
}
/// <summary>

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
@ -22,6 +23,7 @@ namespace MediaBrowser.Providers.TV
/// The _provider manager
/// </summary>
private readonly IProviderManager _providerManager;
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="FanArtSeasonProvider"/> class.
@ -29,10 +31,11 @@ namespace MediaBrowser.Providers.TV
/// <param name="logManager">The log manager.</param>
/// <param name="configurationManager">The configuration manager.</param>
/// <param name="providerManager">The provider manager.</param>
public FanArtSeasonProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
public FanArtSeasonProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
_providerManager = providerManager;
_fileSystem = fileSystem;
}
public override ItemUpdateType ItemUpdateType
@ -76,7 +79,7 @@ namespace MediaBrowser.Providers.TV
if (imagesFileInfo.Exists)
{
return imagesFileInfo.LastWriteTimeUtc;
return _fileSystem.GetLastWriteTimeUtc(imagesFileInfo);
}
}

View File

@ -4,6 +4,7 @@ using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
@ -31,8 +32,9 @@ namespace MediaBrowser.Providers.TV
protected IHttpClient HttpClient { get; private set; }
private readonly IProviderManager _providerManager;
private readonly IFileSystem _fileSystem;
public FanArtTvProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
public FanArtTvProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
if (httpClient == null)
@ -41,6 +43,7 @@ namespace MediaBrowser.Providers.TV
}
HttpClient = httpClient;
_providerManager = providerManager;
_fileSystem = fileSystem;
Current = this;
}
@ -115,7 +118,7 @@ namespace MediaBrowser.Providers.TV
{
var files = new DirectoryInfo(path)
.EnumerateFiles("*.xml", SearchOption.TopDirectoryOnly)
.Select(i => i.LastWriteTimeUtc)
.Select(i => _fileSystem.GetLastWriteTimeUtc(i))
.ToList();
if (files.Count > 0)
@ -353,7 +356,7 @@ namespace MediaBrowser.Providers.TV
}).ConfigureAwait(false))
{
using (var xmlFileStream = new FileStream(xmlPath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
using (var xmlFileStream = _fileSystem.GetFileStream(xmlPath, FileMode.Create, FileAccess.Write, FileShare.Read, true))
{
await response.CopyToAsync(xmlFileStream).ConfigureAwait(false);
}

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Logging;
@ -32,15 +33,17 @@ namespace MediaBrowser.Providers.TV
/// </summary>
private readonly IServerConfigurationManager _config;
private readonly IJsonSerializer _jsonSerializer;
private readonly IFileSystem _fileSystem;
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
public FanArtTvUpdatesPrescanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient)
public FanArtTvUpdatesPrescanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient, IFileSystem fileSystem)
{
_jsonSerializer = jsonSerializer;
_config = config;
_logger = logger;
_httpClient = httpClient;
_fileSystem = fileSystem;
}
/// <summary>
@ -66,7 +69,7 @@ namespace MediaBrowser.Providers.TV
var timestampFileInfo = new FileInfo(timestampFile);
// Don't check for tvdb updates anymore frequently than 24 hours
if (timestampFileInfo.Exists && (DateTime.UtcNow - timestampFileInfo.LastWriteTimeUtc).TotalDays < 1)
if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 1)
{
return;
}

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
@ -36,6 +37,7 @@ namespace MediaBrowser.Providers.TV
/// </summary>
/// <value>The HTTP client.</value>
protected IHttpClient HttpClient { get; private set; }
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="RemoteEpisodeProvider" /> class.
@ -44,11 +46,12 @@ namespace MediaBrowser.Providers.TV
/// <param name="logManager">The log manager.</param>
/// <param name="configurationManager">The configuration manager.</param>
/// <param name="providerManager">The provider manager.</param>
public RemoteEpisodeProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
public RemoteEpisodeProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
HttpClient = httpClient;
_providerManager = providerManager;
_fileSystem = fileSystem;
}
/// <summary>
@ -149,7 +152,7 @@ namespace MediaBrowser.Providers.TV
if (files.Count > 0)
{
return files.Select(i => i.LastWriteTimeUtc).Max() > providerInfo.LastRefreshed;
return files.Select(i => _fileSystem.GetLastWriteTimeUtc(i)).Max() > providerInfo.LastRefreshed;
}
}
@ -240,17 +243,16 @@ namespace MediaBrowser.Providers.TV
{
cancellationToken.ThrowIfCancellationRequested();
var status = ProviderRefreshStatus.Success;
var episode = (Episode)item;
var seriesId = episode.Series != null ? episode.Series.GetProviderId(MetadataProviders.Tvdb) : null;
if (!string.IsNullOrEmpty(seriesId))
{
var seriesDataPath = RemoteSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths,
seriesId);
var seriesDataPath = RemoteSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId);
var status = ProviderRefreshStatus.Success;
try
{
status = await FetchEpisodeData(episode, seriesDataPath, cancellationToken).ConfigureAwait(false);
@ -259,20 +261,10 @@ namespace MediaBrowser.Providers.TV
{
// Don't fail the provider because this will just keep on going and going.
}
BaseProviderInfo data;
if (!item.ProviderData.TryGetValue(Id, out data))
{
data = new BaseProviderInfo();
item.ProviderData[Id] = data;
}
SetLastRefreshed(item, DateTime.UtcNow, status);
return true;
}
Logger.Info("Episode provider not fetching because series does not have a tvdb id: " + item.Path);
return false;
SetLastRefreshed(item, DateTime.UtcNow, status);
return true;
}

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
@ -23,6 +24,7 @@ namespace MediaBrowser.Providers.TV
/// The _provider manager
/// </summary>
private readonly IProviderManager _providerManager;
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="RemoteSeasonProvider"/> class.
@ -31,10 +33,11 @@ namespace MediaBrowser.Providers.TV
/// <param name="configurationManager">The configuration manager.</param>
/// <param name="providerManager">The provider manager.</param>
/// <exception cref="System.ArgumentNullException">httpClient</exception>
public RemoteSeasonProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
public RemoteSeasonProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
_providerManager = providerManager;
_fileSystem = fileSystem;
}
/// <summary>
@ -115,7 +118,7 @@ namespace MediaBrowser.Providers.TV
if (imagesFileInfo.Exists)
{
return imagesFileInfo.LastWriteTimeUtc > providerInfo.LastRefreshed;
return _fileSystem.GetLastWriteTimeUtc(imagesFileInfo) > providerInfo.LastRefreshed;
}
}
return false;
@ -275,6 +278,7 @@ namespace MediaBrowser.Providers.TV
string url = null;
int? bannerSeason = null;
string resolution = null;
string language = null;
while (reader.Read())
{
@ -282,6 +286,12 @@ namespace MediaBrowser.Providers.TV
{
switch (reader.Name)
{
case "Language":
{
language = reader.ReadElementContentAsString() ?? string.Empty;
break;
}
case "BannerType":
{
bannerType = reader.ReadElementContentAsString() ?? string.Empty;
@ -325,11 +335,30 @@ namespace MediaBrowser.Providers.TV
{
if (string.Equals(bannerType2, "season", StringComparison.OrdinalIgnoreCase))
{
data.Poster = url;
// Just grab the first
if (string.IsNullOrWhiteSpace(data.Poster))
{
data.Poster = url;
}
}
else if (string.Equals(bannerType2, "seasonwide", StringComparison.OrdinalIgnoreCase))
{
data.Banner = url;
if (string.IsNullOrWhiteSpace(language) || string.Equals(language, "en", StringComparison.OrdinalIgnoreCase))
{
// Just grab the first
if (string.IsNullOrWhiteSpace(data.Banner))
{
data.Banner = url;
}
}
else if (string.Equals(language, ConfigurationManager.Configuration.PreferredMetadataLanguage, StringComparison.OrdinalIgnoreCase))
{
// Just grab the first
if (string.IsNullOrWhiteSpace(data.LanguageBanner))
{
data.LanguageBanner = url;
}
}
}
}
else if (string.Equals(bannerType, "fanart", StringComparison.OrdinalIgnoreCase))

View File

@ -4,6 +4,7 @@ using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
@ -49,6 +50,8 @@ namespace MediaBrowser.Providers.TV
/// <value>The HTTP client.</value>
protected IHttpClient HttpClient { get; private set; }
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="RemoteSeriesProvider" /> class.
/// </summary>
@ -57,7 +60,7 @@ namespace MediaBrowser.Providers.TV
/// <param name="configurationManager">The configuration manager.</param>
/// <param name="zipClient">The zip client.</param>
/// <exception cref="System.ArgumentNullException">httpClient</exception>
public RemoteSeriesProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IZipClient zipClient)
public RemoteSeriesProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IZipClient zipClient, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
if (httpClient == null)
@ -66,6 +69,7 @@ namespace MediaBrowser.Providers.TV
}
HttpClient = httpClient;
_zipClient = zipClient;
_fileSystem = fileSystem;
Current = this;
}
@ -176,7 +180,7 @@ namespace MediaBrowser.Providers.TV
{
var files = new DirectoryInfo(path)
.EnumerateFiles("*.xml", SearchOption.TopDirectoryOnly)
.Select(i => i.LastWriteTimeUtc)
.Select(i => _fileSystem.GetLastWriteTimeUtc(i))
.ToList();
if (files.Count > 0)
@ -344,7 +348,7 @@ namespace MediaBrowser.Providers.TV
{
string validXml;
using (var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true))
using (var fileStream = _fileSystem.GetFileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, true))
{
using (var reader = new StreamReader(fileStream))
{
@ -354,7 +358,7 @@ namespace MediaBrowser.Providers.TV
}
}
using (var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true))
using (var fileStream = _fileSystem.GetFileStream(file, FileMode.Create, FileAccess.Write, FileShare.Read, true))
{
using (var writer = new StreamWriter(fileStream))
{
@ -1109,21 +1113,37 @@ namespace MediaBrowser.Providers.TV
var nodes = doc.SelectNodes("//Series");
var comparableName = GetComparableName(name);
if (nodes != null)
{
foreach (XmlNode node in nodes)
{
var n = node.SelectSingleNode("./SeriesName");
if (n != null && string.Equals(GetComparableName(n.InnerText), comparableName, StringComparison.OrdinalIgnoreCase))
var titles = new List<string>();
var nameNode = node.SelectSingleNode("./SeriesName");
if (nameNode != null)
{
n = node.SelectSingleNode("./seriesid");
if (n != null)
return n.InnerText;
titles.Add(GetComparableName(nameNode.InnerText));
}
else
var aliasNode = node.SelectSingleNode("./AliasNames");
if (aliasNode != null)
{
if (n != null)
Logger.Info("TVDb Provider - " + n.InnerText + " did not match " + comparableName);
var alias = aliasNode.InnerText.Split('|').Select(GetComparableName);
titles.AddRange(alias);
}
if (titles.Any(t => string.Equals(t, comparableName, StringComparison.OrdinalIgnoreCase)))
{
var id = node.SelectSingleNode("./seriesid");
if (id != null)
return id.InnerText;
}
foreach (var title in titles)
{
Logger.Info("TVDb Provider - " + title + " did not match " + comparableName);
}
}
}
}
// Try stripping off the year if it was supplied

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.IO;
@ -18,10 +19,12 @@ namespace MediaBrowser.Providers.TV
public class SeasonProviderFromXml : BaseMetadataProvider
{
public static SeasonProviderFromXml Current;
private readonly IFileSystem _fileSystem;
public SeasonProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager)
public SeasonProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
_fileSystem = fileSystem;
Current = this;
}
@ -54,7 +57,7 @@ namespace MediaBrowser.Providers.TV
return false;
}
return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed;
return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
}
/// <summary>

View File

@ -39,6 +39,13 @@ namespace MediaBrowser.Providers.TV
private async Task RunInternal(IProgress<double> progress, CancellationToken cancellationToken)
{
if (!_config.Configuration.EnableInternetProviders ||
_config.Configuration.InternetProviderExcludeTypes.Contains(typeof(Series).Name, StringComparer.OrdinalIgnoreCase))
{
progress.Report(100);
return;
}
var seriesList = _libraryManager.RootFolder
.RecursiveChildren
.OfType<Series>()
@ -136,21 +143,27 @@ namespace MediaBrowser.Providers.TV
.Where(i => i.Item1 != -1 && i.Item2 != -1)
.ToList();
var anySeasonsRemoved = await RemoveObsoleteOrMissingSeasons(series, episodeLookup, cancellationToken).ConfigureAwait(false);
var anySeasonsRemoved = await RemoveObsoleteOrMissingSeasons(series, episodeLookup, cancellationToken)
.ConfigureAwait(false);
var anyEpisodesRemoved = await RemoveObsoleteOrMissingEpisodes(series, episodeLookup, cancellationToken).ConfigureAwait(false);
var anyEpisodesRemoved = await RemoveObsoleteOrMissingEpisodes(series, episodeLookup, cancellationToken)
.ConfigureAwait(false);
var hasNewEpisodes = false;
if (_config.Configuration.EnableInternetProviders)
{
hasNewEpisodes = await AddMissingEpisodes(series, seriesDataPath, episodeLookup, cancellationToken).ConfigureAwait(false);
hasNewEpisodes = await AddMissingEpisodes(series, seriesDataPath, episodeLookup, cancellationToken)
.ConfigureAwait(false);
}
if (hasNewEpisodes || anySeasonsRemoved || anyEpisodesRemoved)
{
await series.RefreshMetadata(cancellationToken, true).ConfigureAwait(false);
await series.ValidateChildren(new Progress<double>(), cancellationToken, true).ConfigureAwait(false);
await series.RefreshMetadata(cancellationToken, true)
.ConfigureAwait(false);
await series.ValidateChildren(new Progress<double>(), cancellationToken, true)
.ConfigureAwait(false);
}
}
@ -211,7 +224,7 @@ namespace MediaBrowser.Providers.TV
else if (airDate.Value > now)
{
// tvdb has a lot of nearly blank episodes
_logger.Info("Creating virtual future episode {0} {1}x{2}", series.Name, tuple.Item1, tuple.Item2);
_logger.Info("Creating virtual unaired episode {0} {1}x{2}", series.Name, tuple.Item1, tuple.Item2);
await AddEpisode(series, tuple.Item1, tuple.Item2, cancellationToken).ConfigureAwait(false);

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.IO;
@ -18,10 +19,12 @@ namespace MediaBrowser.Providers.TV
public class SeriesProviderFromXml : BaseMetadataProvider
{
internal static SeriesProviderFromXml Current { get; private set; }
public SeriesProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager)
private readonly IFileSystem _fileSystem;
public SeriesProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
_fileSystem = fileSystem;
Current = this;
}
@ -54,7 +57,7 @@ namespace MediaBrowser.Providers.TV
return false;
}
return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed;
return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
}
/// <summary>

View File

@ -1,11 +1,13 @@
using System.Globalization;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
@ -42,6 +44,7 @@ namespace MediaBrowser.Providers.TV
/// The _config
/// </summary>
private readonly IServerConfigurationManager _config;
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="TvdbPrescanTask"/> class.
@ -49,11 +52,12 @@ namespace MediaBrowser.Providers.TV
/// <param name="logger">The logger.</param>
/// <param name="httpClient">The HTTP client.</param>
/// <param name="config">The config.</param>
public TvdbPrescanTask(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config)
public TvdbPrescanTask(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config, IFileSystem fileSystem)
{
_logger = logger;
_httpClient = httpClient;
_config = config;
_fileSystem = fileSystem;
}
protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
@ -66,7 +70,8 @@ namespace MediaBrowser.Providers.TV
/// <returns>Task.</returns>
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
if (!_config.Configuration.EnableInternetProviders)
if (!_config.Configuration.EnableInternetProviders ||
_config.Configuration.InternetProviderExcludeTypes.Contains(typeof(Series).Name, StringComparer.OrdinalIgnoreCase))
{
progress.Report(100);
return;
@ -81,7 +86,7 @@ namespace MediaBrowser.Providers.TV
var timestampFileInfo = new FileInfo(timestampFile);
// Don't check for tvdb updates anymore frequently than 24 hours
if (timestampFileInfo.Exists && (DateTime.UtcNow - timestampFileInfo.LastWriteTimeUtc).TotalDays < 1)
if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 1)
{
return;
}

View File

@ -1,8 +1,9 @@
using System.Linq;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
@ -11,6 +12,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@ -30,6 +32,7 @@ namespace MediaBrowser.Providers.TV
/// The _provider manager
/// </summary>
private readonly IProviderManager _providerManager;
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="TvdbSeriesImageProvider"/> class.
@ -39,7 +42,7 @@ namespace MediaBrowser.Providers.TV
/// <param name="configurationManager">The configuration manager.</param>
/// <param name="providerManager">The provider manager.</param>
/// <exception cref="System.ArgumentNullException">httpClient</exception>
public TvdbSeriesImageProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
public TvdbSeriesImageProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
: base(logManager, configurationManager)
{
if (httpClient == null)
@ -48,6 +51,7 @@ namespace MediaBrowser.Providers.TV
}
HttpClient = httpClient;
_providerManager = providerManager;
_fileSystem = fileSystem;
}
/// <summary>
@ -127,7 +131,7 @@ namespace MediaBrowser.Providers.TV
if (imagesFileInfo.Exists)
{
return imagesFileInfo.LastWriteTimeUtc;
return _fileSystem.GetLastWriteTimeUtc(imagesFileInfo);
}
}
@ -373,11 +377,19 @@ namespace MediaBrowser.Providers.TV
{
if (string.Equals(type, "poster", StringComparison.OrdinalIgnoreCase))
{
data.Poster = url;
// Just grab the first
if (string.IsNullOrWhiteSpace(data.Poster))
{
data.Poster = url;
}
}
else if (string.Equals(type, "series", StringComparison.OrdinalIgnoreCase))
{
data.Banner = url;
// Just grab the first
if (string.IsNullOrWhiteSpace(data.Banner))
{
data.Banner = url;
}
}
else if (string.Equals(type, "fanart", StringComparison.OrdinalIgnoreCase))
{

View File

@ -1,4 +1,6 @@
using MediaBrowser.Model.Logging;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
using System.Drawing;
@ -40,9 +42,10 @@ namespace MediaBrowser.Server.Implementations.Drawing
/// </summary>
/// <param name="path">The path of the image to get the dimensions of.</param>
/// <param name="logger">The logger.</param>
/// <param name="fileSystem">The file system.</param>
/// <returns>The dimensions of the specified image.</returns>
/// <exception cref="ArgumentException">The image was of an unrecognised format.</exception>
public static Size GetDimensions(string path, ILogger logger)
public static Size GetDimensions(string path, ILogger logger, IFileSystem fileSystem)
{
try
{
@ -60,7 +63,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
}
// Buffer to memory stream to avoid image locking file
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var fs = fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
using (var memoryStream = new MemoryStream())
{

View File

@ -3,6 +3,7 @@ using MediaBrowser.Common.IO;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Entities;
@ -51,16 +52,18 @@ namespace MediaBrowser.Server.Implementations.Drawing
/// The _app paths
/// </summary>
private readonly IServerApplicationPaths _appPaths;
private readonly IFileSystem _fileSystem;
private readonly string _imageSizeCachePath;
private readonly string _croppedWhitespaceImageCachePath;
private readonly string _enhancedImageCachePath;
private readonly string _resizedImageCachePath;
public ImageProcessor(ILogger logger, IServerApplicationPaths appPaths)
public ImageProcessor(ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem)
{
_logger = logger;
_appPaths = appPaths;
_fileSystem = fileSystem;
_imageSizeCachePath = Path.Combine(_appPaths.ImageCachePath, "image-sizes");
_croppedWhitespaceImageCachePath = Path.Combine(_appPaths.ImageCachePath, "cropped-images");
@ -113,7 +116,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
try
{
using (var fileStream = new FileStream(cacheFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
using (var fileStream = _fileSystem.GetFileStream(cacheFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, true))
{
await fileStream.CopyToAsync(toStream).ConfigureAwait(false);
return;
@ -131,7 +134,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
// Check again in case of lock contention
try
{
using (var fileStream = new FileStream(cacheFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
using (var fileStream = _fileSystem.GetFileStream(cacheFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, true))
{
await fileStream.CopyToAsync(toStream).ConfigureAwait(false);
semaphore.Release();
@ -150,7 +153,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
try
{
using (var fileStream = new FileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true))
using (var fileStream = _fileSystem.GetFileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, true))
{
// Copy to memory stream to avoid Image locking file
using (var memoryStream = new MemoryStream())
@ -228,7 +231,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
Directory.CreateDirectory(parentPath);
// Save to the cache location
using (var cacheFileStream = new FileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
using (var cacheFileStream = _fileSystem.GetFileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true))
{
// Save to the filestream
await cacheFileStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
@ -359,7 +362,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
try
{
using (var fileStream = new FileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true))
using (var fileStream = _fileSystem.GetFileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, true))
{
// Copy to memory stream to avoid Image locking file
using (var memoryStream = new MemoryStream())
@ -376,7 +379,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
Directory.CreateDirectory(parentPath);
using (var outputStream = new FileStream(croppedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read))
using (var outputStream = _fileSystem.GetFileStream(croppedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read, false))
{
croppedImage.Save(outputFormat, outputStream, 100);
}
@ -525,7 +528,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
// Cache file doesn't exist no biggie
}
var size = ImageHeader.GetDimensions(path, _logger);
var size = ImageHeader.GetDimensions(path, _logger, _fileSystem);
var parentPath = Path.GetDirectoryName(fullCachePath);
@ -685,7 +688,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
try
{
using (var fileStream = new FileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true))
using (var fileStream = _fileSystem.GetFileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, true))
{
// Copy to memory stream to avoid Image locking file
using (var memoryStream = new MemoryStream())
@ -702,7 +705,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
Directory.CreateDirectory(parentDirectory);
//And then save it in the cache
using (var outputStream = new FileStream(enhancedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read))
using (var outputStream = _fileSystem.GetFileStream(enhancedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read, false))
{
newImage.Save(ImageFormat.Png, outputStream, 100);
}

View File

@ -373,6 +373,11 @@ namespace MediaBrowser.Server.Implementations.Dto
dto.GameSystem = item.GameSystem;
}
private void SetGameSystemProperties(BaseItemDto dto, GameSystem item)
{
dto.GameSystem = item.GameSystemName;
}
/// <summary>
/// Gets the backdrop image tags.
/// </summary>
@ -1064,6 +1069,13 @@ namespace MediaBrowser.Server.Implementations.Dto
SetGameProperties(dto, game);
}
var gameSystem = item as GameSystem;
if (gameSystem != null)
{
SetGameSystemProperties(dto, gameSystem);
}
var musicVideo = item as MusicVideo;
if (musicVideo != null)

View File

@ -1,5 +1,7 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Notifications;
using MediaBrowser.Controller.Plugins;
@ -26,11 +28,12 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
private readonly IJsonSerializer _json;
private readonly INotificationsRepository _notificationsRepo;
private readonly IUserManager _userManager;
private readonly IFileSystem _fileSystem;
private readonly TimeSpan _frequency = TimeSpan.FromHours(6);
private readonly TimeSpan _maxAge = TimeSpan.FromDays(31);
public RemoteNotifications(IApplicationPaths appPaths, ILogger logger, IHttpClient httpClient, IJsonSerializer json, INotificationsRepository notificationsRepo, IUserManager userManager)
public RemoteNotifications(IApplicationPaths appPaths, ILogger logger, IHttpClient httpClient, IJsonSerializer json, INotificationsRepository notificationsRepo, IUserManager userManager, IFileSystem fileSystem)
{
_appPaths = appPaths;
_logger = logger;
@ -38,6 +41,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
_json = json;
_notificationsRepo = notificationsRepo;
_userManager = userManager;
_fileSystem = fileSystem;
}
/// <summary>
@ -56,7 +60,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
{
var dataPath = Path.Combine(_appPaths.DataPath, "remotenotifications.json");
var lastRunTime = File.Exists(dataPath) ? File.GetLastWriteTimeUtc(dataPath) : DateTime.MinValue;
var lastRunTime = File.Exists(dataPath) ? _fileSystem.GetLastWriteTimeUtc(dataPath) : DateTime.MinValue;
try
{

View File

@ -1,6 +1,7 @@
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.Logging;
using ServiceStack.Common;
using ServiceStack.Common.Web;
@ -25,13 +26,15 @@ namespace MediaBrowser.Server.Implementations.HttpServer
/// The _logger
/// </summary>
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="HttpResultFactory"/> class.
/// </summary>
/// <param name="logManager">The log manager.</param>
public HttpResultFactory(ILogManager logManager)
public HttpResultFactory(ILogManager logManager, IFileSystem fileSystem)
{
_fileSystem = fileSystem;
_logger = logManager.GetLogger("HttpResultFactory");
}
@ -288,7 +291,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
throw new ArgumentException("FileShare must be either Read or ReadWrite");
}
var dateModified = File.GetLastWriteTimeUtc(path);
var dateModified = _fileSystem.GetLastWriteTimeUtc(path);
var cacheKey = path + dateModified.Ticks;
@ -303,7 +306,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
/// <returns>Stream.</returns>
private Stream GetFileStream(string path, FileShare fileShare)
{
return new FileStream(path, FileMode.Open, FileAccess.Read, fileShare, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous);
return _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, fileShare, true);
}
/// <summary>

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
@ -87,10 +88,12 @@ namespace MediaBrowser.Server.Implementations.IO
private ILibraryManager LibraryManager { get; set; }
private IServerConfigurationManager ConfigurationManager { get; set; }
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="DirectoryWatchers" /> class.
/// </summary>
public DirectoryWatchers(ILogManager logManager, ITaskManager taskManager, ILibraryManager libraryManager, IServerConfigurationManager configurationManager)
public DirectoryWatchers(ILogManager logManager, ITaskManager taskManager, ILibraryManager libraryManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
{
if (taskManager == null)
{
@ -101,6 +104,7 @@ namespace MediaBrowser.Server.Implementations.IO
TaskManager = taskManager;
Logger = logManager.GetLogger("DirectoryWatchers");
ConfigurationManager = configurationManager;
_fileSystem = fileSystem;
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
}
@ -318,6 +322,18 @@ namespace MediaBrowser.Server.Implementations.IO
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="FileSystemEventArgs" /> instance containing the event data.</param>
void watcher_Changed(object sender, FileSystemEventArgs e)
{
try
{
OnWatcherChanged(e);
}
catch (IOException ex)
{
Logger.ErrorException("IOException in watcher changed", ex);
}
}
private void OnWatcherChanged(FileSystemEventArgs e)
{
var name = e.Name;
@ -418,7 +434,7 @@ namespace MediaBrowser.Server.Implementations.IO
{
try
{
var data = FileSystem.GetFileSystemInfo(path);
var data = _fileSystem.GetFileSystemInfo(path);
if (!data.Exists
|| data.Attributes.HasFlag(FileAttributes.Directory)
@ -434,7 +450,7 @@ namespace MediaBrowser.Server.Implementations.IO
try
{
using (new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
using (_fileSystem.GetFileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
//file is not locked
return false;

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Progress;
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Controller.Configuration;
@ -169,6 +170,8 @@ namespace MediaBrowser.Server.Implementations.Library
private readonly ConcurrentDictionary<string, UserRootFolder> _userRootFolders =
new ConcurrentDictionary<string, UserRootFolder>();
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="LibraryManager" /> class.
/// </summary>
@ -177,7 +180,7 @@ namespace MediaBrowser.Server.Implementations.Library
/// <param name="userManager">The user manager.</param>
/// <param name="configurationManager">The configuration manager.</param>
/// <param name="userDataRepository">The user data repository.</param>
public LibraryManager(ILogger logger, ITaskManager taskManager, IUserManager userManager, IServerConfigurationManager configurationManager, IUserDataManager userDataRepository, Func<IDirectoryWatchers> directoryWatchersFactory)
public LibraryManager(ILogger logger, ITaskManager taskManager, IUserManager userManager, IServerConfigurationManager configurationManager, IUserDataManager userDataRepository, Func<IDirectoryWatchers> directoryWatchersFactory, IFileSystem fileSystem)
{
_logger = logger;
_taskManager = taskManager;
@ -185,6 +188,7 @@ namespace MediaBrowser.Server.Implementations.Library
ConfigurationManager = configurationManager;
_userDataRepository = userDataRepository;
_directoryWatchersFactory = directoryWatchersFactory;
_fileSystem = fileSystem;
ByReferenceItems = new ConcurrentDictionary<Guid, BaseItem>();
ConfigurationManager.ConfigurationUpdated += ConfigurationUpdated;
@ -417,7 +421,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (item != null)
{
ResolverHelper.SetInitialItemValues(item, args);
ResolverHelper.SetInitialItemValues(item, args, _fileSystem);
// Now handle the issue with posibly having the same item referenced from multiple physical
// places within the library. Be sure we always end up with just one instance.
@ -482,7 +486,7 @@ namespace MediaBrowser.Server.Implementations.Library
// When resolving the root, we need it's grandchildren (children of user views)
var flattenFolderDepth = isPhysicalRoot ? 2 : 0;
args.FileSystemDictionary = FileData.GetFilteredFileSystemEntries(args.Path, _logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf);
args.FileSystemDictionary = FileData.GetFilteredFileSystemEntries(args.Path, _fileSystem, _logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf);
// Need to remove subpaths that may have been resolved from shortcuts
// Example: if \\server\movies exists, then strip out \\server\movies\action
@ -701,7 +705,7 @@ namespace MediaBrowser.Server.Implementations.Library
throw new ArgumentNullException();
}
var validFilename = FileSystem.GetValidFilename(name).Trim();
var validFilename = _fileSystem.GetValidFilename(name).Trim();
string subFolderPrefix = null;
@ -768,8 +772,8 @@ namespace MediaBrowser.Server.Implementations.Library
{
Name = name,
Id = id,
DateCreated = fileInfo.CreationTimeUtc,
DateModified = fileInfo.LastWriteTimeUtc,
DateCreated = _fileSystem.GetCreationTimeUtc(fileInfo),
DateModified = _fileSystem.GetLastWriteTimeUtc(fileInfo),
Path = path
};
isNew = true;
@ -1066,7 +1070,7 @@ namespace MediaBrowser.Server.Implementations.Library
Name = Path.GetFileName(dir),
Locations = Directory.EnumerateFiles(dir, "*.mblink", SearchOption.TopDirectoryOnly)
.Select(FileSystem.ResolveShortcut)
.Select(_fileSystem.ResolveShortcut)
.OrderBy(i => i)
.ToList(),
@ -1150,7 +1154,7 @@ namespace MediaBrowser.Server.Implementations.Library
try
{
// Try to resolve the path into a video
video = ResolvePath(FileSystem.GetFileSystemInfo(info.Path)) as Video;
video = ResolvePath(_fileSystem.GetFileSystemInfo(info.Path)) as Video;
if (video == null)
{

View File

@ -1,5 +1,7 @@
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Resolvers;
using System;
@ -18,7 +20,8 @@ namespace MediaBrowser.Server.Implementations.Library
/// </summary>
/// <param name="item">The item.</param>
/// <param name="args">The args.</param>
public static void SetInitialItemValues(BaseItem item, ItemResolveArgs args)
/// <param name="fileSystem">The file system.</param>
public static void SetInitialItemValues(BaseItem item, ItemResolveArgs args, IFileSystem fileSystem)
{
item.ResetResolveArgs(args);
@ -48,7 +51,7 @@ namespace MediaBrowser.Server.Implementations.Library
item.DontFetchMeta = item.Path.IndexOf("[dontfetchmeta]", StringComparison.OrdinalIgnoreCase) != -1;
// Make sure DateCreated and DateModified have values
EntityResolutionHelper.EnsureDates(item, args, true);
EntityResolutionHelper.EnsureDates(fileSystem, item, args, true);
}
/// <summary>

View File

@ -52,7 +52,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
// If there's a collection type and it's not tv, it can't be a series
if (!string.IsNullOrEmpty(collectionType) &&
!string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
!string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase) &&
!string.Equals(collectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase))
{
return null;
}

View File

@ -1,4 +1,6 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Localization;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization;
@ -30,13 +32,16 @@ namespace MediaBrowser.Server.Implementations.Localization
private readonly ConcurrentDictionary<string, Dictionary<string, ParentalRating>> _allParentalRatings =
new ConcurrentDictionary<string, Dictionary<string, ParentalRating>>(StringComparer.OrdinalIgnoreCase);
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="LocalizationManager"/> class.
/// </summary>
/// <param name="configurationManager">The configuration manager.</param>
public LocalizationManager(IServerConfigurationManager configurationManager)
public LocalizationManager(IServerConfigurationManager configurationManager, IFileSystem fileSystem)
{
_configurationManager = configurationManager;
_fileSystem = fileSystem;
ExtractAll();
}
@ -65,7 +70,7 @@ namespace MediaBrowser.Server.Implementations.Localization
{
using (var stream = type.Assembly.GetManifestResourceStream(resource))
{
using (var fs = new FileStream(Path.Combine(localizationPath, filename), FileMode.Create, FileAccess.Write, FileShare.Read))
using (var fs = _fileSystem.GetFileStream(Path.Combine(localizationPath, filename), FileMode.Create, FileAccess.Write, FileShare.Read))
{
stream.CopyTo(fs);
}

View File

@ -46,6 +46,14 @@
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data.SQLite, Version=1.0.89.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=x86">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\System.Data.SQLite.x86.1.0.89.0\lib\net45\System.Data.SQLite.dll</HintPath>
</Reference>
<Reference Include="System.Data.SQLite.Linq, Version=1.0.89.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\System.Data.SQLite.x86.1.0.89.0\lib\net45\System.Data.SQLite.Linq.dll</HintPath>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Reactive.Core">
<HintPath>..\packages\Rx-Core.2.1.30214.0\lib\Net45\System.Reactive.Core.dll</HintPath>
@ -88,12 +96,6 @@
<Reference Include="ServiceStack.Text">
<HintPath>..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll</HintPath>
</Reference>
<Reference Include="System.Data.SQLite">
<HintPath>..\packages\System.Data.SQLite.x86.1.0.88.0\lib\net45\System.Data.SQLite.dll</HintPath>
</Reference>
<Reference Include="System.Data.SQLite.Linq">
<HintPath>..\packages\System.Data.SQLite.x86.1.0.88.0\lib\net45\System.Data.SQLite.Linq.dll</HintPath>
</Reference>
<Reference Include="Mono.Data.Sqlite">
<HintPath>..\packages\ServiceStack.OrmLite.Sqlite.Mono.3.9.64\lib\net35\Mono.Data.Sqlite.dll</HintPath>
</Reference>

View File

@ -1,6 +1,7 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.MediaInfo;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
@ -53,6 +54,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
/// The FF probe resource pool
/// </summary>
private readonly SemaphoreSlim _ffProbeResourcePool = new SemaphoreSlim(1, 1);
private readonly IFileSystem _fileSystem;
public string FFMpegPath { get; private set; }
@ -61,12 +63,13 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
public string Version { get; private set; }
public MediaEncoder(ILogger logger, IApplicationPaths appPaths,
IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, string version)
IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, string version, IFileSystem fileSystem)
{
_logger = logger;
_appPaths = appPaths;
_jsonSerializer = jsonSerializer;
Version = version;
_fileSystem = fileSystem;
FFProbePath = ffProbePath;
FFMpegPath = ffMpegPath;
}
@ -458,8 +461,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "ffmpeg-sub-convert-" + Guid.NewGuid() + ".txt");
var logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read,
StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous);
var logFileStream = _fileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true);
try
{
@ -685,7 +687,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);
var logFileStream = _fileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true);
try
{

View File

@ -35,16 +35,18 @@ namespace MediaBrowser.Server.Implementations.Providers
/// The _directory watchers
/// </summary>
private readonly IDirectoryWatchers _directoryWatchers;
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="ImageSaver"/> class.
/// </summary>
/// <param name="config">The config.</param>
/// <param name="directoryWatchers">The directory watchers.</param>
public ImageSaver(IServerConfigurationManager config, IDirectoryWatchers directoryWatchers)
public ImageSaver(IServerConfigurationManager config, IDirectoryWatchers directoryWatchers, IFileSystem fileSystem)
{
_config = config;
_directoryWatchers = directoryWatchers;
_fileSystem = fileSystem;
_remoteImageCache = new FileSystemRepository(config.ApplicationPaths.DownloadedImagesDataPath);
}
@ -67,30 +69,20 @@ namespace MediaBrowser.Server.Implementations.Providers
throw new ArgumentNullException("mimeType");
}
var saveLocally = _config.Configuration.SaveLocalMeta;
var saveLocally = _config.Configuration.SaveLocalMeta || item is IItemByName || item is User;
if (item is IItemByName)
{
saveLocally = true;
}
else if (item is User)
{
saveLocally = true;
}
else if (item is Audio || item.Parent == null || string.IsNullOrEmpty(item.MetaLocation))
if (item is Audio || item.Parent == null)
{
saveLocally = false;
}
if (type != ImageType.Primary)
if (type != ImageType.Primary && item is Episode)
{
if (item is Episode)
{
saveLocally = false;
}
saveLocally = false;
}
if (item.LocationType == LocationType.Remote || item.LocationType == LocationType.Virtual)
var locationType = item.LocationType;
if (locationType == LocationType.Remote || locationType == LocationType.Virtual)
{
saveLocally = false;
}
@ -186,7 +178,7 @@ namespace MediaBrowser.Server.Implementations.Providers
}
}
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
using (var fs = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true))
{
await source.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, cancellationToken).ConfigureAwait(false);
}
@ -373,7 +365,7 @@ namespace MediaBrowser.Server.Implementations.Providers
path = GetSavePathForItemInMixedFolder(item, type, filename, extension);
}
if (string.IsNullOrEmpty(path) && !string.IsNullOrEmpty(item.MetaLocation))
if (string.IsNullOrEmpty(path))
{
path = Path.Combine(item.MetaLocation, filename + extension);
}

View File

@ -13,6 +13,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Providers;
namespace MediaBrowser.Server.Implementations.Providers
{
@ -48,6 +49,9 @@ namespace MediaBrowser.Server.Implementations.Providers
/// <value>The metadata providers enumerable.</value>
private BaseMetadataProvider[] MetadataProviders { get; set; }
private IImageProvider[] ImageProviders { get; set; }
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="ProviderManager" /> class.
/// </summary>
@ -55,22 +59,25 @@ namespace MediaBrowser.Server.Implementations.Providers
/// <param name="configurationManager">The configuration manager.</param>
/// <param name="directoryWatchers">The directory watchers.</param>
/// <param name="logManager">The log manager.</param>
/// <param name="libraryManager">The library manager.</param>
public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, IDirectoryWatchers directoryWatchers, ILogManager logManager, ILibraryManager libraryManager)
public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, IDirectoryWatchers directoryWatchers, ILogManager logManager, IFileSystem fileSystem)
{
_logger = logManager.GetLogger("ProviderManager");
_httpClient = httpClient;
ConfigurationManager = configurationManager;
_directoryWatchers = directoryWatchers;
_fileSystem = fileSystem;
}
/// <summary>
/// Adds the metadata providers.
/// </summary>
/// <param name="providers">The providers.</param>
public void AddParts(IEnumerable<BaseMetadataProvider> providers)
/// <param name="imageProviders">The image providers.</param>
public void AddParts(IEnumerable<BaseMetadataProvider> providers, IEnumerable<IImageProvider> imageProviders)
{
MetadataProviders = providers.OrderBy(e => e.Priority).ToArray();
ImageProviders = imageProviders.ToArray();
}
/// <summary>
@ -288,7 +295,7 @@ namespace MediaBrowser.Server.Implementations.Providers
{
using (dataToSave)
{
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
using (var fs = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true))
{
await dataToSave.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, cancellationToken).ConfigureAwait(false);
}
@ -342,7 +349,60 @@ namespace MediaBrowser.Server.Implementations.Providers
/// <returns>Task.</returns>
public Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, string sourceUrl, CancellationToken cancellationToken)
{
return new ImageSaver(ConfigurationManager, _directoryWatchers).SaveImage(item, source, mimeType, type, imageIndex, sourceUrl, cancellationToken);
return new ImageSaver(ConfigurationManager, _directoryWatchers, _fileSystem).SaveImage(item, source, mimeType, type, imageIndex, sourceUrl, cancellationToken);
}
/// <summary>
/// Gets the available remote images.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="type">The type.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{IEnumerable{RemoteImageInfo}}.</returns>
public async Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(BaseItem item, ImageType type, CancellationToken cancellationToken)
{
var providers = GetSupportedImageProviders(item, type);
var tasks = providers.Select(i => Task.Run(async () =>
{
try
{
var result = await i.GetAvailableImages(item, type, cancellationToken).ConfigureAwait(false);
return result.ToList();
}
catch (Exception ex)
{
_logger.ErrorException("{0} failed in GetAvailableImages for type {1}", ex, i.GetType().Name, item.GetType().Name);
return new List<RemoteImageInfo>();
}
}));
var results = await Task.WhenAll(tasks).ConfigureAwait(false);
return results.SelectMany(i => i);
}
/// <summary>
/// Gets the supported image providers.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="type">The type.</param>
/// <returns>IEnumerable{IImageProvider}.</returns>
private IEnumerable<IImageProvider> GetSupportedImageProviders(BaseItem item, ImageType type)
{
return ImageProviders.Where(i =>
{
try
{
return i.Supports(item, type);
}
catch (Exception ex)
{
_logger.ErrorException("{0} failed in Supports for type {1}", ex, i.GetType().Name, item.GetType().Name);
return false;
}
});
}
}
}

View File

@ -14,5 +14,5 @@
<package id="ServiceStack.OrmLite.SqlServer" version="3.9.43" targetFramework="net45" />
<package id="ServiceStack.Redis" version="3.9.43" targetFramework="net45" />
<package id="ServiceStack.Text" version="3.9.62" targetFramework="net45" />
<package id="System.Data.SQLite.x86" version="1.0.88.0" targetFramework="net45" />
<package id="System.Data.SQLite.x86" version="1.0.89.0" targetFramework="net45" />
</packages>

View File

@ -0,0 +1,21 @@
using MediaBrowser.Common.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Common.Implementations.IO;
namespace MediaBrowser.ServerApplication.IO
{
/// <summary>
/// Class FileSystemFactory
/// </summary>
public static class FileSystemFactory
{
/// <summary>
/// Creates the file system manager.
/// </summary>
/// <returns>IFileSystem.</returns>
public static IFileSystem CreateFileSystemManager(ILogManager logManager)
{
return new CommonFileSystem(logManager.GetLogger("FileSystem"), false);
}
}
}

View File

@ -88,6 +88,7 @@
<Link>FFMpeg\FFMpegDownloader.cs</Link>
</Compile>
<Compile Include="FFMpeg\FFMpegDownloadInfo.cs" />
<Compile Include="IO\FileSystemFactory.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
@ -129,6 +130,7 @@
<Folder Include="Native\" />
<Folder Include="FFMpeg\" />
<Folder Include="Networking\" />
<Folder Include="IO\" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />

View File

@ -17,6 +17,7 @@ using System.Security.Cryptography.X509Certificates;
using Gtk;
using Gdk;
using System.Threading.Tasks;
using System.Reflection;
namespace MediaBrowser.Server.Mono
{
@ -203,6 +204,8 @@ namespace MediaBrowser.Server.Mono
logger.Info("Server: {0}", Environment.MachineName);
logger.Info("Operating system: {0}", Environment.OSVersion.ToString());
MonoBug11817WorkAround.Apply ();
}
/// <summary>
@ -280,4 +283,34 @@ namespace MediaBrowser.Server.Mono
return true;
}
}
public class MonoBug11817WorkAround
{
public static void Apply()
{
var property = typeof(TimeZoneInfo).GetProperty("TimeZoneDirectory", BindingFlags.Static | BindingFlags.NonPublic);
if (property == null) return;
var zoneInfo = FindZoneInfoFolder();
property.SetValue(null, zoneInfo, new object[0]);
}
public static string FindZoneInfoFolder()
{
var current = new DirectoryInfo(Directory.GetCurrentDirectory());
while(current != null)
{
var zoneinfoTestPath = Path.Combine(current.FullName, "zoneinfo");
if (Directory.Exists(zoneinfoTestPath))
return zoneinfoTestPath;
current = current.Parent;
}
return null;
}
}
}

Some files were not shown because too many files have changed in this diff Show More