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.Entities;
using MediaBrowser.Controller.IO; using MediaBrowser.Controller.IO;
using System; using System;
@ -12,20 +13,27 @@ namespace MediaBrowser.Api.Library
/// </summary> /// </summary>
public static class LibraryHelpers public static class LibraryHelpers
{ {
/// <summary>
/// The shortcut file extension
/// </summary>
private const string ShortcutFileExtension = ".mblink"; private const string ShortcutFileExtension = ".mblink";
/// <summary>
/// The shortcut file search
/// </summary>
private const string ShortcutFileSearch = "*" + ShortcutFileExtension; private const string ShortcutFileSearch = "*" + ShortcutFileExtension;
/// <summary> /// <summary>
/// Adds the virtual folder. /// Adds the virtual folder.
/// </summary> /// </summary>
/// <param name="fileSystem">The file system.</param>
/// <param name="name">The name.</param> /// <param name="name">The name.</param>
/// <param name="collectionType">Type of the collection.</param> /// <param name="collectionType">Type of the collection.</param>
/// <param name="user">The user.</param> /// <param name="user">The user.</param>
/// <param name="appPaths">The app paths.</param> /// <param name="appPaths">The app paths.</param>
/// <exception cref="System.ArgumentException">There is already a media collection with the name + name + .</exception> /// <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 rootFolderPath = user != null ? user.RootFolderPath : appPaths.DefaultUserViewsPath;
var virtualFolderPath = Path.Combine(rootFolderPath, name); var virtualFolderPath = Path.Combine(rootFolderPath, name);
@ -106,12 +114,13 @@ namespace MediaBrowser.Api.Library
/// <summary> /// <summary>
/// Deletes a shortcut from within a virtual folder, within either the default view or a user view /// Deletes a shortcut from within a virtual folder, within either the default view or a user view
/// </summary> /// </summary>
/// <param name="fileSystem">The file system.</param>
/// <param name="virtualFolderName">Name of the virtual folder.</param> /// <param name="virtualFolderName">Name of the virtual folder.</param>
/// <param name="mediaPath">The media path.</param> /// <param name="mediaPath">The media path.</param>
/// <param name="user">The user.</param> /// <param name="user">The user.</param>
/// <param name="appPaths">The app paths.</param> /// <param name="appPaths">The app paths.</param>
/// <exception cref="System.IO.DirectoryNotFoundException">The media folder does not exist</exception> /// <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 rootFolderPath = user != null ? user.RootFolderPath : appPaths.DefaultUserViewsPath;
var path = Path.Combine(rootFolderPath, virtualFolderName); 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)); 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)) if (!string.IsNullOrEmpty(shortcut))
{ {
@ -132,13 +141,14 @@ namespace MediaBrowser.Api.Library
/// <summary> /// <summary>
/// Adds an additional mediaPath to an existing virtual folder, within either the default view or a user view /// Adds an additional mediaPath to an existing virtual folder, within either the default view or a user view
/// </summary> /// </summary>
/// <param name="fileSystem">The file system.</param>
/// <param name="virtualFolderName">Name of the virtual folder.</param> /// <param name="virtualFolderName">Name of the virtual folder.</param>
/// <param name="path">The path.</param> /// <param name="path">The path.</param>
/// <param name="user">The user.</param> /// <param name="user">The user.</param>
/// <param name="appPaths">The app paths.</param> /// <param name="appPaths">The app paths.</param>
/// <exception cref="System.ArgumentException">The path is not valid.</exception> /// <exception cref="System.ArgumentException">The path is not valid.</exception>
/// <exception cref="System.IO.DirectoryNotFoundException">The path does not exist.</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)) if (!Path.IsPathRooted(path))
{ {
@ -160,7 +170,7 @@ namespace MediaBrowser.Api.Library
var rootFolderPath = user != null ? user.RootFolderPath : appPaths.DefaultUserViewsPath; var rootFolderPath = user != null ? user.RootFolderPath : appPaths.DefaultUserViewsPath;
var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName); var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
ValidateNewMediaPath(rootFolderPath, path, appPaths); ValidateNewMediaPath(fileSystem, rootFolderPath, path, appPaths);
var shortcutFilename = Path.GetFileNameWithoutExtension(path); var shortcutFilename = Path.GetFileNameWithoutExtension(path);
@ -172,20 +182,22 @@ namespace MediaBrowser.Api.Library
lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension); lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension);
} }
FileSystem.CreateShortcut(lnk, path); fileSystem.CreateShortcut(lnk, path);
} }
/// <summary> /// <summary>
/// Validates that a new media path can be added /// Validates that a new media path can be added
/// </summary> /// </summary>
/// <param name="fileSystem">The file system.</param>
/// <param name="currentViewRootFolderPath">The current view root folder path.</param> /// <param name="currentViewRootFolderPath">The current view root folder path.</param>
/// <param name="mediaPath">The media path.</param> /// <param name="mediaPath">The media path.</param>
/// <param name="appPaths">The app paths.</param> /// <param name="appPaths">The app paths.</param>
/// <exception cref="System.ArgumentException"></exception> /// <exception cref="System.ArgumentException">
private static void ValidateNewMediaPath(string currentViewRootFolderPath, string mediaPath, IServerApplicationPaths appPaths) /// </exception>
private static void ValidateNewMediaPath(IFileSystem fileSystem, string currentViewRootFolderPath, string mediaPath, IServerApplicationPaths appPaths)
{ {
var duplicate = Directory.EnumerateFiles(appPaths.RootFolderPath, ShortcutFileSearch, SearchOption.AllDirectories) var duplicate = Directory.EnumerateFiles(appPaths.RootFolderPath, ShortcutFileSearch, SearchOption.AllDirectories)
.Select(FileSystem.ResolveShortcut) .Select(fileSystem.ResolveShortcut)
.FirstOrDefault(p => !IsNewPathValid(mediaPath, p, false)); .FirstOrDefault(p => !IsNewPathValid(mediaPath, p, false));
if (!string.IsNullOrEmpty(duplicate)) 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 // Don't allow duplicate sub-paths within the same user library, or it will result in duplicate items
// See comments in IsNewPathValid // See comments in IsNewPathValid
duplicate = Directory.EnumerateFiles(currentViewRootFolderPath, ShortcutFileSearch, SearchOption.AllDirectories) duplicate = Directory.EnumerateFiles(currentViewRootFolderPath, ShortcutFileSearch, SearchOption.AllDirectories)
.Select(FileSystem.ResolveShortcut) .Select(fileSystem.ResolveShortcut)
.FirstOrDefault(p => !IsNewPathValid(mediaPath, p, true)); .FirstOrDefault(p => !IsNewPathValid(mediaPath, p, true));
if (!string.IsNullOrEmpty(duplicate)) 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 // Make sure the current root folder doesn't already have a shortcut to the same path
duplicate = Directory.EnumerateFiles(currentViewRootFolderPath, ShortcutFileSearch, SearchOption.AllDirectories) duplicate = Directory.EnumerateFiles(currentViewRootFolderPath, ShortcutFileSearch, SearchOption.AllDirectories)
.Select(FileSystem.ResolveShortcut) .Select(fileSystem.ResolveShortcut)
.FirstOrDefault(p => mediaPath.Equals(p, StringComparison.OrdinalIgnoreCase)); .FirstOrDefault(p => mediaPath.Equals(p, StringComparison.OrdinalIgnoreCase));
if (!string.IsNullOrEmpty(duplicate)) 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.IO;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
@ -186,6 +187,8 @@ namespace MediaBrowser.Api.Library
private readonly IDirectoryWatchers _directoryWatchers; private readonly IDirectoryWatchers _directoryWatchers;
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="LibraryStructureService"/> class. /// Initializes a new instance of the <see cref="LibraryStructureService"/> class.
/// </summary> /// </summary>
@ -193,7 +196,7 @@ namespace MediaBrowser.Api.Library
/// <param name="userManager">The user manager.</param> /// <param name="userManager">The user manager.</param>
/// <param name="libraryManager">The library manager.</param> /// <param name="libraryManager">The library manager.</param>
/// <exception cref="System.ArgumentNullException">appPaths</exception> /// <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) if (appPaths == null)
{ {
@ -204,6 +207,7 @@ namespace MediaBrowser.Api.Library
_appPaths = appPaths; _appPaths = appPaths;
_libraryManager = libraryManager; _libraryManager = libraryManager;
_directoryWatchers = directoryWatchers; _directoryWatchers = directoryWatchers;
_fileSystem = fileSystem;
} }
/// <summary> /// <summary>
@ -241,13 +245,13 @@ namespace MediaBrowser.Api.Library
{ {
if (string.IsNullOrEmpty(request.UserId)) if (string.IsNullOrEmpty(request.UserId))
{ {
LibraryHelpers.AddVirtualFolder(request.Name, request.CollectionType, null, _appPaths); LibraryHelpers.AddVirtualFolder(_fileSystem, request.Name, request.CollectionType, null, _appPaths);
} }
else else
{ {
var user = _userManager.GetUserById(new Guid(request.UserId)); 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 // 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)) if (string.IsNullOrEmpty(request.UserId))
{ {
LibraryHelpers.AddMediaPath(request.Name, request.Path, null, _appPaths); LibraryHelpers.AddMediaPath(_fileSystem, request.Name, request.Path, null, _appPaths);
} }
else else
{ {
var user = _userManager.GetUserById(new Guid(request.UserId)); 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 // 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)) if (string.IsNullOrEmpty(request.UserId))
{ {
LibraryHelpers.RemoveMediaPath(request.Name, request.Path, null, _appPaths); LibraryHelpers.RemoveMediaPath(_fileSystem, request.Name, request.Path, null, _appPaths);
} }
else else
{ {
var user = _userManager.GetUserById(new Guid(request.UserId)); 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 // 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.Entities.TV;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Querying; using MediaBrowser.Model.Querying;
using ServiceStack.ServiceHost; using ServiceStack.ServiceHost;
using System; using System;
@ -32,6 +34,21 @@ namespace MediaBrowser.Api
public string Id { get; set; } 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> /// <summary>
/// Class GetCriticReviews /// Class GetCriticReviews
/// </summary> /// </summary>
@ -208,6 +225,7 @@ namespace MediaBrowser.Api
private readonly ILibraryManager _libraryManager; private readonly ILibraryManager _libraryManager;
private readonly IUserManager _userManager; private readonly IUserManager _userManager;
private readonly IUserDataManager _userDataManager; private readonly IUserDataManager _userDataManager;
private readonly IProviderManager _providerManager;
private readonly IDtoService _dtoService; private readonly IDtoService _dtoService;
@ -215,13 +233,14 @@ namespace MediaBrowser.Api
/// Initializes a new instance of the <see cref="LibraryService" /> class. /// Initializes a new instance of the <see cref="LibraryService" /> class.
/// </summary> /// </summary>
public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager, public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager,
IDtoService dtoService, IUserDataManager userDataManager) IDtoService dtoService, IUserDataManager userDataManager, IProviderManager providerManager)
{ {
_itemRepo = itemRepo; _itemRepo = itemRepo;
_libraryManager = libraryManager; _libraryManager = libraryManager;
_userManager = userManager; _userManager = userManager;
_dtoService = dtoService; _dtoService = dtoService;
_userDataManager = userDataManager; _userDataManager = userDataManager;
_providerManager = providerManager;
} }
public object Get(GetFile request) public object Get(GetFile request)
@ -240,6 +259,15 @@ namespace MediaBrowser.Api
return ToStaticFileResult(item.Path); 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> /// <summary>
/// Gets the specified request. /// Gets the specified request.
/// </summary> /// </summary>
@ -335,7 +363,9 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns> /// <returns>System.Object.</returns>
public object Get(GetItemCounts request) 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; 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 IMediaEncoder MediaEncoder { get; private set; }
protected IDtoService DtoService { get; private set; } protected IDtoService DtoService { get; private set; }
protected IFileSystem FileSystem { get; private set; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="BaseStreamingService" /> class. /// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
/// </summary> /// </summary>
@ -67,8 +69,9 @@ namespace MediaBrowser.Api.Playback
/// <param name="libraryManager">The library manager.</param> /// <param name="libraryManager">The library manager.</param>
/// <param name="isoManager">The iso manager.</param> /// <param name="isoManager">The iso manager.</param>
/// <param name="mediaEncoder">The media encoder.</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; DtoService = dtoService;
ApplicationPaths = appPaths; ApplicationPaths = appPaths;
UserManager = userManager; UserManager = userManager;
@ -269,7 +272,7 @@ namespace MediaBrowser.Api.Playback
// If fixed dimensions were supplied // If fixed dimensions were supplied
if (request.Width.HasValue && request.Height.HasValue) 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); 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"); 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. // 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); 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;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
@ -32,8 +33,8 @@ namespace MediaBrowser.Api.Playback.Hls
/// <param name="libraryManager">The library manager.</param> /// <param name="libraryManager">The library manager.</param>
/// <param name="isoManager">The iso manager.</param> /// <param name="isoManager">The iso manager.</param>
/// <param name="mediaEncoder">The media encoder.</param> /// <param name="mediaEncoder">The media encoder.</param>
public AudioHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService) public AudioHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem)
: base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService) : 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="libraryManager">The library manager.</param>
/// <param name="isoManager">The iso manager.</param> /// <param name="isoManager">The iso manager.</param>
/// <param name="mediaEncoder">The media encoder.</param> /// <param name="mediaEncoder">The media encoder.</param>
protected BaseHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService) protected BaseHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem)
: base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService) : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem)
{ {
} }
@ -209,7 +209,7 @@ namespace MediaBrowser.Api.Playback.Hls
string fileText; string fileText;
// Need to use FileShare.ReadWrite because we're reading the file at the same time it's being written // 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)) 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;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
@ -39,8 +40,8 @@ namespace MediaBrowser.Api.Playback.Hls
/// <param name="isoManager">The iso manager.</param> /// <param name="isoManager">The iso manager.</param>
/// <param name="mediaEncoder">The media encoder.</param> /// <param name="mediaEncoder">The media encoder.</param>
/// <param name="dtoService">The dto service.</param> /// <param name="dtoService">The dto service.</param>
public VideoHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService) public VideoHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem)
: base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService) : 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;
using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
@ -40,8 +41,8 @@ namespace MediaBrowser.Api.Playback.Progressive
/// </summary> /// </summary>
public class AudioService : BaseProgressiveStreamingService public class AudioService : BaseProgressiveStreamingService
{ {
public AudioService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IDtoService dtoService, IImageProcessor 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) : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, itemRepo, dtoService, imageProcessor, fileSystem)
{ {
} }

View File

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

View File

@ -13,6 +13,7 @@ namespace MediaBrowser.Api.Playback.Progressive
{ {
private string Path { get; set; } private string Path { get; set; }
private ILogger Logger { get; set; } private ILogger Logger { get; set; }
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// The _options /// The _options
@ -32,10 +33,11 @@ namespace MediaBrowser.Api.Playback.Progressive
/// </summary> /// </summary>
/// <param name="path">The path.</param> /// <param name="path">The path.</param>
/// <param name="logger">The logger.</param> /// <param name="logger">The logger.</param>
public ProgressiveStreamWriter(string path, ILogger logger) public ProgressiveStreamWriter(string path, ILogger logger, IFileSystem fileSystem)
{ {
Path = path; Path = path;
Logger = logger; Logger = logger;
_fileSystem = fileSystem;
} }
/// <summary> /// <summary>
@ -83,7 +85,7 @@ namespace MediaBrowser.Api.Playback.Progressive
var eofCount = 0; var eofCount = 0;
long position = 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) 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;
using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
@ -54,8 +55,8 @@ namespace MediaBrowser.Api.Playback.Progressive
/// </summary> /// </summary>
public class VideoService : BaseProgressiveStreamingService public class VideoService : BaseProgressiveStreamingService
{ {
public VideoService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IDtoService dtoService, IImageProcessor 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) : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, itemRepo, dtoService, imageProcessor, fileSystem)
{ {
} }

View File

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

View File

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

View File

@ -1,10 +1,9 @@
using System.Collections; using MediaBrowser.Controller.Dto;
using System.Globalization;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying; using MediaBrowser.Model.Querying;
using ServiceStack.ServiceHost; using ServiceStack.ServiceHost;
using System; 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)] [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; } 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)] [ApiMember(Name = "SeriesId", Description = "Optional. Filter by series id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string ExcludeLocationTypes { get; set; } 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> /// <summary>
/// Gets the item fields. /// Gets the item fields.
/// </summary> /// </summary>
@ -170,10 +160,15 @@ namespace MediaBrowser.Api
{ {
var user = _userManager.GetUserById(request.UserId); var user = _userManager.GetUserById(request.UserId);
var itemsList = user.RootFolder var items = user.RootFolder
.GetRecursiveChildren(user, i => i is Series) .GetRecursiveChildren(user)
.OfType<Series>();
items = FilterSeries(request, items);
var itemsList = items
.AsParallel() .AsParallel()
.Select(i => GetNextUp((Series)i, user, request)) .Select(i => GetNextUp(i, user, request))
.ToList(); .ToList();
itemsList = itemsList itemsList = itemsList
@ -264,35 +259,19 @@ namespace MediaBrowser.Api
private IEnumerable<Episode> FilterItems(GetNextUpEpisodes request, IEnumerable<Episode> items) private IEnumerable<Episode> FilterItems(GetNextUpEpisodes request, IEnumerable<Episode> items)
{ {
// ExcludeLocationTypes // Make this configurable when needed
if (!string.IsNullOrEmpty(request.ExcludeLocationTypes)) 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 items = items.Where(i => i.Id == id);
.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);
} }
return items; 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;
using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies; 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")] [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; } 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)] [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; } public string LocationTypes { get; set; }
[ApiMember(Name = "MinPremiereDate", Description = "Optional. The minimum premiere date. Format = yyyyMMddHHmmss", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] [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 MinPremiereDate { get; set; } public string ExcludeLocationTypes { 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; }
public bool IncludeIndexContainers { 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> /// <summary>
@ -270,6 +269,8 @@ namespace MediaBrowser.Api.UserLibrary
items = ApplyFilter(items, filter, user, _userDataRepository); items = ApplyFilter(items, filter, user, _userDataRepository);
} }
items = FilterVirtualEpisodes(request, items, user);
items = items.AsEnumerable(); items = items.AsEnumerable();
items = ApplySearchTerm(request, items); items = ApplySearchTerm(request, items);
@ -440,6 +441,121 @@ namespace MediaBrowser.Api.UserLibrary
return items; 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> /// <summary>
/// Applies the additional filters. /// Applies the additional filters.
/// </summary> /// </summary>
@ -593,13 +709,6 @@ namespace MediaBrowser.Api.UserLibrary
items = items.Where(f => vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase)); 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 // LocationTypes
if (!string.IsNullOrEmpty(request.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)); 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)) if (!string.IsNullOrEmpty(request.NameStartsWithOrGreater))
{ {
items = items.Where(i => string.Compare(request.NameStartsWithOrGreater, i.SortName, StringComparison.CurrentCultureIgnoreCase) < 1); 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) 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) 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; return items;
} }

View File

@ -1,5 +1,6 @@
using MediaBrowser.Common.IO; using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -27,16 +28,18 @@ namespace MediaBrowser.Api.WebSocket
/// The _kernel /// The _kernel
/// </summary> /// </summary>
private readonly ILogManager _logManager; private readonly ILogManager _logManager;
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="LogFileWebSocketListener" /> class. /// Initializes a new instance of the <see cref="LogFileWebSocketListener" /> class.
/// </summary> /// </summary>
/// <param name="logger">The logger.</param> /// <param name="logger">The logger.</param>
/// <param name="logManager">The log manager.</param> /// <param name="logManager">The log manager.</param>
public LogFileWebSocketListener(ILogger logger, ILogManager logManager) public LogFileWebSocketListener(ILogger logger, ILogManager logManager, IFileSystem fileSystem)
: base(logger) : base(logger)
{ {
_logManager = logManager; _logManager = logManager;
_fileSystem = fileSystem;
_logManager.LoggerLoaded += kernel_LoggerLoaded; _logManager.LoggerLoaded += kernel_LoggerLoaded;
} }
@ -53,7 +56,7 @@ namespace MediaBrowser.Api.WebSocket
state.StartLine = 0; 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; state.StartLine += lines.Count;
@ -96,11 +99,11 @@ namespace MediaBrowser.Api.WebSocket
/// <param name="logFilePath">The log file path.</param> /// <param name="logFilePath">The log file path.</param>
/// <param name="startLine">The start line.</param> /// <param name="startLine">The start line.</param>
/// <returns>Task{IEnumerable{System.String}}.</returns> /// <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>(); 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)) 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.Events;
using MediaBrowser.Common.Implementations.Archiving; using MediaBrowser.Common.Implementations.Archiving;
using MediaBrowser.Common.Implementations.IO; using MediaBrowser.Common.Implementations.IO;
@ -7,6 +6,7 @@ using MediaBrowser.Common.Implementations.ScheduledTasks;
using MediaBrowser.Common.Implementations.Security; using MediaBrowser.Common.Implementations.Security;
using MediaBrowser.Common.Implementations.Serialization; using MediaBrowser.Common.Implementations.Serialization;
using MediaBrowser.Common.Implementations.Updates; using MediaBrowser.Common.Implementations.Updates;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Common.ScheduledTasks;
@ -21,6 +21,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Reflection; using System.Reflection;
using System.Threading; using System.Threading;
@ -150,15 +151,17 @@ namespace MediaBrowser.Common.Implementations
/// Gets or sets the installation manager. /// Gets or sets the installation manager.
/// </summary> /// </summary>
/// <value>The installation manager.</value> /// <value>The installation manager.</value>
protected IInstallationManager InstallationManager { get; set; } protected IInstallationManager InstallationManager { get; private set; }
protected IFileSystem FileSystemManager { get; private set; }
/// <summary> /// <summary>
/// Gets or sets the zip client. /// Gets or sets the zip client.
/// </summary> /// </summary>
/// <value>The zip client.</value> /// <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> /// <summary>
/// Initializes a new instance of the <see cref="BaseApplicationHost{TApplicationPathsType}"/> class. /// Initializes a new instance of the <see cref="BaseApplicationHost{TApplicationPathsType}"/> class.
@ -347,7 +350,10 @@ namespace MediaBrowser.Common.Implementations
RegisterSingleInstance(TaskManager); RegisterSingleInstance(TaskManager);
HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, Logger, CreateHttpClient); FileSystemManager = CreateFileSystemManager();
RegisterSingleInstance(FileSystemManager);
HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, Logger, CreateHttpClient, FileSystemManager);
RegisterSingleInstance(HttpClient); RegisterSingleInstance(HttpClient);
NetworkManager = CreateNetworkManager(); 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); protected abstract HttpClient CreateHttpClient(bool enableHttpCompression);
/// <summary> /// <summary>

View File

@ -34,6 +34,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
public delegate HttpClient GetHttpClientHandler(bool enableHttpCompression); public delegate HttpClient GetHttpClientHandler(bool enableHttpCompression);
private readonly GetHttpClientHandler _getHttpClientHandler; private readonly GetHttpClientHandler _getHttpClientHandler;
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HttpClientManager"/> class. /// Initializes a new instance of the <see cref="HttpClientManager"/> class.
@ -46,7 +47,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
/// or /// or
/// logger /// logger
/// </exception> /// </exception>
public HttpClientManager(IApplicationPaths appPaths, ILogger logger, GetHttpClientHandler getHttpClientHandler) public HttpClientManager(IApplicationPaths appPaths, ILogger logger, GetHttpClientHandler getHttpClientHandler, IFileSystem fileSystem)
{ {
if (appPaths == null) if (appPaths == null)
{ {
@ -59,6 +60,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
_logger = logger; _logger = logger;
_getHttpClientHandler = getHttpClientHandler; _getHttpClientHandler = getHttpClientHandler;
_fileSystem = fileSystem;
_appPaths = appPaths; _appPaths = appPaths;
} }
@ -417,7 +419,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
// We're not able to track progress // We're not able to track progress
using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) 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); 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 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); await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false);
} }

View File

@ -1,24 +1,96 @@
using System.Collections.Generic; using MediaBrowser.Common.IO;
using System.Linq;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using System; using System;
using System.Collections.Specialized;
using System.IO; using System.IO;
using System.Text; using System.Text;
namespace MediaBrowser.Controller.IO namespace MediaBrowser.Common.Implementations.IO
{ {
/// <summary> /// <summary>
/// Class FileSystem /// Class CommonFileSystem
/// </summary> /// </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> /// <summary>
/// Gets the file system info. /// Gets the file system info.
/// </summary> /// </summary>
/// <param name="path">The path.</param> /// <param name="path">The path.</param>
/// <returns>FileSystemInfo.</returns> /// <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 // Take a guess to try and avoid two file system hits, but we'll double-check by calling Exists
if (Path.HasExtension(path)) 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> /// <summary>
/// The space char /// The space char
/// </summary> /// </summary>
@ -102,7 +132,7 @@ namespace MediaBrowser.Controller.IO
/// <param name="filename">The filename.</param> /// <param name="filename">The filename.</param>
/// <returns>System.String.</returns> /// <returns>System.String.</returns>
/// <exception cref="System.ArgumentNullException">filename</exception> /// <exception cref="System.ArgumentNullException">filename</exception>
public static string GetValidFilename(string filename) public string GetValidFilename(string filename)
{ {
if (string.IsNullOrEmpty(filename)) if (string.IsNullOrEmpty(filename))
{ {
@ -120,144 +150,71 @@ namespace MediaBrowser.Controller.IO
} }
/// <summary> /// <summary>
/// Resolves the shortcut. /// Gets the creation time UTC.
/// </summary> /// </summary>
/// <param name="filename">The filename.</param> /// <param name="info">The info.</param>
/// <returns>System.String.</returns> /// <returns>DateTime.</returns>
/// <exception cref="System.ArgumentNullException">filename</exception> public DateTime GetCreationTimeUtc(FileSystemInfo info)
public static string ResolveShortcut(string filename)
{ {
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;
} }
catch (Exception ex)
if (string.Equals(Path.GetExtension(filename), ".mblink", StringComparison.OrdinalIgnoreCase))
{ {
return File.ReadAllText(filename); Logger.ErrorException("Error determining CreationTimeUtc for {0}", ex, info.FullName);
} return DateTime.MinValue;
//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)));
} }
} }
/// <summary> /// <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> /// </summary>
/// <param name="path">The path.</param> /// <param name="path">The path.</param>
/// <returns>NameValueCollection.</returns> /// <returns>DateTime.</returns>
public static NameValueCollection ParseIniFile(string path) 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('='); return new FileStream(path, mode, access, share, 4096, true);
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 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"> <Reference Include="SharpCompress">
<HintPath>..\packages\sharpcompress.0.10.1.3\lib\net40\SharpCompress.dll</HintPath> <HintPath>..\packages\sharpcompress.0.10.1.3\lib\net40\SharpCompress.dll</HintPath>
</Reference> </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" />
<Reference Include="System.Configuration" /> <Reference Include="System.Configuration" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
@ -54,9 +58,6 @@
<Reference Include="ServiceStack.Text"> <Reference Include="ServiceStack.Text">
<HintPath>..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll</HintPath> <HintPath>..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll</HintPath>
</Reference> </Reference>
<Reference Include="SimpleInjector">
<HintPath>..\packages\SimpleInjector.2.3.5\lib\net40-client\SimpleInjector.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="..\SharedVersion.cs"> <Compile Include="..\SharedVersion.cs">
@ -68,6 +69,7 @@
<Compile Include="Configuration\BaseConfigurationManager.cs" /> <Compile Include="Configuration\BaseConfigurationManager.cs" />
<Compile Include="HttpClientManager\HttpClientInfo.cs" /> <Compile Include="HttpClientManager\HttpClientInfo.cs" />
<Compile Include="HttpClientManager\HttpClientManager.cs" /> <Compile Include="HttpClientManager\HttpClientManager.cs" />
<Compile Include="IO\CommonFileSystem.cs" />
<Compile Include="IO\IsoManager.cs" /> <Compile Include="IO\IsoManager.cs" />
<Compile Include="Logging\LogHelper.cs" /> <Compile Include="Logging\LogHelper.cs" />
<Compile Include="Logging\NLogger.cs" /> <Compile Include="Logging\NLogger.cs" />

View File

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

View File

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

View File

@ -3,5 +3,5 @@
<package id="NLog" version="2.1.0" targetFramework="net45" /> <package id="NLog" version="2.1.0" targetFramework="net45" />
<package id="ServiceStack.Text" version="3.9.62" targetFramework="net45" /> <package id="ServiceStack.Text" version="3.9.62" targetFramework="net45" />
<package id="sharpcompress" version="0.10.1.3" 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> </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="Events\GenericEventArgs.cs" />
<Compile Include="Extensions\ResourceNotFoundException.cs" /> <Compile Include="Extensions\ResourceNotFoundException.cs" />
<Compile Include="IO\FileSystemRepository.cs" /> <Compile Include="IO\FileSystemRepository.cs" />
<Compile Include="IO\IFileSystem.cs" />
<Compile Include="IO\ProgressStream.cs" /> <Compile Include="IO\ProgressStream.cs" />
<Compile Include="IO\StreamDefaults.cs" /> <Compile Include="IO\StreamDefaults.cs" />
<Compile Include="MediaInfo\MediaInfoResult.cs" /> <Compile Include="MediaInfo\MediaInfoResult.cs" />

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.IO; using MediaBrowser.Controller.IO;
@ -212,6 +213,7 @@ namespace MediaBrowser.Controller.Entities
public static IProviderManager ProviderManager { get; set; } public static IProviderManager ProviderManager { get; set; }
public static ILocalizationManager LocalizationManager { get; set; } public static ILocalizationManager LocalizationManager { get; set; }
public static IItemRepository ItemRepository { get; set; } public static IItemRepository ItemRepository { get; set; }
public static IFileSystem FileSystem { get; set; }
/// <summary> /// <summary>
/// Returns a <see cref="System.String" /> that represents this instance. /// 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) // When resolving the root, we need it's grandchildren (children of user views)
var flattenFolderDepth = isPhysicalRoot ? 2 : 0; 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 // Need to remove subpaths that may have been resolved from shortcuts
// Example: if \\server\movies exists, then strip out \\server\movies\action // Example: if \\server\movies exists, then strip out \\server\movies\action
@ -413,7 +415,7 @@ namespace MediaBrowser.Controller.Entities
} }
//update our dates //update our dates
EntityResolutionHelper.EnsureDates(this, args, false); EntityResolutionHelper.EnsureDates(FileSystem, this, args, false);
IsOffline = false; IsOffline = false;
@ -1337,6 +1339,13 @@ namespace MediaBrowser.Controller.Entities
var data = userManager.GetUserData(user.Id, key); 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.PlayCount = Math.Max(data.PlayCount, 1);
data.LastPlayedDate = datePlayed ?? data.LastPlayedDate; data.LastPlayedDate = datePlayed ?? data.LastPlayedDate;
@ -1530,7 +1539,8 @@ namespace MediaBrowser.Controller.Entities
} }
// Refresh metadata // 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> /// <summary>
@ -1728,7 +1738,7 @@ namespace MediaBrowser.Controller.Entities
if (locationType == LocationType.Remote || if (locationType == LocationType.Remote ||
locationType == LocationType.Virtual) locationType == LocationType.Virtual)
{ {
return File.GetLastWriteTimeUtc(imagePath); return FileSystem.GetLastWriteTimeUtc(imagePath);
} }
var metaFileEntry = ResolveArgs.GetMetaFileByPath(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 // 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 //existing item - check if it has changed
if (currentChild.HasChanged(child)) 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)); 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.Linq;
using System.Runtime.Serialization; using System.Runtime.Serialization;
@ -191,5 +192,23 @@ namespace MediaBrowser.Controller.Entities.TV
return false; 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 MediaBrowser.Controller.Localization;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -147,5 +148,25 @@ namespace MediaBrowser.Controller.Entities.TV
{ {
return IndexNumber != null ? IndexNumber.Value.ToString("0000") : Name; 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 // Ensure it's been lazy loaded
var config = Configuration; 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 MediaBrowser.Model.Logging;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -15,6 +16,7 @@ namespace MediaBrowser.Controller.IO
/// Gets the filtered file system entries. /// Gets the filtered file system entries.
/// </summary> /// </summary>
/// <param name="path">The path.</param> /// <param name="path">The path.</param>
/// <param name="fileSystem">The file system.</param>
/// <param name="logger">The logger.</param> /// <param name="logger">The logger.</param>
/// <param name="args">The args.</param> /// <param name="args">The args.</param>
/// <param name="searchPattern">The search pattern.</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> /// <param name="resolveShortcuts">if set to <c>true</c> [resolve shortcuts].</param>
/// <returns>Dictionary{System.StringFileSystemInfo}.</returns> /// <returns>Dictionary{System.StringFileSystemInfo}.</returns>
/// <exception cref="System.ArgumentNullException">path</exception> /// <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)) if (string.IsNullOrEmpty(path))
{ {
@ -56,9 +58,9 @@ namespace MediaBrowser.Controller.IO
var fullName = entry.FullName; 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)) if (string.IsNullOrWhiteSpace(newPath))
{ {
@ -77,7 +79,7 @@ namespace MediaBrowser.Controller.IO
} }
else if (flattenFolderDepth > 0 && isDirectory) 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; dict[child.Key] = child.Value;
} }

View File

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

View File

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

View File

@ -552,32 +552,6 @@ namespace MediaBrowser.Controller.Providers
} }
break; 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": case "VoteCount":
{ {
var val = reader.ReadElementContentAsString(); var val = reader.ReadElementContentAsString();
@ -592,19 +566,6 @@ namespace MediaBrowser.Controller.Providers
} }
break; 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": case "MusicbrainzId":
{ {
var mbz = reader.ReadElementContentAsString(); 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.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
@ -52,6 +53,16 @@ namespace MediaBrowser.Controller.Providers
/// Adds the metadata providers. /// Adds the metadata providers.
/// </summary> /// </summary>
/// <param name="providers">The providers.</param> /// <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.IO;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using System; using System;
@ -44,7 +45,8 @@ namespace MediaBrowser.Controller.Resolvers
".f4v", ".f4v",
".3gp", ".3gp",
".webm", ".webm",
".mts" ".mts",
".rec"
}; };
private static readonly Dictionary<string, string> VideoFileExtensionsDictionary = VideoFileExtensions.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, string> VideoFileExtensionsDictionary = VideoFileExtensions.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
@ -125,10 +127,11 @@ namespace MediaBrowser.Controller.Resolvers
/// <summary> /// <summary>
/// Ensures DateCreated and DateModified have values /// Ensures DateCreated and DateModified have values
/// </summary> /// </summary>
/// <param name="fileSystem">The file system.</param>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="args">The args.</param> /// <param name="args">The args.</param>
/// <param name="includeCreationTime">if set to <c>true</c> [include creation time].</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)) if (!Path.IsPathRooted(item.Path))
{ {
@ -144,22 +147,22 @@ namespace MediaBrowser.Controller.Resolvers
{ {
if (includeCreationTime) if (includeCreationTime)
{ {
item.DateCreated = childData.CreationTimeUtc; item.DateCreated = fileSystem.GetCreationTimeUtc(childData);
} }
item.DateModified = childData.LastWriteTimeUtc; item.DateModified = fileSystem.GetLastWriteTimeUtc(childData);
} }
else else
{ {
var fileData = FileSystem.GetFileSystemInfo(item.Path); var fileData = fileSystem.GetFileSystemInfo(item.Path);
if (fileData.Exists) if (fileData.Exists)
{ {
if (includeCreationTime) 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) 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"> <Compile Include="..\MediaBrowser.Model\Plugins\PluginInfo.cs">
<Link>Plugins\PluginInfo.cs</Link> <Link>Plugins\PluginInfo.cs</Link>
</Compile> </Compile>
<Compile Include="..\MediaBrowser.Model\Providers\RemoteImageInfo.cs">
<Link>Providers\RemoteImageInfo.cs</Link>
</Compile>
<Compile Include="..\MediaBrowser.Model\Querying\ArtistsQuery.cs"> <Compile Include="..\MediaBrowser.Model\Querying\ArtistsQuery.cs">
<Link>Querying\ArtistsQuery.cs</Link> <Link>Querying\ArtistsQuery.cs</Link>
</Compile> </Compile>

View File

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

View File

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

View File

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

View File

@ -59,6 +59,7 @@
<Compile Include="Dto\ItemByNameCounts.cs" /> <Compile Include="Dto\ItemByNameCounts.cs" />
<Compile Include="Dto\ItemCounts.cs" /> <Compile Include="Dto\ItemCounts.cs" />
<Compile Include="Dto\ItemIndex.cs" /> <Compile Include="Dto\ItemIndex.cs" />
<Compile Include="Providers\RemoteImageInfo.cs" />
<Compile Include="Dto\StudioDto.cs" /> <Compile Include="Dto\StudioDto.cs" />
<Compile Include="Entities\CollectionType.cs" /> <Compile Include="Entities\CollectionType.cs" />
<Compile Include="Entities\ItemReview.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> /// </summary>
/// <value>The location types.</value> /// <value>The location types.</value>
public LocationType[] LocationTypes { get; set; } 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> /// <summary>
/// Gets or sets the exclude location types. /// Gets or sets the exclude location types.
/// </summary> /// </summary>
/// <value>The exclude location types.</value> /// <value>The exclude location types.</value>
public LocationType[] ExcludeLocationTypes { get; set; } public LocationType[] ExcludeLocationTypes { get; set; }
public bool? HasPremiereDate { get; set; }
public DateTime? MinPremiereDate { get; set; }
public DateTime? MaxPremiereDate { get; set; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ItemQuery" /> class. /// Initializes a new instance of the <see cref="ItemQuery" /> class.
/// </summary> /// </summary>

View File

@ -1,6 +1,4 @@
using MediaBrowser.Model.Entities; 
using System;
namespace MediaBrowser.Model.Querying namespace MediaBrowser.Model.Querying
{ {
public class NextUpQuery public class NextUpQuery
@ -11,6 +9,12 @@ namespace MediaBrowser.Model.Querying
/// <value>The user id.</value> /// <value>The user id.</value>
public string UserId { get; set; } public string UserId { get; set; }
/// <summary>
/// Gets or sets the series id.
/// </summary>
/// <value>The series id.</value>
public string SeriesId { get; set; }
/// <summary> /// <summary>
/// Skips over a given number of items within the results. Use for paging. /// Skips over a given number of items within the results. Use for paging.
/// </summary> /// </summary>
@ -28,20 +32,5 @@ namespace MediaBrowser.Model.Querying
/// </summary> /// </summary>
/// <value>The fields.</value> /// <value>The fields.</value>
public ItemFields[] Fields { get; set; } 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> <Properties>
<MonoDevelop.Ide.Workspace ActiveConfiguration="Release|x86" /> <MonoDevelop.Ide.Workspace ActiveConfiguration="Debug|x86" />
<MonoDevelop.Ide.Workbench ActiveDocument="MediaBrowser.Server.Mono\Program.cs"> <MonoDevelop.Ide.Workbench ActiveDocument="MediaBrowser.Server.Mono\Program.cs">
<Files> <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> </Files>
<Pads> <Pads>
<Pad Id="ProjectPad"> <Pad Id="ProjectPad">
<State expanded="True"> <State expanded="True">
<Node name="MediaBrowser.Common.Implementations" expanded="True"> <Node name="MediaBrowser.Common" expanded="True" />
<Node name="HttpClientManager" expanded="True" /> <Node name="MediaBrowser.Common.Implementations" expanded="True" />
</Node> <Node name="MediaBrowser.Controller" expanded="True" />
<Node name="MediaBrowser.Controller" expanded="True">
<Node name="Drawing" expanded="True" />
</Node>
<Node name="MediaBrowser.Model" expanded="True"> <Node name="MediaBrowser.Model" expanded="True">
<Node name="References" expanded="True" /> <Node name="References" expanded="True" />
<Node name="Web" expanded="True" /> <Node name="Web" expanded="True" />
</Node> </Node>
<Node name="MediaBrowser.Server.Implementations" expanded="True" /> <Node name="MediaBrowser.Server.Implementations" expanded="True" />
<Node name="MediaBrowser.Server.Mono" 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 name="Program.cs" selected="True" />
</Node> </Node>
</State> </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.Entities;
using MediaBrowser.Controller.IO; using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Providers;
@ -17,10 +18,12 @@ namespace MediaBrowser.Providers
public class FolderProviderFromXml : BaseMetadataProvider public class FolderProviderFromXml : BaseMetadataProvider
{ {
public static FolderProviderFromXml Current; 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) : base(logManager, configurationManager)
{ {
_fileSystem = fileSystem;
Current = this; Current = this;
} }
@ -53,7 +56,7 @@ namespace MediaBrowser.Providers
return false; return false;
} }
return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed; return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
} }
/// <summary> /// <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.Entities;
using MediaBrowser.Controller.IO; using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Savers;
using System; using System;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Providers.Savers;
namespace MediaBrowser.Providers.Games namespace MediaBrowser.Providers.Games
{ {
public class GameProviderFromXml : BaseMetadataProvider public class GameProviderFromXml : BaseMetadataProvider
{ {
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="logManager"></param> /// <param name="logManager"></param>
/// <param name="configurationManager"></param> /// <param name="configurationManager"></param>
public GameProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager) public GameProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
: base(logManager, configurationManager) : base(logManager, configurationManager)
{ {
_fileSystem = fileSystem;
} }
/// <summary> /// <summary>
@ -45,7 +48,7 @@ namespace MediaBrowser.Providers.Games
return false; return false;
} }
return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed; return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
} }
/// <summary> /// <summary>
@ -78,7 +81,7 @@ namespace MediaBrowser.Providers.Games
try try
{ {
new BaseItemXmlParser<Game>(Logger).Fetch(game, metaFile, cancellationToken); new GameXmlParser(Logger).Fetch(game, metaFile, cancellationToken);
} }
finally 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.Entities;
using MediaBrowser.Controller.IO; using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Providers;
@ -14,10 +15,12 @@ namespace MediaBrowser.Providers.Games
public class GameSystemProviderFromXml : BaseMetadataProvider public class GameSystemProviderFromXml : BaseMetadataProvider
{ {
internal static GameSystemProviderFromXml Current { get; private set; } 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) : base(logManager, configurationManager)
{ {
_fileSystem = fileSystem;
Current = this; Current = this;
} }
@ -50,7 +53,7 @@ namespace MediaBrowser.Providers.Games
return false; return false;
} }
return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed; return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
} }
/// <summary> /// <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.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO; using MediaBrowser.Controller.IO;
@ -18,9 +19,12 @@ namespace MediaBrowser.Providers
/// </summary> /// </summary>
public class ImagesByNameProvider : ImageFromMediaLocationProvider 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) : base(logManager, configurationManager)
{ {
_fileSystem = fileSystem;
} }
public override ItemUpdateType ItemUpdateType public override ItemUpdateType ItemUpdateType
@ -110,8 +114,8 @@ namespace MediaBrowser.Providers
return files.Select(f => return files.Select(f =>
{ {
var lastWriteTime = FileSystem.GetLastWriteTimeUtc(f, Logger); var lastWriteTime = _fileSystem.GetLastWriteTimeUtc(f);
var creationTime = FileSystem.GetCreationTimeUtc(f, Logger); var creationTime = _fileSystem.GetCreationTimeUtc(f);
return creationTime > lastWriteTime ? creationTime : lastWriteTime; return creationTime > lastWriteTime ? creationTime : lastWriteTime;
@ -150,7 +154,7 @@ namespace MediaBrowser.Providers
/// <returns>System.String.</returns> /// <returns>System.String.</returns>
protected string GetLocation(BaseItem item) protected string GetLocation(BaseItem item)
{ {
var name = FileSystem.GetValidFilename(item.Name); var name = _fileSystem.GetValidFilename(item.Name);
return Path.Combine(ConfigurationManager.ApplicationPaths.GeneralPath, name); return Path.Combine(ConfigurationManager.ApplicationPaths.GeneralPath, name);
} }

View File

@ -49,6 +49,7 @@
<ItemGroup> <ItemGroup>
<Compile Include="FanartBaseProvider.cs" /> <Compile Include="FanartBaseProvider.cs" />
<Compile Include="FolderProviderFromXml.cs" /> <Compile Include="FolderProviderFromXml.cs" />
<Compile Include="Games\GameXmlParser.cs" />
<Compile Include="Games\GameProviderFromXml.cs" /> <Compile Include="Games\GameProviderFromXml.cs" />
<Compile Include="Games\GameSystemProviderFromXml.cs" /> <Compile Include="Games\GameSystemProviderFromXml.cs" />
<Compile Include="ImageFromMediaLocationProvider.cs" /> <Compile Include="ImageFromMediaLocationProvider.cs" />
@ -59,6 +60,7 @@
<Compile Include="MediaInfo\FFProbeVideoInfoProvider.cs" /> <Compile Include="MediaInfo\FFProbeVideoInfoProvider.cs" />
<Compile Include="MediaInfo\VideoImageProvider.cs" /> <Compile Include="MediaInfo\VideoImageProvider.cs" />
<Compile Include="Movies\BoxSetProviderFromXml.cs" /> <Compile Include="Movies\BoxSetProviderFromXml.cs" />
<Compile Include="Movies\ManualMovieDbImageProvider.cs" />
<Compile Include="Movies\MovieUpdatesPrescanTask.cs" /> <Compile Include="Movies\MovieUpdatesPrescanTask.cs" />
<Compile Include="Movies\MovieXmlParser.cs" /> <Compile Include="Movies\MovieXmlParser.cs" />
<Compile Include="Movies\FanArtMovieProvider.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;
using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.IO; using MediaBrowser.Controller.IO;
@ -18,10 +19,12 @@ namespace MediaBrowser.Providers.Movies
public class BoxSetProviderFromXml : BaseMetadataProvider public class BoxSetProviderFromXml : BaseMetadataProvider
{ {
public static BoxSetProviderFromXml Current; 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) : base(logManager, configurationManager)
{ {
_fileSystem = fileSystem;
Current = this; Current = this;
} }
@ -54,7 +57,7 @@ namespace MediaBrowser.Providers.Movies
return false; return false;
} }
return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed; return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
} }
/// <summary> /// <summary>

View File

@ -4,6 +4,7 @@ using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
@ -40,6 +41,7 @@ namespace MediaBrowser.Providers.Movies
private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
internal static FanArtMovieProvider Current { get; private set; } internal static FanArtMovieProvider Current { get; private set; }
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="FanArtMovieProvider" /> class. /// 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="configurationManager">The configuration manager.</param>
/// <param name="providerManager">The provider manager.</param> /// <param name="providerManager">The provider manager.</param>
/// <exception cref="System.ArgumentNullException">httpClient</exception> /// <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) : base(logManager, configurationManager)
{ {
if (httpClient == null) if (httpClient == null)
@ -58,6 +60,7 @@ namespace MediaBrowser.Providers.Movies
} }
HttpClient = httpClient; HttpClient = httpClient;
_providerManager = providerManager; _providerManager = providerManager;
_fileSystem = fileSystem;
Current = this; Current = this;
} }
@ -174,7 +177,7 @@ namespace MediaBrowser.Providers.Movies
{ {
var files = new DirectoryInfo(path) var files = new DirectoryInfo(path)
.EnumerateFiles("*.xml", SearchOption.TopDirectoryOnly) .EnumerateFiles("*.xml", SearchOption.TopDirectoryOnly)
.Select(i => i.LastWriteTimeUtc) .Select(i => _fileSystem.GetLastWriteTimeUtc(i))
.ToList(); .ToList();
if (files.Count > 0) if (files.Count > 0)
@ -275,7 +278,7 @@ namespace MediaBrowser.Providers.Movies
}).ConfigureAwait(false)) }).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); await response.CopyToAsync(xmlFileStream).ConfigureAwait(false);
} }
@ -300,14 +303,14 @@ namespace MediaBrowser.Providers.Movies
string path; 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") ?? var node = doc.SelectSingleNode("//fanart/movie/movieposters/movieposter[@lang = \"" + language + "\"]/@url") ??
doc.SelectSingleNode("//fanart/movie/movieposters/movieposter/@url"); doc.SelectSingleNode("//fanart/movie/movieposters/movieposter/@url");
path = node != null ? node.Value : null; path = node != null ? node.Value : null;
if (!string.IsNullOrEmpty(path)) 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); .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.Configuration;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
@ -32,15 +33,17 @@ namespace MediaBrowser.Providers.Movies
/// </summary> /// </summary>
private readonly IServerConfigurationManager _config; private readonly IServerConfigurationManager _config;
private readonly IJsonSerializer _jsonSerializer; private readonly IJsonSerializer _jsonSerializer;
private readonly IFileSystem _fileSystem;
private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); 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; _jsonSerializer = jsonSerializer;
_config = config; _config = config;
_logger = logger; _logger = logger;
_httpClient = httpClient; _httpClient = httpClient;
_fileSystem = fileSystem;
} }
/// <summary> /// <summary>
@ -66,7 +69,7 @@ namespace MediaBrowser.Providers.Movies
var timestampFileInfo = new FileInfo(timestampFile); var timestampFileInfo = new FileInfo(timestampFile);
// Don't check for tvdb updates anymore frequently than 24 hours // 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; 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.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.Movies;
@ -6,6 +7,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Serialization;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -21,11 +23,6 @@ namespace MediaBrowser.Providers.Movies
/// </summary> /// </summary>
public class MovieDbImagesProvider : BaseMetadataProvider 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> /// <summary>
/// The _provider manager /// The _provider manager
/// </summary> /// </summary>
@ -35,6 +32,7 @@ namespace MediaBrowser.Providers.Movies
/// The _json serializer /// The _json serializer
/// </summary> /// </summary>
private readonly IJsonSerializer _jsonSerializer; private readonly IJsonSerializer _jsonSerializer;
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="MovieDbImagesProvider"/> class. /// 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="configurationManager">The configuration manager.</param>
/// <param name="providerManager">The provider manager.</param> /// <param name="providerManager">The provider manager.</param>
/// <param name="jsonSerializer">The json serializer.</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) : base(logManager, configurationManager)
{ {
_providerManager = providerManager; _providerManager = providerManager;
_jsonSerializer = jsonSerializer; _jsonSerializer = jsonSerializer;
_fileSystem = fileSystem;
} }
/// <summary> /// <summary>
@ -65,6 +64,11 @@ namespace MediaBrowser.Providers.Movies
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
public override bool Supports(BaseItem item) public override bool Supports(BaseItem item)
{
return SupportsItem(item);
}
public static bool SupportsItem(BaseItem item)
{ {
var trailer = item as Trailer; var trailer = item as Trailer;
@ -149,7 +153,7 @@ namespace MediaBrowser.Providers.Movies
{ {
return false; return false;
} }
var path = MovieDbProvider.Current.GetDataFilePath(item, "default"); var path = MovieDbProvider.Current.GetDataFilePath(item, "default");
if (!string.IsNullOrEmpty(path)) if (!string.IsNullOrEmpty(path))
@ -158,7 +162,7 @@ namespace MediaBrowser.Providers.Movies
if (fileInfo.Exists) 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 id = item.GetProviderId(MetadataProviders.Tmdb);
var status = ProviderRefreshStatus.Success;
if (!string.IsNullOrEmpty(id)) if (!string.IsNullOrEmpty(id))
{ {
var images = FetchImages(item); var images = await new ManualMovieDbImageProvider(_jsonSerializer, ConfigurationManager).GetAllImages(item,
cancellationToken).ConfigureAwait(false);
if (images != null) await ProcessImages(item, images.ToList(), cancellationToken).ConfigureAwait(false);
{
status = await ProcessImages(item, images, cancellationToken).ConfigureAwait(false);
}
} }
SetLastRefreshed(item, DateTime.UtcNow, status); SetLastRefreshed(item, DateTime.UtcNow);
return true; 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> /// <summary>
/// Processes the images. /// Processes the images.
/// </summary> /// </summary>
@ -221,68 +199,36 @@ namespace MediaBrowser.Providers.Movies
/// <param name="images">The images.</param> /// <param name="images">The images.</param>
/// <param name="cancellationToken">The cancellation token</param> /// <param name="cancellationToken">The cancellation token</param>
/// <returns>Task.</returns> /// <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(); cancellationToken.ThrowIfCancellationRequested();
var status = ProviderRefreshStatus.Success; var eligiblePosters = images
.Where(i => i.Type == ImageType.Primary)
var eligiblePosters = images.posters == null ?
new List<MovieDbProvider.Poster>() :
images.posters.Where(i => i.width >= ConfigurationManager.Configuration.MinMoviePosterWidth)
.ToList(); .ToList();
eligiblePosters = eligiblePosters.OrderByDescending(i => i.vote_average).ToList();
// poster // poster
if (eligiblePosters.Count > 0 && !item.HasImage(ImageType.Primary)) 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"; var url = poster.Url;
// get highest rated poster for our language
var poster = eligiblePosters.FirstOrDefault(p => string.Equals(p.iso_639_1, ConfigurationManager.Configuration.PreferredMetadataLanguage, StringComparison.OrdinalIgnoreCase)); var img = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions
if (poster == null)
{ {
// couldn't find our specific language, find english Url = url,
poster = eligiblePosters.FirstOrDefault(p => string.Equals(p.iso_639_1, "en", StringComparison.OrdinalIgnoreCase)); CancellationToken = cancellationToken
}
if (poster == null) }).ConfigureAwait(false);
{
//still couldn't find it - try highest rated null one
poster = eligiblePosters.FirstOrDefault(p => p.iso_639_1 == null);
}
if (poster == null) await _providerManager.SaveImage(item, img, MimeTypes.GetMimeType(url), ImageType.Primary, null, url, cancellationToken)
{ .ConfigureAwait(false);
//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);
}
} }
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
var eligibleBackdrops = images.backdrops == null ? new List<MovieDbProvider.Backdrop>() : var eligibleBackdrops = images
images.backdrops.Where(i => i.width >= ConfigurationManager.Configuration.MinMovieBackdropWidth) .Where(i => i.Type == ImageType.Backdrop)
.ToList(); .ToList();
var backdropLimit = ConfigurationManager.Configuration.MaxBackdrops; var backdropLimit = ConfigurationManager.Configuration.MaxBackdrops;
@ -290,13 +236,9 @@ namespace MediaBrowser.Providers.Movies
// backdrops - only download if earlier providers didn't find any (fanart) // backdrops - only download if earlier providers didn't find any (fanart)
if (eligibleBackdrops.Count > 0 && ConfigurationManager.Configuration.DownloadMovieImages.Backdrops && item.BackdropImagePaths.Count < backdropLimit) 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++) for (var i = 0; i < eligibleBackdrops.Count; i++)
{ {
var url = tmdbImageUrl + eligibleBackdrops[i].file_path; var url = eligibleBackdrops[i].Url;
if (!item.ContainsImageWithSourceUrl(url)) if (!item.ContainsImageWithSourceUrl(url))
{ {
@ -307,7 +249,7 @@ namespace MediaBrowser.Providers.Movies
}).ConfigureAwait(false); }).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); .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.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
@ -47,6 +48,7 @@ namespace MediaBrowser.Providers.Movies
/// </summary> /// </summary>
/// <value>The HTTP client.</value> /// <value>The HTTP client.</value>
protected IHttpClient HttpClient { get; private set; } protected IHttpClient HttpClient { get; private set; }
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="MovieDbProvider" /> class. /// 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="jsonSerializer">The json serializer.</param>
/// <param name="httpClient">The HTTP client.</param> /// <param name="httpClient">The HTTP client.</param>
/// <param name="providerManager">The provider manager.</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) : base(logManager, configurationManager)
{ {
JsonSerializer = jsonSerializer; JsonSerializer = jsonSerializer;
HttpClient = httpClient; HttpClient = httpClient;
ProviderManager = providerManager; ProviderManager = providerManager;
_fileSystem = fileSystem;
Current = this; Current = this;
} }
@ -189,6 +192,7 @@ namespace MediaBrowser.Providers.Movies
static readonly Regex[] NameMatches = new[] { 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})\)"), // 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 new Regex(@"(?<name>.*)") // last resort matches the whole string as the name
}; };
@ -215,7 +219,7 @@ namespace MediaBrowser.Providers.Movies
if (fileInfo.Exists) if (fileInfo.Exists)
{ {
return fileInfo.LastWriteTimeUtc > providerInfo.LastRefreshed; return _fileSystem.GetLastWriteTimeUtc(fileInfo) > providerInfo.LastRefreshed;
} }
return true; return true;
@ -320,7 +324,7 @@ namespace MediaBrowser.Providers.Movies
/// <param name="name">The name.</param> /// <param name="name">The name.</param>
/// <param name="justName">Name of the just.</param> /// <param name="justName">Name of the just.</param>
/// <param name="year">The year.</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; justName = null;
year = 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;
using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
@ -21,11 +21,13 @@ namespace MediaBrowser.Providers.Movies
{ {
internal static MovieProviderFromXml Current { get; private set; } internal static MovieProviderFromXml Current { get; private set; }
private readonly IItemRepository _itemRepo; 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) : base(logManager, configurationManager)
{ {
_itemRepo = itemRepo; _itemRepo = itemRepo;
_fileSystem = fileSystem;
Current = this; Current = this;
} }
@ -71,7 +73,7 @@ namespace MediaBrowser.Providers.Movies
return false; return false;
} }
return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed; return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
} }
/// <summary> /// <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.Common.Progress;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
@ -35,6 +36,7 @@ namespace MediaBrowser.Providers.Movies
/// </summary> /// </summary>
private readonly IServerConfigurationManager _config; private readonly IServerConfigurationManager _config;
private readonly IJsonSerializer _json; private readonly IJsonSerializer _json;
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="MovieUpdatesPreScanTask"/> class. /// 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="httpClient">The HTTP client.</param>
/// <param name="config">The config.</param> /// <param name="config">The config.</param>
/// <param name="json">The json.</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; _logger = logger;
_httpClient = httpClient; _httpClient = httpClient;
_config = config; _config = config;
_json = json; _json = json;
_fileSystem = fileSystem;
} }
protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
@ -100,7 +103,7 @@ namespace MediaBrowser.Providers.Movies
var refreshDays = _config.Configuration.EnableTmdbUpdates ? 1 : 7; var refreshDays = _config.Configuration.EnableTmdbUpdates ? 1 : 7;
// Don't check for tvdb updates anymore frequently than 24 hours // 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; 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.Entities;
using MediaBrowser.Controller.IO; using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Providers;
@ -13,10 +14,12 @@ namespace MediaBrowser.Providers.Movies
class PersonProviderFromXml : BaseMetadataProvider class PersonProviderFromXml : BaseMetadataProvider
{ {
internal static PersonProviderFromXml Current { get; private set; } 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) : base(logManager, configurationManager)
{ {
_fileSystem = fileSystem;
Current = this; Current = this;
} }
@ -49,7 +52,7 @@ namespace MediaBrowser.Providers.Movies
return false; return false;
} }
return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed; return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
} }
/// <summary> /// <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.Configuration;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
@ -34,6 +35,7 @@ namespace MediaBrowser.Providers.Movies
/// </summary> /// </summary>
private readonly IServerConfigurationManager _config; private readonly IServerConfigurationManager _config;
private readonly IJsonSerializer _json; private readonly IJsonSerializer _json;
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PersonUpdatesPreScanTask"/> class. /// 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="logger">The logger.</param>
/// <param name="httpClient">The HTTP client.</param> /// <param name="httpClient">The HTTP client.</param>
/// <param name="config">The config.</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; _logger = logger;
_httpClient = httpClient; _httpClient = httpClient;
_config = config; _config = config;
_json = json; _json = json;
_fileSystem = fileSystem;
} }
protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
@ -74,7 +77,7 @@ namespace MediaBrowser.Providers.Movies
var timestampFileInfo = new FileInfo(timestampFile); var timestampFileInfo = new FileInfo(timestampFile);
// Don't check for tvdb updates anymore frequently than 24 hours // 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; return;
} }

View File

@ -30,8 +30,9 @@ namespace MediaBrowser.Providers.Movies
internal static TmdbPersonProvider Current { get; private set; } internal static TmdbPersonProvider Current { get; private set; }
const string DataFileName = "info.json"; 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) : base(logManager, configurationManager)
{ {
if (jsonSerializer == null) if (jsonSerializer == null)
@ -40,6 +41,7 @@ namespace MediaBrowser.Providers.Movies
} }
JsonSerializer = jsonSerializer; JsonSerializer = jsonSerializer;
ProviderManager = providerManager; ProviderManager = providerManager;
_fileSystem = fileSystem;
Current = this; Current = this;
} }
@ -105,7 +107,7 @@ namespace MediaBrowser.Providers.Movies
if (fileInfo.Exists) if (fileInfo.Exists)
{ {
return fileInfo.LastWriteTimeUtc > providerInfo.LastRefreshed; return _fileSystem.GetLastWriteTimeUtc(fileInfo) > providerInfo.LastRefreshed;
} }
return true; return true;
@ -270,7 +272,7 @@ namespace MediaBrowser.Providers.Movies
{ {
Directory.CreateDirectory(personDataPath); 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); 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;
using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.IO; using MediaBrowser.Controller.IO;
@ -15,10 +16,12 @@ namespace MediaBrowser.Providers.Music
class ArtistProviderFromXml : BaseMetadataProvider class ArtistProviderFromXml : BaseMetadataProvider
{ {
public static ArtistProviderFromXml Current; 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) : base(logManager, configurationManager)
{ {
_fileSystem = fileSystem;
Current = this; Current = this;
} }
@ -51,7 +54,7 @@ namespace MediaBrowser.Providers.Music
return false; return false;
} }
return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed; return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
} }
/// <summary> /// <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.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Audio;
@ -37,6 +38,7 @@ namespace MediaBrowser.Providers.Music
protected IHttpClient HttpClient { get; private set; } protected IHttpClient HttpClient { get; private set; }
internal static FanArtAlbumProvider Current { get; private set; } internal static FanArtAlbumProvider Current { get; private set; }
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="FanArtAlbumProvider"/> class. /// 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="logManager">The log manager.</param>
/// <param name="configurationManager">The configuration manager.</param> /// <param name="configurationManager">The configuration manager.</param>
/// <param name="providerManager">The provider 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) : base(logManager, configurationManager)
{ {
_providerManager = providerManager; _providerManager = providerManager;
_fileSystem = fileSystem;
HttpClient = httpClient; HttpClient = httpClient;
Current = this; Current = this;
@ -140,7 +143,7 @@ namespace MediaBrowser.Providers.Music
if (file.Exists) 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.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
@ -15,12 +17,8 @@ namespace MediaBrowser.Providers.Music
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="FanArtArtistByNameProvider" /> class. /// Initializes a new instance of the <see cref="FanArtArtistByNameProvider" /> class.
/// </summary> /// </summary>
/// <param name="httpClient">The HTTP client.</param> public FanArtArtistByNameProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
/// <param name="logManager">The log manager.</param> : base(httpClient, logManager, configurationManager, providerManager, fileSystem)
/// <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)
{ {
} }

View File

@ -1,24 +1,23 @@
using System.Net; using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO; using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net;
using System; using System;
using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml; using System.Xml;
using MediaBrowser.Model.Net;
namespace MediaBrowser.Providers.Music namespace MediaBrowser.Providers.Music
{ {
@ -39,6 +38,7 @@ namespace MediaBrowser.Providers.Music
private readonly IProviderManager _providerManager; private readonly IProviderManager _providerManager;
internal static FanArtArtistProvider Current; internal static FanArtArtistProvider Current;
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="FanArtArtistProvider"/> class. /// 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="configurationManager">The configuration manager.</param>
/// <param name="providerManager">The provider manager.</param> /// <param name="providerManager">The provider manager.</param>
/// <exception cref="System.ArgumentNullException">httpClient</exception> /// <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) : base(logManager, configurationManager)
{ {
if (httpClient == null) if (httpClient == null)
@ -57,6 +57,7 @@ namespace MediaBrowser.Providers.Music
} }
HttpClient = httpClient; HttpClient = httpClient;
_providerManager = providerManager; _providerManager = providerManager;
_fileSystem = fileSystem;
Current = this; Current = this;
} }
@ -167,7 +168,7 @@ namespace MediaBrowser.Providers.Music
{ {
var files = new DirectoryInfo(path) var files = new DirectoryInfo(path)
.EnumerateFiles("*.xml", SearchOption.TopDirectoryOnly) .EnumerateFiles("*.xml", SearchOption.TopDirectoryOnly)
.Select(i => i.LastWriteTimeUtc) .Select(i => _fileSystem.GetLastWriteTimeUtc(i))
.ToList(); .ToList();
if (files.Count > 0) if (files.Count > 0)
@ -284,7 +285,7 @@ namespace MediaBrowser.Providers.Music
}).ConfigureAwait(false)) }).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); 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.Configuration;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
@ -31,15 +32,17 @@ namespace MediaBrowser.Providers.Music
/// </summary> /// </summary>
private readonly IServerConfigurationManager _config; private readonly IServerConfigurationManager _config;
private readonly IJsonSerializer _jsonSerializer; private readonly IJsonSerializer _jsonSerializer;
private readonly IFileSystem _fileSystem;
private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); 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; _jsonSerializer = jsonSerializer;
_config = config; _config = config;
_logger = logger; _logger = logger;
_httpClient = httpClient; _httpClient = httpClient;
_fileSystem = fileSystem;
} }
/// <summary> /// <summary>
@ -65,7 +68,7 @@ namespace MediaBrowser.Providers.Music
var timestampFileInfo = new FileInfo(timestampFile); var timestampFileInfo = new FileInfo(timestampFile);
// Don't check for tvdb updates anymore frequently than 24 hours // 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; 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.Controller.Library;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using System; using System;
@ -22,15 +23,18 @@ namespace MediaBrowser.Providers
/// </summary> /// </summary>
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RefreshIntrosTask"/> class. /// Initializes a new instance of the <see cref="RefreshIntrosTask"/> class.
/// </summary> /// </summary>
/// <param name="libraryManager">The library manager.</param> /// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param> /// <param name="logger">The logger.</param>
public RefreshIntrosTask(ILibraryManager libraryManager, ILogger logger) public RefreshIntrosTask(ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem)
{ {
_libraryManager = libraryManager; _libraryManager = libraryManager;
_logger = logger; _logger = logger;
_fileSystem = fileSystem;
} }
/// <summary> /// <summary>
@ -77,7 +81,7 @@ namespace MediaBrowser.Providers
/// <returns>Task.</returns> /// <returns>Task.</returns>
private async Task RefreshIntro(string path, CancellationToken cancellationToken) 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) if (item == null)
{ {

View File

@ -1,6 +1,7 @@
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities;
using MediaBrowser.Providers.Movies; using MediaBrowser.Providers.Movies;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -70,6 +71,20 @@ namespace MediaBrowser.Providers.Savers
builder.Append("<GameSystem>" + SecurityElement.Escape(game.GameSystem) + "</GameSystem>"); 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); XmlSaverHelpers.AddCommonNodes(item, builder);
builder.Append("</Item>"); builder.Append("</Item>");
@ -79,7 +94,9 @@ namespace MediaBrowser.Providers.Savers
XmlSaverHelpers.Save(builder, xmlFilePath, new List<string> XmlSaverHelpers.Save(builder, xmlFilePath, new List<string>
{ {
"Players", "Players",
"GameSystem" "GameSystem",
"NesBox",
"NesBoxRom"
}); });
// Set last refreshed so that the provider doesn't trigger after the file save // 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;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.IO; using MediaBrowser.Controller.IO;
@ -20,11 +21,13 @@ namespace MediaBrowser.Providers.TV
{ {
internal static EpisodeProviderFromXml Current { get; private set; } internal static EpisodeProviderFromXml Current { get; private set; }
private readonly IItemRepository _itemRepo; 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) : base(logManager, configurationManager)
{ {
_itemRepo = itemRepo; _itemRepo = itemRepo;
_fileSystem = fileSystem;
Current = this; Current = this;
} }
@ -76,7 +79,7 @@ namespace MediaBrowser.Providers.TV
return false; return false;
} }
return FileSystem.GetLastWriteTimeUtc(file, Logger) > providerInfo.LastRefreshed; return _fileSystem.GetLastWriteTimeUtc(file) > providerInfo.LastRefreshed;
} }
/// <summary> /// <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;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
@ -22,6 +23,7 @@ namespace MediaBrowser.Providers.TV
/// The _provider manager /// The _provider manager
/// </summary> /// </summary>
private readonly IProviderManager _providerManager; private readonly IProviderManager _providerManager;
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="FanArtSeasonProvider"/> class. /// 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="logManager">The log manager.</param>
/// <param name="configurationManager">The configuration manager.</param> /// <param name="configurationManager">The configuration manager.</param>
/// <param name="providerManager">The provider 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) : base(logManager, configurationManager)
{ {
_providerManager = providerManager; _providerManager = providerManager;
_fileSystem = fileSystem;
} }
public override ItemUpdateType ItemUpdateType public override ItemUpdateType ItemUpdateType
@ -76,7 +79,7 @@ namespace MediaBrowser.Providers.TV
if (imagesFileInfo.Exists) 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.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
@ -31,8 +32,9 @@ namespace MediaBrowser.Providers.TV
protected IHttpClient HttpClient { get; private set; } protected IHttpClient HttpClient { get; private set; }
private readonly IProviderManager _providerManager; 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) : base(logManager, configurationManager)
{ {
if (httpClient == null) if (httpClient == null)
@ -41,6 +43,7 @@ namespace MediaBrowser.Providers.TV
} }
HttpClient = httpClient; HttpClient = httpClient;
_providerManager = providerManager; _providerManager = providerManager;
_fileSystem = fileSystem;
Current = this; Current = this;
} }
@ -115,7 +118,7 @@ namespace MediaBrowser.Providers.TV
{ {
var files = new DirectoryInfo(path) var files = new DirectoryInfo(path)
.EnumerateFiles("*.xml", SearchOption.TopDirectoryOnly) .EnumerateFiles("*.xml", SearchOption.TopDirectoryOnly)
.Select(i => i.LastWriteTimeUtc) .Select(i => _fileSystem.GetLastWriteTimeUtc(i))
.ToList(); .ToList();
if (files.Count > 0) if (files.Count > 0)
@ -353,7 +356,7 @@ namespace MediaBrowser.Providers.TV
}).ConfigureAwait(false)) }).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); 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.Configuration;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
@ -32,15 +33,17 @@ namespace MediaBrowser.Providers.TV
/// </summary> /// </summary>
private readonly IServerConfigurationManager _config; private readonly IServerConfigurationManager _config;
private readonly IJsonSerializer _jsonSerializer; private readonly IJsonSerializer _jsonSerializer;
private readonly IFileSystem _fileSystem;
private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); 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; _jsonSerializer = jsonSerializer;
_config = config; _config = config;
_logger = logger; _logger = logger;
_httpClient = httpClient; _httpClient = httpClient;
_fileSystem = fileSystem;
} }
/// <summary> /// <summary>
@ -66,7 +69,7 @@ namespace MediaBrowser.Providers.TV
var timestampFileInfo = new FileInfo(timestampFile); var timestampFileInfo = new FileInfo(timestampFile);
// Don't check for tvdb updates anymore frequently than 24 hours // 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; 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.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
@ -36,6 +37,7 @@ namespace MediaBrowser.Providers.TV
/// </summary> /// </summary>
/// <value>The HTTP client.</value> /// <value>The HTTP client.</value>
protected IHttpClient HttpClient { get; private set; } protected IHttpClient HttpClient { get; private set; }
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RemoteEpisodeProvider" /> class. /// 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="logManager">The log manager.</param>
/// <param name="configurationManager">The configuration manager.</param> /// <param name="configurationManager">The configuration manager.</param>
/// <param name="providerManager">The provider 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) : base(logManager, configurationManager)
{ {
HttpClient = httpClient; HttpClient = httpClient;
_providerManager = providerManager; _providerManager = providerManager;
_fileSystem = fileSystem;
} }
/// <summary> /// <summary>
@ -149,7 +152,7 @@ namespace MediaBrowser.Providers.TV
if (files.Count > 0) 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(); cancellationToken.ThrowIfCancellationRequested();
var status = ProviderRefreshStatus.Success;
var episode = (Episode)item; var episode = (Episode)item;
var seriesId = episode.Series != null ? episode.Series.GetProviderId(MetadataProviders.Tvdb) : null; var seriesId = episode.Series != null ? episode.Series.GetProviderId(MetadataProviders.Tvdb) : null;
if (!string.IsNullOrEmpty(seriesId)) if (!string.IsNullOrEmpty(seriesId))
{ {
var seriesDataPath = RemoteSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, var seriesDataPath = RemoteSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId);
seriesId);
var status = ProviderRefreshStatus.Success;
try try
{ {
status = await FetchEpisodeData(episode, seriesDataPath, cancellationToken).ConfigureAwait(false); 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. // 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); SetLastRefreshed(item, DateTime.UtcNow, status);
return false; 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;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
@ -23,6 +24,7 @@ namespace MediaBrowser.Providers.TV
/// The _provider manager /// The _provider manager
/// </summary> /// </summary>
private readonly IProviderManager _providerManager; private readonly IProviderManager _providerManager;
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RemoteSeasonProvider"/> class. /// 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="configurationManager">The configuration manager.</param>
/// <param name="providerManager">The provider manager.</param> /// <param name="providerManager">The provider manager.</param>
/// <exception cref="System.ArgumentNullException">httpClient</exception> /// <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) : base(logManager, configurationManager)
{ {
_providerManager = providerManager; _providerManager = providerManager;
_fileSystem = fileSystem;
} }
/// <summary> /// <summary>
@ -115,7 +118,7 @@ namespace MediaBrowser.Providers.TV
if (imagesFileInfo.Exists) if (imagesFileInfo.Exists)
{ {
return imagesFileInfo.LastWriteTimeUtc > providerInfo.LastRefreshed; return _fileSystem.GetLastWriteTimeUtc(imagesFileInfo) > providerInfo.LastRefreshed;
} }
} }
return false; return false;
@ -275,6 +278,7 @@ namespace MediaBrowser.Providers.TV
string url = null; string url = null;
int? bannerSeason = null; int? bannerSeason = null;
string resolution = null; string resolution = null;
string language = null;
while (reader.Read()) while (reader.Read())
{ {
@ -282,6 +286,12 @@ namespace MediaBrowser.Providers.TV
{ {
switch (reader.Name) switch (reader.Name)
{ {
case "Language":
{
language = reader.ReadElementContentAsString() ?? string.Empty;
break;
}
case "BannerType": case "BannerType":
{ {
bannerType = reader.ReadElementContentAsString() ?? string.Empty; bannerType = reader.ReadElementContentAsString() ?? string.Empty;
@ -325,11 +335,30 @@ namespace MediaBrowser.Providers.TV
{ {
if (string.Equals(bannerType2, "season", StringComparison.OrdinalIgnoreCase)) 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)) 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)) 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.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
@ -49,6 +50,8 @@ namespace MediaBrowser.Providers.TV
/// <value>The HTTP client.</value> /// <value>The HTTP client.</value>
protected IHttpClient HttpClient { get; private set; } protected IHttpClient HttpClient { get; private set; }
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RemoteSeriesProvider" /> class. /// Initializes a new instance of the <see cref="RemoteSeriesProvider" /> class.
/// </summary> /// </summary>
@ -57,7 +60,7 @@ namespace MediaBrowser.Providers.TV
/// <param name="configurationManager">The configuration manager.</param> /// <param name="configurationManager">The configuration manager.</param>
/// <param name="zipClient">The zip client.</param> /// <param name="zipClient">The zip client.</param>
/// <exception cref="System.ArgumentNullException">httpClient</exception> /// <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) : base(logManager, configurationManager)
{ {
if (httpClient == null) if (httpClient == null)
@ -66,6 +69,7 @@ namespace MediaBrowser.Providers.TV
} }
HttpClient = httpClient; HttpClient = httpClient;
_zipClient = zipClient; _zipClient = zipClient;
_fileSystem = fileSystem;
Current = this; Current = this;
} }
@ -176,7 +180,7 @@ namespace MediaBrowser.Providers.TV
{ {
var files = new DirectoryInfo(path) var files = new DirectoryInfo(path)
.EnumerateFiles("*.xml", SearchOption.TopDirectoryOnly) .EnumerateFiles("*.xml", SearchOption.TopDirectoryOnly)
.Select(i => i.LastWriteTimeUtc) .Select(i => _fileSystem.GetLastWriteTimeUtc(i))
.ToList(); .ToList();
if (files.Count > 0) if (files.Count > 0)
@ -344,7 +348,7 @@ namespace MediaBrowser.Providers.TV
{ {
string validXml; 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)) 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)) using (var writer = new StreamWriter(fileStream))
{ {
@ -1109,21 +1113,37 @@ namespace MediaBrowser.Providers.TV
var nodes = doc.SelectNodes("//Series"); var nodes = doc.SelectNodes("//Series");
var comparableName = GetComparableName(name); var comparableName = GetComparableName(name);
if (nodes != null) if (nodes != null)
{
foreach (XmlNode node in nodes) foreach (XmlNode node in nodes)
{ {
var n = node.SelectSingleNode("./SeriesName"); var titles = new List<string>();
if (n != null && string.Equals(GetComparableName(n.InnerText), comparableName, StringComparison.OrdinalIgnoreCase))
var nameNode = node.SelectSingleNode("./SeriesName");
if (nameNode != null)
{ {
n = node.SelectSingleNode("./seriesid"); titles.Add(GetComparableName(nameNode.InnerText));
if (n != null)
return n.InnerText;
} }
else
var aliasNode = node.SelectSingleNode("./AliasNames");
if (aliasNode != null)
{ {
if (n != null) var alias = aliasNode.InnerText.Split('|').Select(GetComparableName);
Logger.Info("TVDb Provider - " + n.InnerText + " did not match " + comparableName); 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 // 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;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.IO; using MediaBrowser.Controller.IO;
@ -18,10 +19,12 @@ namespace MediaBrowser.Providers.TV
public class SeasonProviderFromXml : BaseMetadataProvider public class SeasonProviderFromXml : BaseMetadataProvider
{ {
public static SeasonProviderFromXml Current; 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) : base(logManager, configurationManager)
{ {
_fileSystem = fileSystem;
Current = this; Current = this;
} }
@ -54,7 +57,7 @@ namespace MediaBrowser.Providers.TV
return false; return false;
} }
return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed; return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
} }
/// <summary> /// <summary>

View File

@ -39,6 +39,13 @@ namespace MediaBrowser.Providers.TV
private async Task RunInternal(IProgress<double> progress, CancellationToken cancellationToken) 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 var seriesList = _libraryManager.RootFolder
.RecursiveChildren .RecursiveChildren
.OfType<Series>() .OfType<Series>()
@ -136,21 +143,27 @@ namespace MediaBrowser.Providers.TV
.Where(i => i.Item1 != -1 && i.Item2 != -1) .Where(i => i.Item1 != -1 && i.Item2 != -1)
.ToList(); .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; var hasNewEpisodes = false;
if (_config.Configuration.EnableInternetProviders) 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) if (hasNewEpisodes || anySeasonsRemoved || anyEpisodesRemoved)
{ {
await series.RefreshMetadata(cancellationToken, true).ConfigureAwait(false); await series.RefreshMetadata(cancellationToken, true)
await series.ValidateChildren(new Progress<double>(), cancellationToken, true).ConfigureAwait(false); .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) else if (airDate.Value > now)
{ {
// tvdb has a lot of nearly blank episodes // 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); 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;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.IO; using MediaBrowser.Controller.IO;
@ -18,10 +19,12 @@ namespace MediaBrowser.Providers.TV
public class SeriesProviderFromXml : BaseMetadataProvider public class SeriesProviderFromXml : BaseMetadataProvider
{ {
internal static SeriesProviderFromXml Current { get; private set; } internal static SeriesProviderFromXml Current { get; private set; }
private readonly IFileSystem _fileSystem;
public SeriesProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager)
public SeriesProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
: base(logManager, configurationManager) : base(logManager, configurationManager)
{ {
_fileSystem = fileSystem;
Current = this; Current = this;
} }
@ -54,7 +57,7 @@ namespace MediaBrowser.Providers.TV
return false; return false;
} }
return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed; return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
} }
/// <summary> /// <summary>

View File

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

View File

@ -1,8 +1,9 @@
using System.Linq; using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
@ -11,6 +12,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -30,6 +32,7 @@ namespace MediaBrowser.Providers.TV
/// The _provider manager /// The _provider manager
/// </summary> /// </summary>
private readonly IProviderManager _providerManager; private readonly IProviderManager _providerManager;
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="TvdbSeriesImageProvider"/> class. /// 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="configurationManager">The configuration manager.</param>
/// <param name="providerManager">The provider manager.</param> /// <param name="providerManager">The provider manager.</param>
/// <exception cref="System.ArgumentNullException">httpClient</exception> /// <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) : base(logManager, configurationManager)
{ {
if (httpClient == null) if (httpClient == null)
@ -48,6 +51,7 @@ namespace MediaBrowser.Providers.TV
} }
HttpClient = httpClient; HttpClient = httpClient;
_providerManager = providerManager; _providerManager = providerManager;
_fileSystem = fileSystem;
} }
/// <summary> /// <summary>
@ -127,7 +131,7 @@ namespace MediaBrowser.Providers.TV
if (imagesFileInfo.Exists) 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)) 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)) 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)) 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
@ -40,9 +42,10 @@ namespace MediaBrowser.Server.Implementations.Drawing
/// </summary> /// </summary>
/// <param name="path">The path of the image to get the dimensions of.</param> /// <param name="path">The path of the image to get the dimensions of.</param>
/// <param name="logger">The logger.</param> /// <param name="logger">The logger.</param>
/// <param name="fileSystem">The file system.</param>
/// <returns>The dimensions of the specified image.</returns> /// <returns>The dimensions of the specified image.</returns>
/// <exception cref="ArgumentException">The image was of an unrecognised format.</exception> /// <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 try
{ {
@ -60,7 +63,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
} }
// Buffer to memory stream to avoid image locking file // 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()) using (var memoryStream = new MemoryStream())
{ {

View File

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

View File

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

View File

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

View File

@ -1,6 +1,7 @@
using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO; using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using ServiceStack.Common; using ServiceStack.Common;
using ServiceStack.Common.Web; using ServiceStack.Common.Web;
@ -25,13 +26,15 @@ namespace MediaBrowser.Server.Implementations.HttpServer
/// The _logger /// The _logger
/// </summary> /// </summary>
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HttpResultFactory"/> class. /// Initializes a new instance of the <see cref="HttpResultFactory"/> class.
/// </summary> /// </summary>
/// <param name="logManager">The log manager.</param> /// <param name="logManager">The log manager.</param>
public HttpResultFactory(ILogManager logManager) public HttpResultFactory(ILogManager logManager, IFileSystem fileSystem)
{ {
_fileSystem = fileSystem;
_logger = logManager.GetLogger("HttpResultFactory"); _logger = logManager.GetLogger("HttpResultFactory");
} }
@ -288,7 +291,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
throw new ArgumentException("FileShare must be either Read or ReadWrite"); 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; var cacheKey = path + dateModified.Ticks;
@ -303,7 +306,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
/// <returns>Stream.</returns> /// <returns>Stream.</returns>
private Stream GetFileStream(string path, FileShare fileShare) 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> /// <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.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO; using MediaBrowser.Controller.IO;
@ -87,10 +88,12 @@ namespace MediaBrowser.Server.Implementations.IO
private ILibraryManager LibraryManager { get; set; } private ILibraryManager LibraryManager { get; set; }
private IServerConfigurationManager ConfigurationManager { get; set; } private IServerConfigurationManager ConfigurationManager { get; set; }
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DirectoryWatchers" /> class. /// Initializes a new instance of the <see cref="DirectoryWatchers" /> class.
/// </summary> /// </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) if (taskManager == null)
{ {
@ -101,6 +104,7 @@ namespace MediaBrowser.Server.Implementations.IO
TaskManager = taskManager; TaskManager = taskManager;
Logger = logManager.GetLogger("DirectoryWatchers"); Logger = logManager.GetLogger("DirectoryWatchers");
ConfigurationManager = configurationManager; ConfigurationManager = configurationManager;
_fileSystem = fileSystem;
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged; SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
} }
@ -318,6 +322,18 @@ namespace MediaBrowser.Server.Implementations.IO
/// <param name="sender">The source of the event.</param> /// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="FileSystemEventArgs" /> instance containing the event data.</param> /// <param name="e">The <see cref="FileSystemEventArgs" /> instance containing the event data.</param>
void watcher_Changed(object sender, FileSystemEventArgs e) 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; var name = e.Name;
@ -418,7 +434,7 @@ namespace MediaBrowser.Server.Implementations.IO
{ {
try try
{ {
var data = FileSystem.GetFileSystemInfo(path); var data = _fileSystem.GetFileSystemInfo(path);
if (!data.Exists if (!data.Exists
|| data.Attributes.HasFlag(FileAttributes.Directory) || data.Attributes.HasFlag(FileAttributes.Directory)
@ -434,7 +450,7 @@ namespace MediaBrowser.Server.Implementations.IO
try 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 //file is not locked
return false; return false;

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Progress; using MediaBrowser.Common.Progress;
using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
@ -169,6 +170,8 @@ namespace MediaBrowser.Server.Implementations.Library
private readonly ConcurrentDictionary<string, UserRootFolder> _userRootFolders = private readonly ConcurrentDictionary<string, UserRootFolder> _userRootFolders =
new ConcurrentDictionary<string, UserRootFolder>(); new ConcurrentDictionary<string, UserRootFolder>();
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="LibraryManager" /> class. /// Initializes a new instance of the <see cref="LibraryManager" /> class.
/// </summary> /// </summary>
@ -177,7 +180,7 @@ namespace MediaBrowser.Server.Implementations.Library
/// <param name="userManager">The user manager.</param> /// <param name="userManager">The user manager.</param>
/// <param name="configurationManager">The configuration manager.</param> /// <param name="configurationManager">The configuration manager.</param>
/// <param name="userDataRepository">The user data repository.</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; _logger = logger;
_taskManager = taskManager; _taskManager = taskManager;
@ -185,6 +188,7 @@ namespace MediaBrowser.Server.Implementations.Library
ConfigurationManager = configurationManager; ConfigurationManager = configurationManager;
_userDataRepository = userDataRepository; _userDataRepository = userDataRepository;
_directoryWatchersFactory = directoryWatchersFactory; _directoryWatchersFactory = directoryWatchersFactory;
_fileSystem = fileSystem;
ByReferenceItems = new ConcurrentDictionary<Guid, BaseItem>(); ByReferenceItems = new ConcurrentDictionary<Guid, BaseItem>();
ConfigurationManager.ConfigurationUpdated += ConfigurationUpdated; ConfigurationManager.ConfigurationUpdated += ConfigurationUpdated;
@ -417,7 +421,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (item != null) 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 // 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. // 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) // When resolving the root, we need it's grandchildren (children of user views)
var flattenFolderDepth = isPhysicalRoot ? 2 : 0; 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 // Need to remove subpaths that may have been resolved from shortcuts
// Example: if \\server\movies exists, then strip out \\server\movies\action // Example: if \\server\movies exists, then strip out \\server\movies\action
@ -701,7 +705,7 @@ namespace MediaBrowser.Server.Implementations.Library
throw new ArgumentNullException(); throw new ArgumentNullException();
} }
var validFilename = FileSystem.GetValidFilename(name).Trim(); var validFilename = _fileSystem.GetValidFilename(name).Trim();
string subFolderPrefix = null; string subFolderPrefix = null;
@ -768,8 +772,8 @@ namespace MediaBrowser.Server.Implementations.Library
{ {
Name = name, Name = name,
Id = id, Id = id,
DateCreated = fileInfo.CreationTimeUtc, DateCreated = _fileSystem.GetCreationTimeUtc(fileInfo),
DateModified = fileInfo.LastWriteTimeUtc, DateModified = _fileSystem.GetLastWriteTimeUtc(fileInfo),
Path = path Path = path
}; };
isNew = true; isNew = true;
@ -1066,7 +1070,7 @@ namespace MediaBrowser.Server.Implementations.Library
Name = Path.GetFileName(dir), Name = Path.GetFileName(dir),
Locations = Directory.EnumerateFiles(dir, "*.mblink", SearchOption.TopDirectoryOnly) Locations = Directory.EnumerateFiles(dir, "*.mblink", SearchOption.TopDirectoryOnly)
.Select(FileSystem.ResolveShortcut) .Select(_fileSystem.ResolveShortcut)
.OrderBy(i => i) .OrderBy(i => i)
.ToList(), .ToList(),
@ -1150,7 +1154,7 @@ namespace MediaBrowser.Server.Implementations.Library
try try
{ {
// Try to resolve the path into a video // 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) if (video == null)
{ {

View File

@ -1,5 +1,7 @@
using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Resolvers; using MediaBrowser.Controller.Resolvers;
using System; using System;
@ -18,7 +20,8 @@ namespace MediaBrowser.Server.Implementations.Library
/// </summary> /// </summary>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="args">The args.</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); item.ResetResolveArgs(args);
@ -48,7 +51,7 @@ namespace MediaBrowser.Server.Implementations.Library
item.DontFetchMeta = item.Path.IndexOf("[dontfetchmeta]", StringComparison.OrdinalIgnoreCase) != -1; item.DontFetchMeta = item.Path.IndexOf("[dontfetchmeta]", StringComparison.OrdinalIgnoreCase) != -1;
// Make sure DateCreated and DateModified have values // Make sure DateCreated and DateModified have values
EntityResolutionHelper.EnsureDates(item, args, true); EntityResolutionHelper.EnsureDates(fileSystem, item, args, true);
} }
/// <summary> /// <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 there's a collection type and it's not tv, it can't be a series
if (!string.IsNullOrEmpty(collectionType) && 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; 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.Controller.Localization;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Globalization;
@ -30,13 +32,16 @@ namespace MediaBrowser.Server.Implementations.Localization
private readonly ConcurrentDictionary<string, Dictionary<string, ParentalRating>> _allParentalRatings = private readonly ConcurrentDictionary<string, Dictionary<string, ParentalRating>> _allParentalRatings =
new ConcurrentDictionary<string, Dictionary<string, ParentalRating>>(StringComparer.OrdinalIgnoreCase); new ConcurrentDictionary<string, Dictionary<string, ParentalRating>>(StringComparer.OrdinalIgnoreCase);
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="LocalizationManager"/> class. /// Initializes a new instance of the <see cref="LocalizationManager"/> class.
/// </summary> /// </summary>
/// <param name="configurationManager">The configuration manager.</param> /// <param name="configurationManager">The configuration manager.</param>
public LocalizationManager(IServerConfigurationManager configurationManager) public LocalizationManager(IServerConfigurationManager configurationManager, IFileSystem fileSystem)
{ {
_configurationManager = configurationManager; _configurationManager = configurationManager;
_fileSystem = fileSystem;
ExtractAll(); ExtractAll();
} }
@ -65,7 +70,7 @@ namespace MediaBrowser.Server.Implementations.Localization
{ {
using (var stream = type.Assembly.GetManifestResourceStream(resource)) 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); stream.CopyTo(fs);
} }

View File

@ -46,6 +46,14 @@
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <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.Drawing" />
<Reference Include="System.Reactive.Core"> <Reference Include="System.Reactive.Core">
<HintPath>..\packages\Rx-Core.2.1.30214.0\lib\Net45\System.Reactive.Core.dll</HintPath> <HintPath>..\packages\Rx-Core.2.1.30214.0\lib\Net45\System.Reactive.Core.dll</HintPath>
@ -88,12 +96,6 @@
<Reference Include="ServiceStack.Text"> <Reference Include="ServiceStack.Text">
<HintPath>..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll</HintPath> <HintPath>..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll</HintPath>
</Reference> </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"> <Reference Include="Mono.Data.Sqlite">
<HintPath>..\packages\ServiceStack.OrmLite.Sqlite.Mono.3.9.64\lib\net35\Mono.Data.Sqlite.dll</HintPath> <HintPath>..\packages\ServiceStack.OrmLite.Sqlite.Mono.3.9.64\lib\net35\Mono.Data.Sqlite.dll</HintPath>
</Reference> </Reference>

View File

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

View File

@ -35,16 +35,18 @@ namespace MediaBrowser.Server.Implementations.Providers
/// The _directory watchers /// The _directory watchers
/// </summary> /// </summary>
private readonly IDirectoryWatchers _directoryWatchers; private readonly IDirectoryWatchers _directoryWatchers;
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ImageSaver"/> class. /// Initializes a new instance of the <see cref="ImageSaver"/> class.
/// </summary> /// </summary>
/// <param name="config">The config.</param> /// <param name="config">The config.</param>
/// <param name="directoryWatchers">The directory watchers.</param> /// <param name="directoryWatchers">The directory watchers.</param>
public ImageSaver(IServerConfigurationManager config, IDirectoryWatchers directoryWatchers) public ImageSaver(IServerConfigurationManager config, IDirectoryWatchers directoryWatchers, IFileSystem fileSystem)
{ {
_config = config; _config = config;
_directoryWatchers = directoryWatchers; _directoryWatchers = directoryWatchers;
_fileSystem = fileSystem;
_remoteImageCache = new FileSystemRepository(config.ApplicationPaths.DownloadedImagesDataPath); _remoteImageCache = new FileSystemRepository(config.ApplicationPaths.DownloadedImagesDataPath);
} }
@ -67,30 +69,20 @@ namespace MediaBrowser.Server.Implementations.Providers
throw new ArgumentNullException("mimeType"); throw new ArgumentNullException("mimeType");
} }
var saveLocally = _config.Configuration.SaveLocalMeta; var saveLocally = _config.Configuration.SaveLocalMeta || item is IItemByName || item is User;
if (item is IItemByName) if (item is Audio || item.Parent == null)
{
saveLocally = true;
}
else if (item is User)
{
saveLocally = true;
}
else if (item is Audio || item.Parent == null || string.IsNullOrEmpty(item.MetaLocation))
{ {
saveLocally = false; 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; 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); await source.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, cancellationToken).ConfigureAwait(false);
} }
@ -373,7 +365,7 @@ namespace MediaBrowser.Server.Implementations.Providers
path = GetSavePathForItemInMixedFolder(item, type, filename, extension); 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); path = Path.Combine(item.MetaLocation, filename + extension);
} }

View File

@ -13,6 +13,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Providers;
namespace MediaBrowser.Server.Implementations.Providers namespace MediaBrowser.Server.Implementations.Providers
{ {
@ -48,6 +49,9 @@ namespace MediaBrowser.Server.Implementations.Providers
/// <value>The metadata providers enumerable.</value> /// <value>The metadata providers enumerable.</value>
private BaseMetadataProvider[] MetadataProviders { get; set; } private BaseMetadataProvider[] MetadataProviders { get; set; }
private IImageProvider[] ImageProviders { get; set; }
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ProviderManager" /> class. /// Initializes a new instance of the <see cref="ProviderManager" /> class.
/// </summary> /// </summary>
@ -55,22 +59,25 @@ namespace MediaBrowser.Server.Implementations.Providers
/// <param name="configurationManager">The configuration manager.</param> /// <param name="configurationManager">The configuration manager.</param>
/// <param name="directoryWatchers">The directory watchers.</param> /// <param name="directoryWatchers">The directory watchers.</param>
/// <param name="logManager">The log manager.</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, IFileSystem fileSystem)
public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, IDirectoryWatchers directoryWatchers, ILogManager logManager, ILibraryManager libraryManager)
{ {
_logger = logManager.GetLogger("ProviderManager"); _logger = logManager.GetLogger("ProviderManager");
_httpClient = httpClient; _httpClient = httpClient;
ConfigurationManager = configurationManager; ConfigurationManager = configurationManager;
_directoryWatchers = directoryWatchers; _directoryWatchers = directoryWatchers;
_fileSystem = fileSystem;
} }
/// <summary> /// <summary>
/// Adds the metadata providers. /// Adds the metadata providers.
/// </summary> /// </summary>
/// <param name="providers">The providers.</param> /// <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(); MetadataProviders = providers.OrderBy(e => e.Priority).ToArray();
ImageProviders = imageProviders.ToArray();
} }
/// <summary> /// <summary>
@ -288,7 +295,7 @@ namespace MediaBrowser.Server.Implementations.Providers
{ {
using (dataToSave) 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); await dataToSave.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, cancellationToken).ConfigureAwait(false);
} }
@ -342,7 +349,60 @@ namespace MediaBrowser.Server.Implementations.Providers
/// <returns>Task.</returns> /// <returns>Task.</returns>
public Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, string sourceUrl, CancellationToken cancellationToken) 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.OrmLite.SqlServer" version="3.9.43" targetFramework="net45" />
<package id="ServiceStack.Redis" 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="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> </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> <Link>FFMpeg\FFMpegDownloader.cs</Link>
</Compile> </Compile>
<Compile Include="FFMpeg\FFMpegDownloadInfo.cs" /> <Compile Include="FFMpeg\FFMpegDownloadInfo.cs" />
<Compile Include="IO\FileSystemFactory.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup> <ItemGroup>
@ -129,6 +130,7 @@
<Folder Include="Native\" /> <Folder Include="Native\" />
<Folder Include="FFMpeg\" /> <Folder Include="FFMpeg\" />
<Folder Include="Networking\" /> <Folder Include="Networking\" />
<Folder Include="IO\" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="app.config" /> <None Include="app.config" />

View File

@ -17,6 +17,7 @@ using System.Security.Cryptography.X509Certificates;
using Gtk; using Gtk;
using Gdk; using Gdk;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Reflection;
namespace MediaBrowser.Server.Mono namespace MediaBrowser.Server.Mono
{ {
@ -203,6 +204,8 @@ namespace MediaBrowser.Server.Mono
logger.Info("Server: {0}", Environment.MachineName); logger.Info("Server: {0}", Environment.MachineName);
logger.Info("Operating system: {0}", Environment.OSVersion.ToString()); logger.Info("Operating system: {0}", Environment.OSVersion.ToString());
MonoBug11817WorkAround.Apply ();
} }
/// <summary> /// <summary>
@ -280,4 +283,34 @@ namespace MediaBrowser.Server.Mono
return true; 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