aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Server.Implementations
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Server.Implementations')
-rw-r--r--MediaBrowser.Server.Implementations/Channels/ChannelManager.cs33
-rw-r--r--MediaBrowser.Server.Implementations/Collections/CollectionManager.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Collections/CollectionsDynamicFolder.cs7
-rw-r--r--MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs10
-rw-r--r--MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs11
-rw-r--r--MediaBrowser.Server.Implementations/Connect/ConnectManager.cs13
-rw-r--r--MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs7
-rw-r--r--MediaBrowser.Server.Implementations/Devices/DeviceManager.cs6
-rw-r--r--MediaBrowser.Server.Implementations/Devices/DeviceRepository.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Dto/DtoService.cs6
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/Notifications/RemoteNotifications.cs4
-rw-r--r--MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs12
-rw-r--r--MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs12
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs9
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs41
-rw-r--r--MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Library/LibraryManager.cs53
-rw-r--r--MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs14
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs26
-rw-r--r--MediaBrowser.Server.Implementations/Library/UserManager.cs8
-rw-r--r--MediaBrowser.Server.Implementations/Library/UserViewManager.cs64
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs7
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs171
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs7
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs5
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs5
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs25
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs23
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs57
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs16
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs13
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/ar.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/bg-BG.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/ca.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/core.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/cs.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/da.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/de.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/el.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/en-GB.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/en-US.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/es-AR.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/es-MX.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/es.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/fi.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/fr.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/gsw.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/he.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/hr.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/it.json55
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/kk.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/ko.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/ms.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/nb.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/nl.json5
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/pl.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/pt-BR.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/pt-PT.json5
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/ro.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/ru.json23
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/sl-SI.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/sv.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/tr.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/uk.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/vi.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/zh-CN.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/zh-HK.json177
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/zh-TW.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/LocalizationManager.cs4
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj38
-rw-r--r--MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs2
-rw-r--r--MediaBrowser.Server.Implementations/News/NewsEntryPoint.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs77
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs160
-rw-r--r--MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs7
-rw-r--r--MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs10
-rw-r--r--MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs11
-rw-r--r--MediaBrowser.Server.Implementations/Sync/MediaSync.cs9
-rw-r--r--MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Sync/SyncManager.cs37
-rw-r--r--MediaBrowser.Server.Implementations/Themes/AppThemeManager.cs168
-rw-r--r--MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs13
-rw-r--r--MediaBrowser.Server.Implementations/packages.config2
84 files changed, 975 insertions, 615 deletions
diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
index f670176e6..d7209fbdf 100644
--- a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
+++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
@@ -31,7 +31,6 @@ namespace MediaBrowser.Server.Implementations.Channels
public class ChannelManager : IChannelManager, IDisposable
{
private IChannel[] _channels;
- private IChannelFactory[] _factories;
private readonly IUserManager _userManager;
private readonly IUserDataManager _userDataManager;
@@ -76,10 +75,9 @@ namespace MediaBrowser.Server.Implementations.Channels
}
}
- public void AddParts(IEnumerable<IChannel> channels, IEnumerable<IChannelFactory> factories)
+ public void AddParts(IEnumerable<IChannel> channels)
{
- _channels = channels.Where(i => !(i is IFactoryChannel)).ToArray();
- _factories = factories.ToArray();
+ _channels = channels.ToArray();
}
public string ChannelDownloadPath
@@ -99,20 +97,7 @@ namespace MediaBrowser.Server.Implementations.Channels
private IEnumerable<IChannel> GetAllChannels()
{
- return _factories
- .SelectMany(i =>
- {
- try
- {
- return i.GetChannels().ToList();
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting channel list", ex);
- return new List<IChannel>();
- }
- })
- .Concat(_channels)
+ return _channels
.OrderBy(i => i.Name);
}
@@ -318,7 +303,7 @@ namespace MediaBrowser.Server.Implementations.Channels
try
{
- var files = new DirectoryInfo(parentPath).EnumerateFiles("*", SearchOption.TopDirectoryOnly);
+ var files = _fileSystem.GetFiles(parentPath);
if (string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
{
@@ -411,7 +396,7 @@ namespace MediaBrowser.Server.Implementations.Channels
{
_logger.Debug("Creating directory {0}", path);
- Directory.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
fileInfo = new DirectoryInfo(path);
if (!fileInfo.Exists)
@@ -448,7 +433,7 @@ namespace MediaBrowser.Server.Implementations.Channels
item.Name = channelInfo.Name;
}
- await item.RefreshMetadata(new MetadataRefreshOptions
+ await item.RefreshMetadata(new MetadataRefreshOptions(_fileSystem)
{
ForceSave = isNew
@@ -1082,7 +1067,7 @@ namespace MediaBrowser.Server.Implementations.Channels
{
try
{
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
_jsonSerializer.SerializeToFile(result, path);
}
@@ -1462,7 +1447,7 @@ namespace MediaBrowser.Server.Implementations.Channels
options.RequestHeaders[header.Key] = header.Value;
}
- Directory.CreateDirectory(Path.GetDirectoryName(destination));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(destination));
// Determine output extension
var response = await _httpClient.GetTempFileResponse(options).ConfigureAwait(false);
@@ -1500,7 +1485,7 @@ namespace MediaBrowser.Server.Implementations.Channels
throw new ApplicationException("Unexpected response type encountered: " + response.ContentType);
}
- File.Copy(response.TempFilePath, destination, true);
+ _fileSystem.CopyFile(response.TempFilePath, destination, true);
try
{
diff --git a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs
index 04f82db6f..b8c23224f 100644
--- a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs
+++ b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs
@@ -70,7 +70,7 @@ namespace MediaBrowser.Server.Implementations.Collections
try
{
- Directory.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
var collection = new BoxSet
{
@@ -88,7 +88,7 @@ namespace MediaBrowser.Server.Implementations.Collections
await parentFolder.AddChild(collection, CancellationToken.None).ConfigureAwait(false);
- await collection.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService()), CancellationToken.None)
+ await collection.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_fileSystem)), CancellationToken.None)
.ConfigureAwait(false);
if (options.ItemIdList.Count > 0)
diff --git a/MediaBrowser.Server.Implementations/Collections/CollectionsDynamicFolder.cs b/MediaBrowser.Server.Implementations/Collections/CollectionsDynamicFolder.cs
index 915a27c11..0fc7fb3f6 100644
--- a/MediaBrowser.Server.Implementations/Collections/CollectionsDynamicFolder.cs
+++ b/MediaBrowser.Server.Implementations/Collections/CollectionsDynamicFolder.cs
@@ -1,23 +1,26 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
using System.IO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.Collections
{
public class CollectionsDynamicFolder : IVirtualFolderCreator
{
private readonly IApplicationPaths _appPaths;
+ private IFileSystem _fileSystem;
- public CollectionsDynamicFolder(IApplicationPaths appPaths)
+ public CollectionsDynamicFolder(IApplicationPaths appPaths, IFileSystem fileSystem)
{
_appPaths = appPaths;
+ _fileSystem = fileSystem;
}
public BasePluginFolder GetFolder()
{
var path = Path.Combine(_appPaths.DataPath, "collections");
- Directory.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
return new ManualCollectionsFolder
{
diff --git a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
index bf199503b..050b79db7 100644
--- a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
+++ b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
@@ -15,6 +15,7 @@ using MediaBrowser.Model.Serialization;
using System;
using System.IO;
using System.Linq;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.Configuration
{
@@ -23,15 +24,18 @@ namespace MediaBrowser.Server.Implementations.Configuration
/// </summary>
public class ServerConfigurationManager : BaseConfigurationManager, IServerConfigurationManager
{
+ private readonly IFileSystem _fileSystem;
+
/// <summary>
/// Initializes a new instance of the <see cref="ServerConfigurationManager" /> class.
/// </summary>
/// <param name="applicationPaths">The application paths.</param>
/// <param name="logManager">The log manager.</param>
/// <param name="xmlSerializer">The XML serializer.</param>
- public ServerConfigurationManager(IApplicationPaths applicationPaths, ILogManager logManager, IXmlSerializer xmlSerializer)
+ public ServerConfigurationManager(IApplicationPaths applicationPaths, ILogManager logManager, IXmlSerializer xmlSerializer, IFileSystem fileSystem)
: base(applicationPaths, logManager, xmlSerializer)
{
+ _fileSystem = fileSystem;
UpdateItemsByNamePath();
UpdateMetadataPath();
}
@@ -198,7 +202,7 @@ namespace MediaBrowser.Server.Implementations.Configuration
&& !string.Equals(Configuration.ItemsByNamePath ?? string.Empty, newPath))
{
// Validate
- if (!Directory.Exists(newPath))
+ if (!_fileSystem.DirectoryExists(newPath))
{
throw new DirectoryNotFoundException(string.Format("{0} does not exist.", newPath));
}
@@ -218,7 +222,7 @@ namespace MediaBrowser.Server.Implementations.Configuration
&& !string.Equals(Configuration.MetadataPath ?? string.Empty, newPath))
{
// Validate
- if (!Directory.Exists(newPath))
+ if (!_fileSystem.DirectoryExists(newPath))
{
throw new DirectoryNotFoundException(string.Format("{0} does not exist.", newPath));
}
diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs b/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs
index 8a659fb65..a8900fa5b 100644
--- a/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs
+++ b/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs
@@ -10,6 +10,7 @@ using System.IO;
using System.Net;
using System.Text;
using System.Threading;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.Connect
{
@@ -23,8 +24,9 @@ namespace MediaBrowser.Server.Implementations.Connect
private readonly INetworkManager _networkManager;
private readonly IApplicationHost _appHost;
+ private readonly IFileSystem _fileSystem;
- public ConnectEntryPoint(IHttpClient httpClient, IApplicationPaths appPaths, ILogger logger, INetworkManager networkManager, IConnectManager connectManager, IApplicationHost appHost)
+ public ConnectEntryPoint(IHttpClient httpClient, IApplicationPaths appPaths, ILogger logger, INetworkManager networkManager, IConnectManager connectManager, IApplicationHost appHost, IFileSystem fileSystem)
{
_httpClient = httpClient;
_appPaths = appPaths;
@@ -32,6 +34,7 @@ namespace MediaBrowser.Server.Implementations.Connect
_networkManager = networkManager;
_connectManager = connectManager;
_appHost = appHost;
+ _fileSystem = fileSystem;
}
public void Run()
@@ -90,8 +93,8 @@ namespace MediaBrowser.Server.Implementations.Connect
try
{
- Directory.CreateDirectory(Path.GetDirectoryName(path));
- File.WriteAllText(path, address, Encoding.UTF8);
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.WriteAllText(path, address, Encoding.UTF8);
}
catch (Exception ex)
{
@@ -105,7 +108,7 @@ namespace MediaBrowser.Server.Implementations.Connect
try
{
- var endpoint = File.ReadAllText(path, Encoding.UTF8);
+ var endpoint = _fileSystem.ReadAllText(path, Encoding.UTF8);
if (IsValid(endpoint))
{
diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
index 7cd96c5f3..aab3a2121 100644
--- a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
+++ b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
@@ -23,6 +23,7 @@ using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.Connect
{
@@ -40,6 +41,7 @@ namespace MediaBrowser.Server.Implementations.Connect
private readonly IUserManager _userManager;
private readonly IProviderManager _providerManager;
private readonly ISecurityManager _securityManager;
+ private readonly IFileSystem _fileSystem;
private ConnectData _data = new ConnectData();
@@ -104,7 +106,7 @@ namespace MediaBrowser.Server.Implementations.Connect
IEncryptionManager encryption,
IHttpClient httpClient,
IServerApplicationHost appHost,
- IServerConfigurationManager config, IUserManager userManager, IProviderManager providerManager, ISecurityManager securityManager)
+ IServerConfigurationManager config, IUserManager userManager, IProviderManager providerManager, ISecurityManager securityManager, IFileSystem fileSystem)
{
_logger = logger;
_appPaths = appPaths;
@@ -116,6 +118,7 @@ namespace MediaBrowser.Server.Implementations.Connect
_userManager = userManager;
_providerManager = providerManager;
_securityManager = securityManager;
+ _fileSystem = fileSystem;
_userManager.UserConfigurationUpdated += _userManager_UserConfigurationUpdated;
_config.ConfigurationUpdated += _config_ConfigurationUpdated;
@@ -315,7 +318,7 @@ namespace MediaBrowser.Server.Implementations.Connect
try
{
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
var json = _json.SerializeToString(_data);
@@ -323,7 +326,7 @@ namespace MediaBrowser.Server.Implementations.Connect
lock (_dataFileLock)
{
- File.WriteAllText(path, encrypted, Encoding.UTF8);
+ _fileSystem.WriteAllText(path, encrypted, Encoding.UTF8);
}
}
catch (Exception ex)
@@ -340,7 +343,7 @@ namespace MediaBrowser.Server.Implementations.Connect
{
lock (_dataFileLock)
{
- var encrypted = File.ReadAllText(path, Encoding.UTF8);
+ var encrypted = _fileSystem.ReadAllText(path, Encoding.UTF8);
var json = _encryption.DecryptString(encrypted);
@@ -943,7 +946,7 @@ namespace MediaBrowser.Server.Implementations.Connect
{
await _providerManager.SaveImage(user, imageUrl, _connectImageSemaphore, ImageType.Primary, null, CancellationToken.None).ConfigureAwait(false);
- await user.RefreshMetadata(new MetadataRefreshOptions
+ await user.RefreshMetadata(new MetadataRefreshOptions(_fileSystem)
{
ForceSave = true,
diff --git a/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs b/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs
index 566f4c5f4..15567703d 100644
--- a/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs
+++ b/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs
@@ -3,6 +3,7 @@ using MediaBrowser.Controller.Entities;
using System;
using System.IO;
using System.Linq;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.Devices
{
@@ -51,17 +52,19 @@ namespace MediaBrowser.Server.Implementations.Devices
public class CameraUploadsDynamicFolder : IVirtualFolderCreator
{
private readonly IApplicationPaths _appPaths;
+ private readonly IFileSystem _fileSystem;
- public CameraUploadsDynamicFolder(IApplicationPaths appPaths)
+ public CameraUploadsDynamicFolder(IApplicationPaths appPaths, IFileSystem fileSystem)
{
_appPaths = appPaths;
+ _fileSystem = fileSystem;
}
public BasePluginFolder GetFolder()
{
var path = Path.Combine(_appPaths.DataPath, "camerauploads");
- Directory.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
return new CameraUploadsFolder
{
diff --git a/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs b/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs
index 04337dda6..a6a8b3a7a 100644
--- a/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs
+++ b/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs
@@ -8,6 +8,7 @@ using MediaBrowser.Model.Devices;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Net;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Session;
using MediaBrowser.Model.Users;
@@ -151,12 +152,13 @@ namespace MediaBrowser.Server.Implementations.Devices
path = Path.Combine(path, _fileSystem.GetValidFilename(file.Album));
}
- Directory.CreateDirectory(path);
-
path = Path.Combine(path, file.Name);
+ path = Path.ChangeExtension(path, MimeTypes.ToExtension(file.MimeType) ?? "jpg");
_libraryMonitor.ReportFileSystemChangeBeginning(path);
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
+
try
{
using (var fs = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
diff --git a/MediaBrowser.Server.Implementations/Devices/DeviceRepository.cs b/MediaBrowser.Server.Implementations/Devices/DeviceRepository.cs
index 6d324b1ab..b8262d05f 100644
--- a/MediaBrowser.Server.Implementations/Devices/DeviceRepository.cs
+++ b/MediaBrowser.Server.Implementations/Devices/DeviceRepository.cs
@@ -47,7 +47,7 @@ namespace MediaBrowser.Server.Implementations.Devices
public Task SaveDevice(DeviceInfo device)
{
var path = Path.Combine(GetDevicePath(device.Id), "device.json");
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
lock (_syncLock)
{
@@ -178,7 +178,7 @@ namespace MediaBrowser.Server.Implementations.Devices
public void AddCameraUpload(string deviceId, LocalFileInfo file)
{
var path = Path.Combine(GetDevicePath(deviceId), "camerauploads.json");
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
lock (_syncLock)
{
diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
index edfef38fd..2f2ebb349 100644
--- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs
+++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
@@ -908,12 +908,6 @@ namespace MediaBrowser.Server.Implementations.Dto
dto.DisplayMediaType = item.DisplayMediaType;
}
- // Leave null if false
- if (item.IsUnidentified)
- {
- dto.IsUnidentified = item.IsUnidentified;
- }
-
if (fields.Contains(ItemFields.Settings))
{
dto.LockedFields = item.LockedFields;
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/Notifications/RemoteNotifications.cs b/MediaBrowser.Server.Implementations/EntryPoints/Notifications/RemoteNotifications.cs
index d5b7f5b36..932e94b2a 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/Notifications/RemoteNotifications.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/Notifications/RemoteNotifications.cs
@@ -60,7 +60,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
{
var dataPath = Path.Combine(_appPaths.DataPath, "remotenotifications.json");
- var lastRunTime = File.Exists(dataPath) ? _fileSystem.GetLastWriteTimeUtc(dataPath) : DateTime.MinValue;
+ var lastRunTime = _fileSystem.FileExists(dataPath) ? _fileSystem.GetLastWriteTimeUtc(dataPath) : DateTime.MinValue;
try
{
@@ -88,7 +88,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
{
var notifications = _json.DeserializeFromStream<RemoteNotification[]>(stream);
- File.WriteAllText(dataPath, string.Empty);
+ _fileSystem.WriteAllText(dataPath, string.Empty);
await CreateNotifications(notifications, lastRunTime).ConfigureAwait(false);
}
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
index 06b72e4ef..0389980e2 100644
--- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
+++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
@@ -182,7 +182,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
_logger.Info("Sorting file {0} to new path {1}", sourcePath, newPath);
result.TargetPath = newPath;
- var fileExists = File.Exists(result.TargetPath);
+ var fileExists = _fileSystem.FileExists(result.TargetPath);
var otherDuplicatePaths = GetOtherDuplicatePaths(result.TargetPath, series, seasonNumber, episodeNumber, endingEpiosdeNumber);
if (!overwriteExisting)
@@ -272,7 +272,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
var destination = Path.Combine(directory, filename);
- File.Move(file, destination);
+ _fileSystem.MoveFile(file, destination);
}
}
}
@@ -332,19 +332,19 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
{
_libraryMonitor.ReportFileSystemChangeBeginning(result.TargetPath);
- Directory.CreateDirectory(Path.GetDirectoryName(result.TargetPath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(result.TargetPath));
- var targetAlreadyExists = File.Exists(result.TargetPath);
+ var targetAlreadyExists = _fileSystem.FileExists(result.TargetPath);
try
{
if (targetAlreadyExists || options.CopyOriginalFile)
{
- File.Copy(result.OriginalPath, result.TargetPath, true);
+ _fileSystem.CopyFile(result.OriginalPath, result.TargetPath, true);
}
else
{
- File.Move(result.OriginalPath, result.TargetPath);
+ _fileSystem.MoveFile(result.OriginalPath, result.TargetPath);
}
result.Status = FileSortingStatus.Success;
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs
index 0caa8c26e..2867cbecb 100644
--- a/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs
+++ b/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs
@@ -111,8 +111,8 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
{
try
{
- return Directory
- .EnumerateDirectories(path, "*", SearchOption.TopDirectoryOnly)
+ return _fileSystem
+ .GetFileSystemEntryPaths(path)
.ToList();
}
catch (IOException ex)
@@ -132,8 +132,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
{
try
{
- return new DirectoryInfo(path)
- .EnumerateFiles("*", SearchOption.AllDirectories)
+ return _fileSystem.GetFiles(path, true)
.ToList();
}
catch (IOException ex)
@@ -151,8 +150,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
/// <param name="extensions">The extensions.</param>
private void DeleteLeftOverFiles(string path, IEnumerable<string> extensions)
{
- var eligibleFiles = new DirectoryInfo(path)
- .EnumerateFiles("*", SearchOption.AllDirectories)
+ var eligibleFiles = _fileSystem.GetFiles(path, true)
.Where(i => extensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase))
.ToList();
@@ -189,7 +187,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
try
{
_logger.Debug("Deleting empty directory {0}", path);
- Directory.Delete(path);
+ _fileSystem.DeleteDirectory(path, false);
}
catch (UnauthorizedAccessException) { }
catch (DirectoryNotFoundException) { }
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
index 3795f4b15..1885afc61 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -79,6 +79,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer
_containerAdapter = new ContainerAdapter(applicationHost);
}
+ public string GlobalResponse { get; set; }
+
public override void Configure(Container container)
{
HostConfig.Instance.DefaultRedirectPath = DefaultRedirectPath;
@@ -336,6 +338,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer
return Task.FromResult(true);
}
+ if (!string.IsNullOrWhiteSpace(GlobalResponse))
+ {
+ httpRes.Write(GlobalResponse);
+ httpRes.ContentType = "text/plain";
+ return Task.FromResult(true);
+ }
+
var handler = HttpHandlerFactory.GetHandler(httpReq);
var remoteIp = httpReq.RemoteIp;
diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
index 80892b96c..ae5ce796e 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
@@ -69,47 +69,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
token = httpReq.QueryString["api_key"];
}
- // Hack until iOS is updated
- // TODO: Remove
- if (string.IsNullOrWhiteSpace(client))
- {
- var userAgent = httpReq.Headers["User-Agent"] ?? string.Empty;
-
- if (userAgent.IndexOf("mediabrowserios", StringComparison.OrdinalIgnoreCase) != -1 ||
- userAgent.IndexOf("iphone", StringComparison.OrdinalIgnoreCase) != -1 ||
- userAgent.IndexOf("ipad", StringComparison.OrdinalIgnoreCase) != -1)
- {
- client = "iOS";
- }
-
- else if (userAgent.IndexOf("crKey", StringComparison.OrdinalIgnoreCase) != -1)
- {
- client = "Chromecast";
- }
- }
-
- // Hack until iOS is updated
- // TODO: Remove
- if (string.IsNullOrWhiteSpace(device))
- {
- var userAgent = httpReq.Headers["User-Agent"] ?? string.Empty;
-
- if (userAgent.IndexOf("iPhone", StringComparison.OrdinalIgnoreCase) != -1)
- {
- device = "iPhone";
- }
-
- else if (userAgent.IndexOf("iPad", StringComparison.OrdinalIgnoreCase) != -1)
- {
- device = "iPad";
- }
-
- else if (userAgent.IndexOf("crKey", StringComparison.OrdinalIgnoreCase) != -1)
- {
- device = "Chromecast";
- }
- }
-
var info = new AuthorizationInfo
{
Client = client,
diff --git a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
index 5bd26ce18..cb9d5a09f 100644
--- a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
+++ b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
@@ -645,7 +645,7 @@ namespace MediaBrowser.Server.Implementations.IO
if (item != null)
{
// If the item has been deleted find the first valid parent that still exists
- while (!Directory.Exists(item.Path) && !File.Exists(item.Path))
+ while (!_fileSystem.DirectoryExists(item.Path) && !_fileSystem.FileExists(item.Path))
{
item = item.Parent;
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index cc9d9551c..26961c490 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -395,12 +395,12 @@ namespace MediaBrowser.Server.Implementations.Library
{
foreach (var path in item.GetDeletePaths().ToList())
{
- if (Directory.Exists(path))
+ if (_fileSystem.DirectoryExists(path))
{
_logger.Debug("Deleting path {0}", path);
_fileSystem.DeleteDirectory(path, true);
}
- else if (File.Exists(path))
+ else if (_fileSystem.FileExists(path))
{
_logger.Debug("Deleting path {0}", path);
_fileSystem.DeleteFile(path);
@@ -548,7 +548,7 @@ namespace MediaBrowser.Server.Implementations.Library
public BaseItem ResolvePath(FileSystemInfo fileInfo,
Folder parent = null)
{
- return ResolvePath(fileInfo, new DirectoryService(_logger), parent);
+ return ResolvePath(fileInfo, new DirectoryService(_logger, _fileSystem), parent);
}
private BaseItem ResolvePath(FileSystemInfo fileInfo, IDirectoryService directoryService, Folder parent = null, string collectionType = null)
@@ -691,7 +691,7 @@ namespace MediaBrowser.Server.Implementations.Library
{
var rootFolderPath = ConfigurationManager.ApplicationPaths.RootFolderPath;
- Directory.CreateDirectory(rootFolderPath);
+ _fileSystem.CreateDirectory(rootFolderPath);
var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? (AggregateFolder)ResolvePath(new DirectoryInfo(rootFolderPath));
@@ -742,7 +742,7 @@ namespace MediaBrowser.Server.Implementations.Library
{
var userRootPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
- Directory.CreateDirectory(userRootPath);
+ _fileSystem.CreateDirectory(userRootPath);
var tmpItem = GetItemById(GetNewItemId(userRootPath, typeof(UserRootFolder))) as UserRootFolder;
@@ -1007,9 +1007,9 @@ namespace MediaBrowser.Server.Implementations.Library
public Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
{
// Ensure the location is available.
- Directory.CreateDirectory(ConfigurationManager.ApplicationPaths.PeoplePath);
+ _fileSystem.CreateDirectory(ConfigurationManager.ApplicationPaths.PeoplePath);
- return new PeopleValidator(this, _logger, ConfigurationManager).ValidatePeople(cancellationToken, progress);
+ return new PeopleValidator(this, _logger, ConfigurationManager, _fileSystem).ValidatePeople(cancellationToken, progress);
}
/// <summary>
@@ -1064,7 +1064,7 @@ namespace MediaBrowser.Server.Implementations.Library
progress.Report(.5);
// Start by just validating the children of the root, but go no further
- await RootFolder.ValidateChildren(new Progress<double>(), cancellationToken, new MetadataRefreshOptions(), recursive: false);
+ await RootFolder.ValidateChildren(new Progress<double>(), cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: false);
progress.Report(1);
@@ -1072,7 +1072,7 @@ namespace MediaBrowser.Server.Implementations.Library
await userRoot.RefreshMetadata(cancellationToken).ConfigureAwait(false);
- await userRoot.ValidateChildren(new Progress<double>(), cancellationToken, new MetadataRefreshOptions(), recursive: false).ConfigureAwait(false);
+ await userRoot.ValidateChildren(new Progress<double>(), cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: false).ConfigureAwait(false);
progress.Report(2);
var innerProgress = new ActionableProgress<double>();
@@ -1080,7 +1080,7 @@ namespace MediaBrowser.Server.Implementations.Library
innerProgress.RegisterAction(pct => progress.Report(2 + pct * .73));
// Now validate the entire media library
- await RootFolder.ValidateChildren(innerProgress, cancellationToken, new MetadataRefreshOptions(), recursive: true).ConfigureAwait(false);
+ await RootFolder.ValidateChildren(innerProgress, cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: true).ConfigureAwait(false);
progress.Report(75);
@@ -1165,7 +1165,7 @@ namespace MediaBrowser.Server.Implementations.Library
/// <returns>IEnumerable{VirtualFolderInfo}.</returns>
private IEnumerable<VirtualFolderInfo> GetView(string path)
{
- return Directory.EnumerateDirectories(path, "*", SearchOption.TopDirectoryOnly)
+ return _fileSystem.GetFileSystemEntryPaths(path)
.Select(dir => new VirtualFolderInfo
{
Name = Path.GetFileName(dir),
@@ -1638,6 +1638,7 @@ namespace MediaBrowser.Server.Implementations.Library
}
private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromHours(24);
+ //private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromMinutes(1);
public Task<UserView> GetNamedView(User user,
string name,
@@ -1645,12 +1646,7 @@ namespace MediaBrowser.Server.Implementations.Library
string sortName,
CancellationToken cancellationToken)
{
- if (ConfigurationManager.Configuration.EnableUserSpecificUserViews)
- {
- return GetNamedViewInternal(user, name, null, viewType, sortName, null, cancellationToken);
- }
-
- return GetNamedView(name, viewType, sortName, cancellationToken);
+ return GetNamedViewInternal(user, name, null, viewType, sortName, null, cancellationToken);
}
public async Task<UserView> GetNamedView(string name,
@@ -1671,7 +1667,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (item == null ||
!string.Equals(item.Path, path, StringComparison.OrdinalIgnoreCase))
{
- Directory.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
item = new UserView
{
@@ -1702,7 +1698,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (refresh)
{
await item.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None).ConfigureAwait(false);
- _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions
+ _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem)
{
// Not sure why this is necessary but need to figure it out
// View images are not getting utilized without this
@@ -1758,7 +1754,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (item == null)
{
- Directory.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
item = new UserView
{
@@ -1767,7 +1763,8 @@ namespace MediaBrowser.Server.Implementations.Library
DateCreated = DateTime.UtcNow,
Name = name,
ViewType = viewType,
- ForcedSortName = sortName
+ ForcedSortName = sortName,
+ UserId = user.Id
};
if (!string.IsNullOrWhiteSpace(parentId))
@@ -1780,6 +1777,12 @@ namespace MediaBrowser.Server.Implementations.Library
isNew = true;
}
+ if (!item.UserId.HasValue)
+ {
+ item.UserId = user.Id;
+ await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
+ }
+
if (!string.Equals(viewType, item.ViewType, StringComparison.OrdinalIgnoreCase))
{
item.ViewType = viewType;
@@ -1790,7 +1793,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (refresh)
{
- _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions
+ _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem)
{
// Need to force save to increment DateLastSaved
ForceSave = true
@@ -1828,7 +1831,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (item == null)
{
- Directory.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
item = new UserView
{
@@ -1860,7 +1863,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (refresh)
{
- _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions
+ _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem)
{
// Need to force save to increment DateLastSaved
ForceSave = true
@@ -2181,7 +2184,7 @@ namespace MediaBrowser.Server.Implementations.Library
}
}
- return item.People ?? new List<PersonInfo>();
+ return new List<PersonInfo>();
}
public List<Person> GetPeopleItems(InternalPeopleQuery query)
diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
index e3ec99392..a348c728e 100644
--- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
@@ -15,6 +15,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.Library
{
@@ -24,17 +25,19 @@ namespace MediaBrowser.Server.Implementations.Library
private readonly IUserManager _userManager;
private readonly ILibraryManager _libraryManager;
private readonly IJsonSerializer _jsonSerializer;
+ private readonly IFileSystem _fileSystem;
private IMediaSourceProvider[] _providers;
private readonly ILogger _logger;
- public MediaSourceManager(IItemRepository itemRepo, IUserManager userManager, ILibraryManager libraryManager, ILogger logger, IJsonSerializer jsonSerializer)
+ public MediaSourceManager(IItemRepository itemRepo, IUserManager userManager, ILibraryManager libraryManager, ILogger logger, IJsonSerializer jsonSerializer, IFileSystem fileSystem)
{
_itemRepo = itemRepo;
_userManager = userManager;
_libraryManager = libraryManager;
_logger = logger;
_jsonSerializer = jsonSerializer;
+ _fileSystem = fileSystem;
}
public void AddParts(IEnumerable<IMediaSourceProvider> providers)
@@ -127,9 +130,12 @@ namespace MediaBrowser.Server.Implementations.Library
{
var supportsExternalStream = StreamSupportsExternalStream(subStream);
- if (supportsExternalStream && videoBitrate >= maxAllowedBitrateForExternalSubtitleStream)
+ if (!subStream.IsExternal)
{
- supportsExternalStream = false;
+ if (supportsExternalStream && videoBitrate >= maxAllowedBitrateForExternalSubtitleStream)
+ {
+ supportsExternalStream = false;
+ }
}
subStream.SupportsExternalStream = supportsExternalStream;
@@ -167,7 +173,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (source.Protocol == MediaProtocol.File)
{
// TODO: Path substitution
- if (!File.Exists(source.Path))
+ if (!_fileSystem.FileExists(source.Path))
{
source.SupportsDirectStream = false;
}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
index 0d1e4202c..d9f23977c 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
@@ -309,20 +309,26 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
//we need to only look at the name of this actual item (not parents)
var justName = item.IsInMixedFolder ? Path.GetFileName(item.Path) : Path.GetFileName(item.ContainingFolderPath);
- // check for tmdb id
- var tmdbid = justName.GetAttributeValue("tmdbid");
-
- if (!string.IsNullOrEmpty(tmdbid))
+ if (!string.IsNullOrWhiteSpace(justName))
{
- item.SetProviderId(MetadataProviders.Tmdb, tmdbid);
- }
+ // check for tmdb id
+ var tmdbid = justName.GetAttributeValue("tmdbid");
- // check for imdb id - we use full media path, as we can assume, that this will match in any use case (wither id in parent dir or in file name)
- var imdbid = item.Path.GetAttributeValue("imdbid");
+ if (!string.IsNullOrWhiteSpace(tmdbid))
+ {
+ item.SetProviderId(MetadataProviders.Tmdb, tmdbid);
+ }
+ }
- if (!string.IsNullOrEmpty(imdbid))
+ if (!string.IsNullOrWhiteSpace(item.Path))
{
- item.SetProviderId(MetadataProviders.Imdb, imdbid);
+ // check for imdb id - we use full media path, as we can assume, that this will match in any use case (wither id in parent dir or in file name)
+ var imdbid = item.Path.GetAttributeValue("imdbid");
+
+ if (!string.IsNullOrWhiteSpace(imdbid))
+ {
+ item.SetProviderId(MetadataProviders.Imdb, imdbid);
+ }
}
}
}
diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs
index 5012f2479..a8fc7b4aa 100644
--- a/MediaBrowser.Server.Implementations/Library/UserManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs
@@ -454,7 +454,7 @@ namespace MediaBrowser.Server.Implementations.Library
/// <returns>Task.</returns>
public Task RefreshUsersMetadata(CancellationToken cancellationToken)
{
- var tasks = Users.Select(user => user.RefreshMetadata(new MetadataRefreshOptions(), cancellationToken)).ToList();
+ var tasks = Users.Select(user => user.RefreshMetadata(new MetadataRefreshOptions(_fileSystem), cancellationToken)).ToList();
return Task.WhenAll(tasks);
}
@@ -745,7 +745,7 @@ namespace MediaBrowser.Server.Implementations.Library
text.AppendLine(string.Empty);
text.AppendLine("The pin code will expire at " + expiration.ToLocalTime().ToShortDateString() + " " + expiration.ToLocalTime().ToShortTimeString());
- File.WriteAllText(path, text.ToString(), Encoding.UTF8);
+ _fileSystem.WriteAllText(path, text.ToString(), Encoding.UTF8);
var result = new PasswordPinCreationResult
{
@@ -919,7 +919,7 @@ namespace MediaBrowser.Server.Implementations.Library
var path = GetPolifyFilePath(user);
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
lock (_policySyncLock)
{
@@ -1006,7 +1006,7 @@ namespace MediaBrowser.Server.Implementations.Library
config = _jsonSerializer.DeserializeFromString<UserConfiguration>(json);
}
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
lock (_configSyncLock)
{
diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
index 43f77ec49..fe9e09318 100644
--- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
@@ -65,20 +65,24 @@ namespace MediaBrowser.Server.Implementations.Library
var list = new List<Folder>();
- if (_config.Configuration.EnableUserSpecificUserViews)
+ if (_config.Configuration.EnableUserViews)
{
foreach (var folder in standaloneFolders)
{
var collectionFolder = folder as ICollectionFolder;
var folderViewType = collectionFolder == null ? null : collectionFolder.CollectionType;
- if (plainFolderIds.Contains(folder.Id))
+ if (UserView.IsUserSpecific(folder))
{
- list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, false, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, true, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ }
+ else if (plainFolderIds.Contains(folder.Id))
+ {
+ list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, false, string.Empty, cancellationToken).ConfigureAwait(false));
}
else if (!string.IsNullOrWhiteSpace(folderViewType))
{
- list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, true, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, true, string.Empty, cancellationToken).ConfigureAwait(false));
}
else
{
@@ -88,7 +92,29 @@ namespace MediaBrowser.Server.Implementations.Library
}
else
{
- list.AddRange(standaloneFolders);
+ // TODO: Deprecate this whole block
+ foreach (var folder in standaloneFolders)
+ {
+ var collectionFolder = folder as ICollectionFolder;
+ var folderViewType = collectionFolder == null ? null : collectionFolder.CollectionType;
+
+ if (UserView.IsUserSpecific(folder))
+ {
+ list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, true, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ }
+ else if (plainFolderIds.Contains(folder.Id))
+ {
+ list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, false, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ }
+ else if (!string.IsNullOrWhiteSpace(folderViewType))
+ {
+ list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, true, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ }
+ else
+ {
+ list.Add(folder);
+ }
+ }
}
var parents = foldersWithViewTypes.Where(i => string.Equals(i.GetViewType(user), CollectionType.TvShows, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.GetViewType(user)))
@@ -123,22 +149,6 @@ namespace MediaBrowser.Server.Implementations.Library
list.Add(await GetUserView(parents, list, CollectionType.Games, string.Empty, user, cancellationToken).ConfigureAwait(false));
}
- parents = foldersWithViewTypes.Where(i => string.Equals(i.GetViewType(user), CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase))
- .ToList();
-
- if (parents.Count > 0)
- {
- list.Add(await GetUserView(parents, list, CollectionType.BoxSets, string.Empty, user, cancellationToken).ConfigureAwait(false));
- }
-
- parents = foldersWithViewTypes.Where(i => string.Equals(i.GetViewType(user), CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))
- .ToList();
-
- if (parents.Count > 0)
- {
- list.Add(await GetUserView(parents, list, CollectionType.Playlists, string.Empty, user, cancellationToken).ConfigureAwait(false));
- }
-
if (user.Configuration.DisplayFoldersView)
{
var name = _localizationManager.GetLocalizedString("ViewType" + CollectionType.Folders);
@@ -204,9 +214,9 @@ namespace MediaBrowser.Server.Implementations.Library
public async Task<UserView> GetUserView(List<ICollectionFolder> parents, List<Folder> currentViews, string viewType, string sortName, User user, CancellationToken cancellationToken)
{
var name = _localizationManager.GetLocalizedString("ViewType" + viewType);
- var enableUserSpecificViews = _config.Configuration.EnableUserSpecificUserViews;
+ var enableUserViews = _config.Configuration.EnableUserViews;
- if (parents.Count == 1 && parents.All(i => string.Equals((enableUserSpecificViews ? i.CollectionType : i.GetViewType(user)), viewType, StringComparison.OrdinalIgnoreCase)))
+ if (parents.Count == 1 && parents.All(i => string.Equals((enableUserViews ? i.GetViewType(user) : i.CollectionType), viewType, StringComparison.OrdinalIgnoreCase)))
{
if (!string.IsNullOrWhiteSpace(parents[0].Name))
{
@@ -222,7 +232,7 @@ namespace MediaBrowser.Server.Implementations.Library
return await GetUserView(parentId, name, viewType, enableRichView, sortName, user, cancellationToken).ConfigureAwait(false);
}
- if (enableUserSpecificViews)
+ if (!enableUserViews)
{
var view = await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false);
@@ -244,6 +254,12 @@ namespace MediaBrowser.Server.Implementations.Library
return _libraryManager.GetNamedView(user, name, parentId.ToString("N"), viewType, sortName, null, cancellationToken);
}
+ public Task<UserView> GetUserView(Guid parentId, string name, string viewType, bool enableRichView, string sortName, CancellationToken cancellationToken)
+ {
+ viewType = enableRichView ? viewType : null;
+ return _libraryManager.GetNamedView(name, parentId.ToString("N"), viewType, sortName, null, cancellationToken);
+ }
+
public List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request)
{
var user = _userManager.GetUserById(request.UserId);
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs
index a4c43af5d..c6b294e83 100644
--- a/MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs
+++ b/MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs
@@ -11,6 +11,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.Library.Validators
{
@@ -29,17 +30,19 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
private readonly ILogger _logger;
private readonly IServerConfigurationManager _config;
+ private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="PeopleValidator" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
- public PeopleValidator(ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config)
+ public PeopleValidator(ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config, IFileSystem fileSystem)
{
_libraryManager = libraryManager;
_logger = logger;
_config = config;
+ _fileSystem = fileSystem;
}
private bool DownloadMetadata(PersonInfo i, PeopleMetadataOptions options)
@@ -121,7 +124,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
validIds.Add(item.Id);
- var options = new MetadataRefreshOptions
+ var options = new MetadataRefreshOptions(_fileSystem)
{
MetadataRefreshMode = person.Value ? MetadataRefreshMode.Default : MetadataRefreshMode.ValidationOnly,
ImageRefreshMode = person.Value ? ImageRefreshMode.Default : ImageRefreshMode.ValidationOnly
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 4e0d6e8d4..38b83eb02 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -8,7 +8,9 @@ using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.FileOrganization;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Events;
@@ -47,10 +49,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private readonly ILibraryManager _libraryManager;
private readonly IProviderManager _providerManager;
private readonly IFileOrganizationService _organizationService;
+ private readonly IMediaEncoder _mediaEncoder;
public static EmbyTV Current;
- public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ISecurityManager security, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService)
+ public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ISecurityManager security, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService, IMediaEncoder mediaEncoder)
{
Current = this;
@@ -64,12 +67,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_libraryMonitor = libraryMonitor;
_providerManager = providerManager;
_organizationService = organizationService;
+ _mediaEncoder = mediaEncoder;
_liveTvManager = (LiveTvManager)liveTvManager;
_jsonSerializer = jsonSerializer;
- _recordingProvider = new ItemDataProvider<RecordingInfo>(jsonSerializer, _logger, Path.Combine(DataPath, "recordings"), (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase));
- _seriesTimerProvider = new SeriesTimerManager(jsonSerializer, _logger, Path.Combine(DataPath, "seriestimers"));
- _timerProvider = new TimerManager(jsonSerializer, _logger, Path.Combine(DataPath, "timers"));
+ _recordingProvider = new ItemDataProvider<RecordingInfo>(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "recordings"), (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase));
+ _seriesTimerProvider = new SeriesTimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "seriestimers"));
+ _timerProvider = new TimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "timers"));
_timerProvider.TimerFired += _timerProvider_TimerFired;
}
@@ -126,6 +130,33 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
return status;
}
+ public async Task RefreshSeriesTimers(CancellationToken cancellationToken, IProgress<double> progress)
+ {
+ var timers = await GetSeriesTimersAsync(cancellationToken).ConfigureAwait(false);
+
+ List<ChannelInfo> channels = null;
+
+ foreach (var timer in timers)
+ {
+ List<ProgramInfo> epgData;
+
+ if (timer.RecordAnyChannel)
+ {
+ if (channels == null)
+ {
+ channels = (await GetChannelsAsync(true, CancellationToken.None).ConfigureAwait(false)).ToList();
+ }
+ var channelIds = channels.Select(i => i.Id).ToList();
+ epgData = GetEpgDataForChannels(channelIds);
+ }
+ else
+ {
+ epgData = GetEpgDataForChannel(timer.ChannelId);
+ }
+ await UpdateTimersForSeriesTimer(epgData, timer).ConfigureAwait(false);
+ }
+ }
+
private List<ChannelInfo> _channelCache = null;
private async Task<IEnumerable<ChannelInfo>> GetChannelsAsync(bool enableCache, CancellationToken cancellationToken)
{
@@ -235,7 +266,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
try
{
- File.Delete(remove.Path);
+ _fileSystem.DeleteFile(remove.Path);
}
catch (DirectoryNotFoundException)
{
@@ -366,6 +397,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
{
+ try
+ {
+ return await GetProgramsAsyncInternal(channelId, startDateUtc, endDateUtc, cancellationToken).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error getting programs", ex);
+ return GetEpgDataForChannel(channelId).Where(i => i.StartDate <= endDateUtc && i.EndDate >= startDateUtc);
+ }
+ }
+
+ private async Task<IEnumerable<ProgramInfo>> GetProgramsAsyncInternal(string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
+ {
var channels = await GetChannelsAsync(true, cancellationToken).ConfigureAwait(false);
var channel = channels.First(i => string.Equals(i.Id, channelId, StringComparison.OrdinalIgnoreCase));
@@ -373,6 +417,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
var programs = await provider.Item1.GetProgramsAsync(provider.Item2, channel.Number, startDateUtc, endDateUtc, cancellationToken)
.ConfigureAwait(false);
+
var list = programs.ToList();
// Replace the value that came from the provider with a normalized value
@@ -428,6 +473,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
if (mediaSourceInfo != null)
{
+ await AddMediaInfo(mediaSourceInfo, false, cancellationToken).ConfigureAwait(false);
+
mediaSourceInfo.Id = Guid.NewGuid().ToString("N");
return mediaSourceInfo;
}
@@ -458,6 +505,84 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
throw new NotImplementedException();
}
+ private async Task AddMediaInfo(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
+ {
+ var originalRuntime = mediaSource.RunTimeTicks;
+
+ var info = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest
+ {
+ InputPath = mediaSource.Path,
+ Protocol = mediaSource.Protocol,
+ MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video,
+ ExtractChapters = false
+
+ }, cancellationToken).ConfigureAwait(false);
+
+ mediaSource.Bitrate = info.Bitrate;
+ mediaSource.Container = info.Container;
+ mediaSource.Formats = info.Formats;
+ mediaSource.MediaStreams = info.MediaStreams;
+ mediaSource.RunTimeTicks = info.RunTimeTicks;
+ mediaSource.Size = info.Size;
+ mediaSource.Timestamp = info.Timestamp;
+ mediaSource.Video3DFormat = info.Video3DFormat;
+ mediaSource.VideoType = info.VideoType;
+
+ mediaSource.DefaultSubtitleStreamIndex = null;
+
+ // Null this out so that it will be treated like a live stream
+ if (!originalRuntime.HasValue)
+ {
+ mediaSource.RunTimeTicks = null;
+ }
+
+ var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Audio);
+
+ if (audioStream == null || audioStream.Index == -1)
+ {
+ mediaSource.DefaultAudioStreamIndex = null;
+ }
+ else
+ {
+ mediaSource.DefaultAudioStreamIndex = audioStream.Index;
+ }
+
+ var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Video);
+ if (videoStream != null)
+ {
+ if (!videoStream.BitRate.HasValue)
+ {
+ var width = videoStream.Width ?? 1920;
+
+ if (width >= 1900)
+ {
+ videoStream.BitRate = 8000000;
+ }
+
+ else if (width >= 1260)
+ {
+ videoStream.BitRate = 3000000;
+ }
+
+ else if (width >= 700)
+ {
+ videoStream.BitRate = 1000000;
+ }
+ }
+ }
+
+ // Try to estimate this
+ if (!mediaSource.Bitrate.HasValue)
+ {
+ var total = mediaSource.MediaStreams.Select(i => i.BitRate ?? 0).Sum();
+
+ if (total > 0)
+ {
+ mediaSource.Bitrate = total;
+ }
+ }
+ }
+
public Task<List<MediaSourceInfo>> GetRecordingStreamMediaSources(string recordingId, CancellationToken cancellationToken)
{
throw new NotImplementedException();
@@ -500,14 +625,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
catch (Exception ex)
{
_logger.ErrorException("Error recording stream", ex);
-
- if (DateTime.UtcNow < timer.EndDate)
- {
- const int retryIntervalSeconds = 60;
- _logger.Info("Retrying recording in {0} seconds.", retryIntervalSeconds);
-
- _timerProvider.StartTimer(timer, TimeSpan.FromSeconds(retryIntervalSeconds));
- }
}
}
@@ -553,7 +670,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
var recordingFileName = _fileSystem.GetValidFilename(RecordingHelper.GetRecordingName(timer, info)) + ".ts";
recordPath = Path.Combine(recordPath, recordingFileName);
- Directory.CreateDirectory(Path.GetDirectoryName(recordPath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(recordPath));
var recording = _recordingProvider.GetAll().FirstOrDefault(x => string.Equals(x.ProgramId, info.Id, StringComparison.OrdinalIgnoreCase));
@@ -597,7 +714,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_recordingProvider.Update(recording);
_logger.Info("Beginning recording.");
-
+
try
{
httpRequestOptions.BufferContent = false;
@@ -607,7 +724,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_logger.Info("Writing file to path: " + recordPath);
using (var response = await _httpClient.SendAsync(httpRequestOptions, "GET"))
{
- using (var output = File.Open(recordPath, FileMode.Create, FileAccess.Write, FileShare.Read))
+ using (var output = _fileSystem.GetFileStream(recordPath, FileMode.Create, FileAccess.Write, FileShare.Read))
{
await response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, linkedToken);
}
@@ -626,15 +743,31 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_logger.ErrorException("Error recording", ex);
recording.Status = RecordingStatus.Error;
}
+ finally
+ {
+ CancellationTokenSource removed;
+ _activeRecordings.TryRemove(timer.Id, out removed);
+ }
recording.DateLastUpdated = DateTime.UtcNow;
_recordingProvider.Update(recording);
- _timerProvider.Delete(timer);
- _logger.Info("Recording was a success");
if (recording.Status == RecordingStatus.Completed)
{
OnSuccessfulRecording(recording);
+ _timerProvider.Delete(timer);
+ }
+ else if (DateTime.UtcNow < timer.EndDate)
+ {
+ const int retryIntervalSeconds = 60;
+ _logger.Info("Retrying recording in {0} seconds.", retryIntervalSeconds);
+
+ _timerProvider.StartTimer(timer, TimeSpan.FromSeconds(retryIntervalSeconds));
+ }
+ else
+ {
+ _timerProvider.Delete(timer);
+ _recordingProvider.Delete(recording);
}
}
@@ -752,7 +885,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private void SaveEpgDataForChannel(string channelId, List<ProgramInfo> epgData)
{
var path = GetChannelEpgCachePath(channelId);
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
lock (_epgLock)
{
_jsonSerializer.SerializeToFile(epgData, path);
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
index 75dec5f97..2c8917ab4 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
@@ -4,6 +4,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
@@ -16,13 +17,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
protected readonly ILogger Logger;
private readonly string _dataPath;
protected readonly Func<T, T, bool> EqualityComparer;
+ private readonly IFileSystem _fileSystem;
- public ItemDataProvider(IJsonSerializer jsonSerializer, ILogger logger, string dataPath, Func<T, T, bool> equalityComparer)
+ public ItemDataProvider(IFileSystem fileSystem, IJsonSerializer jsonSerializer, ILogger logger, string dataPath, Func<T, T, bool> equalityComparer)
{
Logger = logger;
_dataPath = dataPath;
EqualityComparer = equalityComparer;
_jsonSerializer = jsonSerializer;
+ _fileSystem = fileSystem;
}
public IReadOnlyList<T> GetAll()
@@ -69,7 +72,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private void UpdateList(List<T> newList)
{
var file = _dataPath + ".json";
- Directory.CreateDirectory(Path.GetDirectoryName(file));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(file));
lock (_fileDataLock)
{
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs
index eab278eb4..563658885 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs
@@ -2,13 +2,14 @@
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using System;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
public class SeriesTimerManager : ItemDataProvider<SeriesTimerInfo>
{
- public SeriesTimerManager(IJsonSerializer jsonSerializer, ILogger logger, string dataPath)
- : base(jsonSerializer, logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase))
+ public SeriesTimerManager(IFileSystem fileSystem, IJsonSerializer jsonSerializer, ILogger logger, string dataPath)
+ : base(fileSystem, jsonSerializer, logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase))
{
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
index 3ae38f382..64a5b7339 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
@@ -7,6 +7,7 @@ using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
@@ -16,8 +17,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public event EventHandler<GenericEventArgs<TimerInfo>> TimerFired;
- public TimerManager(IJsonSerializer jsonSerializer, ILogger logger, string dataPath)
- : base(jsonSerializer, logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase))
+ public TimerManager(IFileSystem fileSystem, IJsonSerializer jsonSerializer, ILogger logger, string dataPath)
+ : base(fileSystem, jsonSerializer, logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase))
{
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
index d53c08150..868889ba7 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
@@ -216,20 +216,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
// Helper.logger.Info("Modifyin channel " + channel.Number);
if (_channelPair.ContainsKey(channel.Number))
{
- string channelName;
if (_channelPair[channel.Number].logo != null)
{
channel.ImageUrl = _channelPair[channel.Number].logo.URL;
channel.HasImage = true;
}
- if (_channelPair[channel.Number].affiliate != null)
- {
- channelName = _channelPair[channel.Number].affiliate;
- }
- else
- {
- channelName = _channelPair[channel.Number].name;
- }
+ string channelName = _channelPair[channel.Number].name;
channel.Name = channelName;
}
else
@@ -245,8 +237,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
ScheduleDirect.ProgramDetails details)
{
//_logger.Debug("Show type is: " + (details.showType ?? "No ShowType"));
- DateTime startAt = DateTime.ParseExact(programInfo.airDateTime, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'",
- CultureInfo.InvariantCulture);
+ DateTime startAt = GetDate(programInfo.airDateTime);
DateTime endAt = startAt.AddSeconds(programInfo.duration);
ProgramAudio audioType = ProgramAudio.Stereo;
@@ -369,6 +360,17 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
return info;
}
+ private DateTime GetDate(string value)
+ {
+ var date = DateTime.ParseExact(value, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", CultureInfo.InvariantCulture);
+
+ if (date.Kind != DateTimeKind.Utc)
+ {
+ date = DateTime.SpecifyKind(date, DateTimeKind.Utc);
+ }
+ return date;
+ }
+
private string GetProgramLogo(string apiUrl, ScheduleDirect.ShowImages images)
{
string url = "";
@@ -408,7 +410,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
{
imageIdString += "\"" + i.Substring(0, 10) + "\",";
}
- ;
});
imageIdString = imageIdString.TrimEnd(',') + "]";
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
index d73b144b8..0a33d7383 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -580,7 +580,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
item.Name = channelInfo.Name;
}
- await item.RefreshMetadata(new MetadataRefreshOptions
+ await item.RefreshMetadata(new MetadataRefreshOptions(_fileSystem)
{
ForceSave = isNew,
ReplaceImages = replaceImages.Distinct().ToList()
@@ -659,7 +659,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
}
}
- _providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions());
+ _providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem));
return item;
}
@@ -759,7 +759,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false);
}
- _providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions());
+ _providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem));
return item.Id;
}
@@ -1082,6 +1082,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv
await CleanDatabaseInternal(newChannelIdList, new[] { typeof(LiveTvChannel).Name }, progress, cancellationToken).ConfigureAwait(false);
await CleanDatabaseInternal(newProgramIdList, new[] { typeof(LiveTvProgram).Name }, progress, cancellationToken).ConfigureAwait(false);
+ var coreService = _services.OfType<EmbyTV.EmbyTV>().FirstOrDefault();
+
+ if (coreService != null)
+ {
+ await coreService.RefreshSeriesTimers(cancellationToken, new Progress<double>()).ConfigureAwait(false);
+ }
+
// Load these now which will prefetch metadata
var dtoOptions = new DtoOptions();
dtoOptions.Fields.Remove(ItemFields.SyncInfo);
@@ -1155,7 +1162,17 @@ namespace MediaBrowser.Server.Implementations.LiveTv
foreach (var program in channelPrograms)
{
+ if (program.StartDate.Kind != DateTimeKind.Utc)
+ {
+ _logger.Error("{0} returned StartDate.DateTimeKind.{1} instead of UTC for program {2}", service.Name, program.StartDate.Kind.ToString(), program.Name);
+ }
+ else if (program.EndDate.Kind != DateTimeKind.Utc)
+ {
+ _logger.Error("{0} returned EndDate.DateTimeKind.{1} instead of UTC for program {2}", service.Name, program.EndDate.Kind.ToString(), program.Name);
+ }
+
var programItem = await GetProgram(program, channelId, currentChannel.ChannelType, service.Name, cancellationToken).ConfigureAwait(false);
+
programs.Add(programItem.Id);
}
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
index 909e2bba5..e5222e55d 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
@@ -109,23 +109,22 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
foreach (var host in hostsWithChannel)
{
- // Check to make sure the tuner is available
- // If there's only one tuner, don't bother with the check and just let the tuner be the one to throw an error
- if (hostsWithChannel.Count > 1 && !await IsAvailable(host, channelId, cancellationToken).ConfigureAwait(false))
+ try
{
- Logger.Error("Tuner is not currently available");
- continue;
- }
+ var mediaSources = await GetChannelStreamMediaSources(host, channelId, cancellationToken).ConfigureAwait(false);
- var mediaSources = await GetChannelStreamMediaSources(host, channelId, cancellationToken).ConfigureAwait(false);
+ // Prefix the id with the host Id so that we can easily find it
+ foreach (var mediaSource in mediaSources)
+ {
+ mediaSource.Id = host.Id + mediaSource.Id;
+ }
- // Prefix the id with the host Id so that we can easily find it
- foreach (var mediaSource in mediaSources)
+ return mediaSources;
+ }
+ catch (Exception ex)
{
- mediaSource.Id = host.Id + mediaSource.Id;
+ Logger.Error("Error opening tuner", ex);
}
-
- return mediaSources;
}
}
@@ -163,23 +162,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
foreach (var host in hostsWithChannel)
{
- // Check to make sure the tuner is available
- // If there's only one tuner, don't bother with the check and just let the tuner be the one to throw an error
- // If a streamId is specified then availibility has already been checked in GetChannelStreamMediaSources
- if (string.IsNullOrWhiteSpace(streamId) && hostsWithChannel.Count > 1)
+ try
{
- if (!await IsAvailable(host, channelId, cancellationToken).ConfigureAwait(false))
+ var stream = await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false);
+
+ if (stream != null)
{
- Logger.Error("Tuner is not currently available");
- continue;
+ return stream;
}
}
-
- var stream = await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false);
-
- if (stream != null)
+ catch (Exception ex)
{
- return stream;
+ Logger.Error("Error opening tuner", ex);
}
}
}
@@ -187,21 +181,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
throw new LiveTvConflictException();
}
- protected async Task<bool> IsAvailable(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
- {
- try
- {
- return await IsAvailableInternal(tuner, channelId, cancellationToken).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error checking tuner availability", ex);
- return false;
- }
- }
-
- protected abstract Task<bool> IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken);
-
protected abstract bool IsValidChannelId(string channelId);
protected LiveTvOptions GetConfiguration()
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index bccb0db0a..571b00257 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -325,11 +325,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
BitRate = 128000
}
},
- RequiresOpening = false,
- RequiresClosing = false,
+ RequiresOpening = true,
+ RequiresClosing = true,
BufferMs = 1000,
Container = "ts",
- Id = profile
+ Id = profile,
+ SupportsDirectPlay = true,
+ SupportsDirectStream = true,
+ SupportsTranscoding = true
};
return mediaSource;
@@ -395,12 +398,5 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
await GetChannels(info, false, CancellationToken.None).ConfigureAwait(false);
}
}
-
- protected override async Task<bool> IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
- {
- var info = await GetTunerInfos(tuner, cancellationToken).ConfigureAwait(false);
-
- return info.Any(i => i.Status == LiveTvTunerStatus.Available || string.Equals(i.ChannelId, channelId, StringComparison.OrdinalIgnoreCase));
- }
}
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
index 3783e4b08..31139b15d 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
@@ -12,14 +12,18 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
{
public class M3UTunerHost : BaseTunerHost, ITunerHost
{
- public M3UTunerHost(IConfigurationManager config, ILogger logger)
+ private readonly IFileSystem _fileSystem;
+
+ public M3UTunerHost(IConfigurationManager config, ILogger logger, IFileSystem fileSystem)
: base(config, logger)
{
+ _fileSystem = fileSystem;
}
public override string Type
@@ -119,7 +123,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
public async Task Validate(TunerHostInfo info)
{
- if (!File.Exists(info.Url))
+ if (!_fileSystem.FileExists(info.Url))
{
throw new FileNotFoundException();
}
@@ -190,10 +194,5 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
}
return new List<MediaSourceInfo> { };
}
-
- protected override Task<bool> IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
- {
- return Task.FromResult(true);
- }
}
}
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/ar.json b/MediaBrowser.Server.Implementations/Localization/Core/ar.json
index 3d15d7b2e..fd47027c2 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/ar.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/ar.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/bg-BG.json b/MediaBrowser.Server.Implementations/Localization/Core/bg-BG.json
index 8854611a0..d719ae08e 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/bg-BG.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/bg-BG.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/ca.json b/MediaBrowser.Server.Implementations/Localization/Core/ca.json
index 35f2bafb8..46004f52c 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/ca.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/ca.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/core.json b/MediaBrowser.Server.Implementations/Localization/Core/core.json
index 4eb66929d..5f11b9436 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/core.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/core.json
@@ -173,5 +173,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
}
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/cs.json b/MediaBrowser.Server.Implementations/Localization/Core/cs.json
index ee30a6028..771e735e9 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/cs.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/cs.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/da.json b/MediaBrowser.Server.Implementations/Localization/Core/da.json
index 21d7e9e14..e6e4d9835 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/da.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/da.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Aldersgr\u00e6nser",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/de.json b/MediaBrowser.Server.Implementations/Localization/Core/de.json
index 277a224ce..0464b65ac 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/de.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/de.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Produzenten",
"HeaderWriter": "Autoren",
"HeaderParentalRatings": "Altersbeschr\u00e4nkung",
- "HeaderCommunityRatings": "Community Bewertungen"
+ "HeaderCommunityRatings": "Community Bewertungen",
+ "StartupEmbyServerIsLoading": "Emby Server startet, bitte versuchen Sie es gleich noch einmal."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/el.json b/MediaBrowser.Server.Implementations/Localization/Core/el.json
index 213868042..7e94f7987 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/el.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/el.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/en-GB.json b/MediaBrowser.Server.Implementations/Localization/Core/en-GB.json
index 566d2cf09..73534b08d 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/en-GB.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/en-GB.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/en-US.json b/MediaBrowser.Server.Implementations/Localization/Core/en-US.json
index abe203804..e444c0e93 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/en-US.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/en-US.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/es-AR.json b/MediaBrowser.Server.Implementations/Localization/Core/es-AR.json
index 9c1ea6cb9..8068e32a9 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/es-AR.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/es-AR.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/es-MX.json b/MediaBrowser.Server.Implementations/Localization/Core/es-MX.json
index 9e1030dbd..972f94100 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/es-MX.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/es-MX.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Productores",
"HeaderWriter": "Guionistas",
"HeaderParentalRatings": "Clasificaci\u00f3n Parental",
- "HeaderCommunityRatings": "Clasificaciones de la comunidad"
+ "HeaderCommunityRatings": "Clasificaciones de la comunidad",
+ "StartupEmbyServerIsLoading": "El servidor Emby esta cargando. Por favor intente de nuevo dentro de poco."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/es.json b/MediaBrowser.Server.Implementations/Localization/Core/es.json
index f93fd7219..9bf56e4af 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/es.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/es.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/fi.json b/MediaBrowser.Server.Implementations/Localization/Core/fi.json
index 5df95146c..f0ab5b0d0 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/fi.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/fi.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/fr.json b/MediaBrowser.Server.Implementations/Localization/Core/fr.json
index fe76ac64e..d8bffe699 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/fr.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/fr.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producteurs",
"HeaderWriter": "Auteur(e)s",
"HeaderParentalRatings": "Note parentale",
- "HeaderCommunityRatings": "Classification de la communaut\u00e9"
+ "HeaderCommunityRatings": "Classification de la communaut\u00e9",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/gsw.json b/MediaBrowser.Server.Implementations/Localization/Core/gsw.json
index 7334b24ce..736c3d18f 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/gsw.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/gsw.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/he.json b/MediaBrowser.Server.Implementations/Localization/Core/he.json
index b3bec3f02..a66438482 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/he.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/he.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/hr.json b/MediaBrowser.Server.Implementations/Localization/Core/hr.json
index 451ff4f36..2b9d56566 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/hr.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/hr.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/it.json b/MediaBrowser.Server.Implementations/Localization/Core/it.json
index 90f800634..197b9e2bb 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/it.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/it.json
@@ -20,8 +20,8 @@
"LabelExit": "Esci",
"LabelVisitCommunity": "Visita la Community",
"LabelGithub": "Github",
- "LabelApiDocumentation": "Documentazione sulle Api",
- "LabelDeveloperResources": "Risorse per i programmatori",
+ "LabelApiDocumentation": "Documentazione Api",
+ "LabelDeveloperResources": "Risorse programmatori",
"LabelBrowseLibrary": "Esplora la libreria",
"LabelConfigureServer": "Configura Emby",
"LabelRestartServer": "Riavvia Server",
@@ -120,36 +120,36 @@
"UserStartedPlayingItemWithValues": "{0} \u00e8 partito da {1}",
"UserStoppedPlayingItemWithValues": "{0} stoppato {1}",
"SubtitleDownloadFailureForItem": "Sottotitoli non scaricati per {0}",
- "HeaderUnidentified": "Unidentified",
- "HeaderImagePrimary": "Primary",
- "HeaderImageBackdrop": "Backdrop",
+ "HeaderUnidentified": "Non identificata",
+ "HeaderImagePrimary": "Primaria",
+ "HeaderImageBackdrop": "Sfondo",
"HeaderImageLogo": "Logo",
- "HeaderUserPrimaryImage": "User Image",
- "HeaderOverview": "Overview",
- "HeaderShortOverview": "Short Overview",
- "HeaderType": "Type",
- "HeaderSeverity": "Severity",
+ "HeaderUserPrimaryImage": "Immagine utente",
+ "HeaderOverview": "Panoramica",
+ "HeaderShortOverview": "breve panoramica",
+ "HeaderType": "Tipo",
+ "HeaderSeverity": "gravit\u00e0",
"HeaderUser": "Utente",
"HeaderName": "Nome",
"HeaderDate": "Data",
"HeaderPremiereDate": "Premiere Date",
- "HeaderDateAdded": "Date Added",
+ "HeaderDateAdded": "Aggiunto il",
"HeaderReleaseDate": "Data Rilascio",
"HeaderRuntime": "Durata",
- "HeaderPlayCount": "Play Count",
+ "HeaderPlayCount": "Visto N\u00b0",
"HeaderSeason": "Stagione",
"HeaderSeasonNumber": "Stagione Numero",
- "HeaderSeries": "Series:",
+ "HeaderSeries": "Serie:",
"HeaderNetwork": "Rete",
- "HeaderYear": "Year:",
- "HeaderYears": "Years:",
- "HeaderParentalRating": "Parental Rating",
+ "HeaderYear": "Anno:",
+ "HeaderYears": "Anni",
+ "HeaderParentalRating": "Valutazione parentale",
"HeaderCommunityRating": "Voto Comunit\u00e0",
"HeaderTrailers": "Trailers",
"HeaderSpecials": "Speciali",
- "HeaderGameSystems": "Game Systems",
- "HeaderPlayers": "Players:",
- "HeaderAlbumArtists": "Album Artists",
+ "HeaderGameSystems": "Sistemi di gioco",
+ "HeaderPlayers": "Giocatori",
+ "HeaderAlbumArtists": "Album Artisti",
"HeaderAlbums": "Album",
"HeaderDisc": "Disco",
"HeaderTrack": "Traccia",
@@ -163,14 +163,15 @@
"HeaderStatus": "Stato",
"HeaderTracks": "Traccia",
"HeaderMusicArtist": "Music artist",
- "HeaderLocked": "Locked",
+ "HeaderLocked": "Bloccato",
"HeaderStudios": "Studios",
- "HeaderActor": "Actors",
- "HeaderComposer": "Composers",
- "HeaderDirector": "Directors",
- "HeaderGuestStar": "Guest star",
- "HeaderProducer": "Producers",
- "HeaderWriter": "Writers",
+ "HeaderActor": "Attori",
+ "HeaderComposer": "Compositori",
+ "HeaderDirector": "Registi",
+ "HeaderGuestStar": "Personaggi famosi",
+ "HeaderProducer": "Produttori",
+ "HeaderWriter": "Sceneggiatori",
"HeaderParentalRatings": "Valutazioni genitori",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/kk.json b/MediaBrowser.Server.Implementations/Localization/Core/kk.json
index 7e17dea6b..863523606 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/kk.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/kk.json
@@ -104,7 +104,7 @@
"DeviceOnlineWithName": "{0} \u049b\u043e\u0441\u044b\u043b\u0493\u0430\u043d",
"UserOnlineFromDevice": "{0} - {1} \u0430\u0440\u049b\u044b\u043b\u044b \u049b\u043e\u0441\u044b\u043b\u0493\u0430\u043d",
"ProviderValue": "\u0416\u0435\u0442\u043a\u0456\u0437\u0443\u0448\u0456: {0}",
- "SubtitlesDownloadedForItem": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 {0} \u04af\u0448\u0456\u043d \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u044b\u043d\u0434\u044b",
+ "SubtitlesDownloadedForItem": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 {0} \u04af\u0448\u0456\u043d \u0436\u04af\u043a\u0442\u0435\u043b\u0456\u043f \u0430\u043b\u044b\u043d\u0434\u044b",
"UserConfigurationUpdatedWithName": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b {0} \u04af\u0448\u0456\u043d \u0442\u0435\u04a3\u0448\u0435\u043b\u0456\u043c \u0436\u0430\u04a3\u0430\u0440\u0442\u044b\u043b\u0434\u044b",
"UserCreatedWithName": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b {0} \u0436\u0430\u0441\u0430\u043b\u0493\u0430\u043d",
"UserPasswordChangedWithName": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b {0} \u04af\u0448\u0456\u043d \u049b\u04b1\u043f\u0438\u044f \u0441\u04e9\u0437 \u04e9\u0437\u0433\u0435\u0440\u0442\u0456\u043b\u0434\u0456",
@@ -117,9 +117,9 @@
"DeviceOfflineWithName": "{0} \u0430\u0436\u044b\u0440\u0430\u0442\u044b\u043b\u0493\u0430\u043d",
"UserLockedOutWithName": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b {0} \u049b\u04b1\u0440\u0441\u0430\u0443\u043b\u044b",
"UserOfflineFromDevice": "{0} - {1} \u0430\u0440\u049b\u044b\u043b\u044b \u0430\u0436\u044b\u0440\u0430\u0442\u044b\u043b\u0493\u0430\u043d",
- "UserStartedPlayingItemWithValues": "{0} - {1} \u043e\u0439\u043d\u0430\u0442\u0443\u044b \u0431\u0430\u0441\u0442\u0430\u043b\u0434\u044b",
- "UserStoppedPlayingItemWithValues": "{0} - {1} \u043e\u0439\u043d\u0430\u0442\u0443\u044b \u0442\u043e\u049b\u0442\u0430\u043b\u0434\u044b",
- "SubtitleDownloadFailureForItem": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 {0} \u04af\u0448\u0456\u043d \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u044b\u043d\u0443\u044b \u0441\u04d9\u0442\u0441\u0456\u0437",
+ "UserStartedPlayingItemWithValues": "{0} - {1} \u043e\u0439\u043d\u0430\u0442\u0443\u044b\u043d \u0431\u0430\u0441\u0442\u0430\u0434\u044b",
+ "UserStoppedPlayingItemWithValues": "{0} - {1} \u043e\u0439\u043d\u0430\u0442\u0443\u044b\u043d \u0442\u043e\u049b\u0442\u0430\u0442\u0442\u044b",
+ "SubtitleDownloadFailureForItem": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 {0} \u04af\u0448\u0456\u043d \u0436\u04af\u043a\u0442\u0435\u043b\u0456\u043f \u0430\u043b\u044b\u043d\u0443\u044b \u0441\u04d9\u0442\u0441\u0456\u0437",
"HeaderUnidentified": "\u0410\u043d\u044b\u049b\u0442\u0430\u043b\u043c\u0430\u0493\u0430\u043d",
"HeaderImagePrimary": "\u041d\u0435\u0433\u0456\u0437\u0433\u0456",
"HeaderImageBackdrop": "\u0410\u0440\u0442\u049b\u044b \u0441\u0443\u0440\u0435\u0442",
@@ -172,5 +172,6 @@
"HeaderProducer": "\u041f\u0440\u043e\u0434\u044e\u0441\u0435\u0440\u043b\u0435\u0440",
"HeaderWriter": "\u0421\u0446\u0435\u043d\u0430\u0440\u0438\u0439\u0448\u0456\u043b\u0435\u0440",
"HeaderParentalRatings": "\u0416\u0430\u0441\u0442\u0430\u0441 \u0441\u0430\u043d\u0430\u0442\u0442\u0430\u0440",
- "HeaderCommunityRatings": "\u049a\u0430\u0443\u044b\u043c \u0431\u0430\u0493\u0430\u043b\u0430\u0443\u043b\u0430\u0440\u044b"
+ "HeaderCommunityRatings": "\u049a\u0430\u0443\u044b\u043c \u0431\u0430\u0493\u0430\u043b\u0430\u0443\u043b\u0430\u0440\u044b",
+ "StartupEmbyServerIsLoading": "Emby Server \u0436\u04af\u043a\u0442\u0435\u043b\u0443\u0434\u0435. \u04d8\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u043a\u04e9\u043f \u04b1\u0437\u0430\u043c\u0430\u0439 \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/ko.json b/MediaBrowser.Server.Implementations/Localization/Core/ko.json
index 8bc5b5672..6044efb62 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/ko.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/ko.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/ms.json b/MediaBrowser.Server.Implementations/Localization/Core/ms.json
index a85f00132..6b5c4393f 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/ms.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/ms.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/nb.json b/MediaBrowser.Server.Implementations/Localization/Core/nb.json
index 2ab601701..f4ebe89b6 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/nb.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/nb.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Foreldresensur",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/nl.json b/MediaBrowser.Server.Implementations/Localization/Core/nl.json
index 8658518a4..b32ebefc3 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/nl.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/nl.json
@@ -157,7 +157,7 @@
"HeaderVideo": "Video",
"HeaderEmbeddedImage": "Ingesloten afbeelding",
"HeaderResolution": "Resolutie",
- "HeaderSubtitles": "Ondertitels",
+ "HeaderSubtitles": "Ondertiteling",
"HeaderGenres": "Genres",
"HeaderCountries": "Landen",
"HeaderStatus": "Status",
@@ -172,5 +172,6 @@
"HeaderProducer": "Producenten",
"HeaderWriter": "Schrijvers",
"HeaderParentalRatings": "Ouderlijke toezicht",
- "HeaderCommunityRatings": "Gemeenschapswaardering"
+ "HeaderCommunityRatings": "Gemeenschapswaardering",
+ "StartupEmbyServerIsLoading": "Emby Server is aan het laden, probeer het later opnieuw."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/pl.json b/MediaBrowser.Server.Implementations/Localization/Core/pl.json
index b7b0e228e..13dca8889 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/pl.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/pl.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/pt-BR.json b/MediaBrowser.Server.Implementations/Localization/Core/pt-BR.json
index e5e8afaa5..9548262c9 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/pt-BR.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/pt-BR.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Produtores",
"HeaderWriter": "Escritores",
"HeaderParentalRatings": "Classifica\u00e7\u00f5es Parentais",
- "HeaderCommunityRatings": "Avalia\u00e7\u00f5es da comunidade"
+ "HeaderCommunityRatings": "Avalia\u00e7\u00f5es da comunidade",
+ "StartupEmbyServerIsLoading": "O Servidor Emby est\u00e1 carregando. Por favor, tente novamente em breve."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/pt-PT.json b/MediaBrowser.Server.Implementations/Localization/Core/pt-PT.json
index 5aa832e16..c3d514c8a 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/pt-PT.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/pt-PT.json
@@ -46,7 +46,7 @@
"NotificationOptionInstallationFailed": "Falha na instala\u00e7\u00e3o",
"NotificationOptionNewLibraryContent": "Adicionado novo conte\u00fado",
"NotificationOptionNewLibraryContentMultiple": "Novo conte\u00fado adicionado (m\u00faltiplo)",
- "NotificationOptionCameraImageUploaded": "Camera image uploaded",
+ "NotificationOptionCameraImageUploaded": "Imagem da c\u00e2mara carregada",
"NotificationOptionUserLockedOut": "User locked out",
"NotificationOptionServerRestartRequired": "\u00c9 necess\u00e1rio reiniciar o servidor",
"ViewTypePlaylists": "Playlists",
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/ro.json b/MediaBrowser.Server.Implementations/Localization/Core/ro.json
index 6c945006a..a6aa9577b 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/ro.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/ro.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/ru.json b/MediaBrowser.Server.Implementations/Localization/Core/ru.json
index c705ddef4..f36db9e25 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/ru.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/ru.json
@@ -46,7 +46,7 @@
"NotificationOptionInstallationFailed": "\u0421\u0431\u043e\u0439 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438",
"NotificationOptionNewLibraryContent": "\u041d\u043e\u0432\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e",
"NotificationOptionNewLibraryContentMultiple": "\u041d\u043e\u0432\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e (\u043c\u043d\u043e\u0433\u043e\u043a\u0440\u0430\u0442\u043d\u043e)",
- "NotificationOptionCameraImageUploaded": "\u0424\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u044f \u0441 \u043a\u0430\u043c\u0435\u0440\u044b \u0432\u044b\u043b\u043e\u0436\u0435\u043d\u0430",
+ "NotificationOptionCameraImageUploaded": "\u041f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0430 \u0432\u044b\u043a\u043b\u0430\u0434\u043a\u0430 \u043e\u0442\u0441\u043d\u044f\u0442\u043e\u0433\u043e \u0441 \u043a\u0430\u043c\u0435\u0440\u044b",
"NotificationOptionUserLockedOut": "\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d",
"NotificationOptionServerRestartRequired": "\u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0430",
"ViewTypePlaylists": "\u0421\u043f\u0438\u0441\u043a\u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f",
@@ -81,7 +81,7 @@
"ViewTypeMusicLatest": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435",
"ViewTypeMusicPlaylists": "\u0421\u043f\u0438\u0441\u043a\u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f",
"ViewTypeMusicAlbums": "\u0410\u043b\u044c\u0431\u043e\u043c\u044b",
- "ViewTypeMusicAlbumArtists": "\u0410\u043b\u044c\u0431\u043e\u043c\u043d\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u0438",
+ "ViewTypeMusicAlbumArtists": "\u0418\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u0438 \u0430\u043b\u044c\u0431\u043e\u043c\u0430",
"HeaderOtherDisplaySettings": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f",
"ViewTypeMusicSongs": "\u041a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u0438",
"ViewTypeMusicFavorites": "\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u043e\u0435",
@@ -117,11 +117,11 @@
"DeviceOfflineWithName": "{0} - \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043f\u0440\u0435\u0440\u0432\u0430\u043d\u043e",
"UserLockedOutWithName": "\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c {0} \u0431\u044b\u043b \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d",
"UserOfflineFromDevice": "{0} - \u043f\u043e\u0434\u043a\u043b. \u0441 {1} \u043f\u0440\u0435\u0440\u0432\u0430\u043d\u043e",
- "UserStartedPlayingItemWithValues": "{0} - \u0432\u043e\u0441\u043f\u0440-\u0438\u0435 \u00ab{1}\u00bb \u0437\u0430\u043f-\u043d\u043e",
- "UserStoppedPlayingItemWithValues": "{0} - \u0432\u043e\u0441\u043f\u0440-\u0438\u0435 \u00ab{1}\u00bb \u043e\u0441\u0442-\u043d\u043e",
+ "UserStartedPlayingItemWithValues": "{0} - \u0432\u043e\u0441\u043f\u0440. \u00ab{1}\u00bb \u0437\u0430\u043f-\u043d\u043e",
+ "UserStoppedPlayingItemWithValues": "{0} - \u0432\u043e\u0441\u043f\u0440. \u00ab{1}\u00bb \u043e\u0441\u0442-\u043d\u043e",
"SubtitleDownloadFailureForItem": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u044b \u043a {0} \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c",
"HeaderUnidentified": "\u041d\u0435 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u043d\u043e",
- "HeaderImagePrimary": "\u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439",
+ "HeaderImagePrimary": "\u0413\u043e\u043b\u043e\u0432\u043d\u043e\u0439",
"HeaderImageBackdrop": "\u0417\u0430\u0434\u043d\u0438\u043a",
"HeaderImageLogo": "\u041b\u043e\u0433\u043e\u0442\u0438\u043f",
"HeaderUserPrimaryImage": "\u0420\u0438\u0441\u0443\u043d\u043e\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f",
@@ -133,23 +133,23 @@
"HeaderName": "\u0418\u043c\u044f (\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435)",
"HeaderDate": "\u0414\u0430\u0442\u0430",
"HeaderPremiereDate": "\u0414\u0430\u0442\u0430 \u043f\u0440\u0435\u043c\u044c\u0435\u0440\u044b",
- "HeaderDateAdded": "\u0414\u0430\u0442\u0430 \u0434\u043e\u0431-\u0438\u044f",
+ "HeaderDateAdded": "\u0414\u0430\u0442\u0430 \u0434\u043e\u0431.",
"HeaderReleaseDate": "\u0414\u0430\u0442\u0430 \u0432\u044b\u043f.",
"HeaderRuntime": "\u0414\u043b\u0438\u0442.",
- "HeaderPlayCount": "\u0427\u0438\u0441\u043b\u043e \u0432\u043e\u0441\u043f\u0440-\u0438\u0439",
+ "HeaderPlayCount": "\u041a\u043e\u043b-\u0432\u043e \u0432\u043e\u0441\u043f\u0440.",
"HeaderSeason": "\u0421\u0435\u0437\u043e\u043d",
- "HeaderSeasonNumber": "\u041d\u043e\u043c\u0435\u0440 \u0441\u0435\u0437\u043e\u043d\u0430",
+ "HeaderSeasonNumber": "\u2116 \u0441\u0435\u0437\u043e\u043d\u0430",
"HeaderSeries": "\u0421\u0435\u0440\u0438\u0430\u043b:",
"HeaderNetwork": "\u0422\u0435\u043b\u0435\u0441\u0435\u0442\u044c",
"HeaderYear": "\u0413\u043e\u0434:",
"HeaderYears": "\u0413\u043e\u0434\u044b:",
- "HeaderParentalRating": "\u0412\u043e\u0437\u0440. \u043a\u0430\u0442-\u0438\u044f",
+ "HeaderParentalRating": "\u0412\u043e\u0437\u0440. \u043a\u0430\u0442.",
"HeaderCommunityRating": "\u041e\u0431\u0449. \u043e\u0446\u0435\u043d\u043a\u0430",
"HeaderTrailers": "\u0422\u0440\u0435\u0439\u043b.",
"HeaderSpecials": "\u0421\u043f\u0435\u0446.",
"HeaderGameSystems": "\u0418\u0433\u0440. \u0441\u0438\u0441\u0442\u0435\u043c\u044b",
"HeaderPlayers": "\u0418\u0433\u0440\u043e\u043a\u0438:",
- "HeaderAlbumArtists": "\u0410\u043b\u044c\u0431\u043e\u043c. \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u0438",
+ "HeaderAlbumArtists": "\u0418\u0441\u043f-\u043b\u0438 \u0430\u043b\u044c\u0431\u043e\u043c\u0430",
"HeaderAlbums": "\u0410\u043b\u044c\u0431\u043e\u043c\u044b",
"HeaderDisc": "\u0414\u0438\u0441\u043a",
"HeaderTrack": "\u0414\u043e\u0440-\u043a\u0430",
@@ -172,5 +172,6 @@
"HeaderProducer": "\u041f\u0440\u043e\u0434\u044e\u0441\u0435\u0440\u044b",
"HeaderWriter": "\u0421\u0446\u0435\u043d\u0430\u0440\u0438\u0441\u0442\u044b",
"HeaderParentalRatings": "\u0412\u043e\u0437\u0440\u0430\u0441\u0442\u043d\u0430\u044f \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044f",
- "HeaderCommunityRatings": "\u041e\u0431\u0449. \u043e\u0446\u0435\u043d\u043a\u0438"
+ "HeaderCommunityRatings": "\u041e\u0431\u0449. \u043e\u0446\u0435\u043d\u043a\u0438",
+ "StartupEmbyServerIsLoading": "Emby Server \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442\u0441\u044f. \u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443 \u0432\u0441\u043a\u043e\u0440\u0435."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/sl-SI.json b/MediaBrowser.Server.Implementations/Localization/Core/sl-SI.json
index abe203804..e444c0e93 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/sl-SI.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/sl-SI.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/sv.json b/MediaBrowser.Server.Implementations/Localization/Core/sv.json
index 3a5a322c6..667b8e4b4 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/sv.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/sv.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/tr.json b/MediaBrowser.Server.Implementations/Localization/Core/tr.json
index f127cc816..810df2665 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/tr.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/tr.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/uk.json b/MediaBrowser.Server.Implementations/Localization/Core/uk.json
index ec9ca5a39..73c9b26f9 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/uk.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/uk.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/vi.json b/MediaBrowser.Server.Implementations/Localization/Core/vi.json
index 6e0c3ea20..75a5dbea7 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/vi.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/vi.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/zh-CN.json b/MediaBrowser.Server.Implementations/Localization/Core/zh-CN.json
index 54cd7e59b..3368e5ccd 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/zh-CN.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/zh-CN.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "\u5bb6\u957f\u5206\u7ea7",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/zh-HK.json b/MediaBrowser.Server.Implementations/Localization/Core/zh-HK.json
new file mode 100644
index 000000000..8b5a8ff0d
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Localization/Core/zh-HK.json
@@ -0,0 +1,177 @@
+{
+ "AppDeviceValues": "App: {0}, Device: {1}",
+ "UserDownloadingItemWithValues": "{0} is downloading {1}",
+ "FolderTypeMixed": "Mixed content",
+ "FolderTypeMovies": "Movies",
+ "FolderTypeMusic": "Music",
+ "FolderTypeAdultVideos": "Adult videos",
+ "FolderTypePhotos": "Photos",
+ "FolderTypeMusicVideos": "Music videos",
+ "FolderTypeHomeVideos": "Home videos",
+ "FolderTypeGames": "Games",
+ "FolderTypeBooks": "Books",
+ "FolderTypeTvShows": "TV",
+ "FolderTypeInherit": "\u7e7c\u627f",
+ "HeaderCastCrew": "\u6f14\u54e1\u9663\u5bb9",
+ "HeaderPeople": "People",
+ "ValueSpecialEpisodeName": "Special - {0}",
+ "LabelChapterName": "Chapter {0}",
+ "NameSeasonNumber": "Season {0}",
+ "LabelExit": "\u96e2\u958b",
+ "LabelVisitCommunity": "\u8a2a\u554f\u8a0e\u8ad6\u5340",
+ "LabelGithub": "Github",
+ "LabelApiDocumentation": "Api \u6587\u4ef6",
+ "LabelDeveloperResources": "\u958b\u767c\u8005\u8cc7\u6e90",
+ "LabelBrowseLibrary": "\u700f\u89bd\u8cc7\u6599\u5eab",
+ "LabelConfigureServer": "\u8a2d\u7f6e Emby",
+ "LabelRestartServer": "\u91cd\u555f\u4f3a\u670d\u5668",
+ "CategorySync": "\u540c\u6b65",
+ "CategoryUser": "User",
+ "CategorySystem": "System",
+ "CategoryApplication": "Application",
+ "CategoryPlugin": "Plugin",
+ "NotificationOptionPluginError": "Plugin failure",
+ "NotificationOptionApplicationUpdateAvailable": "Application update available",
+ "NotificationOptionApplicationUpdateInstalled": "Application update installed",
+ "NotificationOptionPluginUpdateInstalled": "Plugin update installed",
+ "NotificationOptionPluginInstalled": "Plugin installed",
+ "NotificationOptionPluginUninstalled": "Plugin uninstalled",
+ "NotificationOptionVideoPlayback": "Video playback started",
+ "NotificationOptionAudioPlayback": "Audio playback started",
+ "NotificationOptionGamePlayback": "Game playback started",
+ "NotificationOptionVideoPlaybackStopped": "Video playback stopped",
+ "NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
+ "NotificationOptionGamePlaybackStopped": "Game playback stopped",
+ "NotificationOptionTaskFailed": "Scheduled task failure",
+ "NotificationOptionInstallationFailed": "Installation failure",
+ "NotificationOptionNewLibraryContent": "New content added",
+ "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
+ "NotificationOptionCameraImageUploaded": "Camera image uploaded",
+ "NotificationOptionUserLockedOut": "User locked out",
+ "NotificationOptionServerRestartRequired": "Server restart required",
+ "ViewTypePlaylists": "Playlists",
+ "ViewTypeMovies": "Movies",
+ "ViewTypeTvShows": "TV",
+ "ViewTypeGames": "Games",
+ "ViewTypeMusic": "Music",
+ "ViewTypeMusicGenres": "Genres",
+ "ViewTypeMusicArtists": "Artists",
+ "ViewTypeBoxSets": "Collections",
+ "ViewTypeChannels": "Channels",
+ "ViewTypeLiveTV": "Live TV",
+ "ViewTypeLiveTvNowPlaying": "Now Airing",
+ "ViewTypeLatestGames": "Latest Games",
+ "ViewTypeRecentlyPlayedGames": "Recently Played",
+ "ViewTypeGameFavorites": "Favorites",
+ "ViewTypeGameSystems": "Game Systems",
+ "ViewTypeGameGenres": "Genres",
+ "ViewTypeTvResume": "Resume",
+ "ViewTypeTvNextUp": "Next Up",
+ "ViewTypeTvLatest": "Latest",
+ "ViewTypeTvShowSeries": "Series",
+ "ViewTypeTvGenres": "Genres",
+ "ViewTypeTvFavoriteSeries": "Favorite Series",
+ "ViewTypeTvFavoriteEpisodes": "Favorite Episodes",
+ "ViewTypeMovieResume": "Resume",
+ "ViewTypeMovieLatest": "Latest",
+ "ViewTypeMovieMovies": "Movies",
+ "ViewTypeMovieCollections": "Collections",
+ "ViewTypeMovieFavorites": "Favorites",
+ "ViewTypeMovieGenres": "Genres",
+ "ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
+ "ViewTypeMusicAlbums": "Albums",
+ "ViewTypeMusicAlbumArtists": "Album Artists",
+ "HeaderOtherDisplaySettings": "Display Settings",
+ "ViewTypeMusicSongs": "Songs",
+ "ViewTypeMusicFavorites": "Favorites",
+ "ViewTypeMusicFavoriteAlbums": "Favorite Albums",
+ "ViewTypeMusicFavoriteArtists": "Favorite Artists",
+ "ViewTypeMusicFavoriteSongs": "Favorite Songs",
+ "ViewTypeFolders": "Folders",
+ "ViewTypeLiveTvRecordingGroups": "Recordings",
+ "ViewTypeLiveTvChannels": "Channels",
+ "ScheduledTaskFailedWithName": "{0} failed",
+ "LabelRunningTimeValue": "Running time: {0}",
+ "ScheduledTaskStartedWithName": "{0} started",
+ "VersionNumber": "\u7248\u672c {0}",
+ "PluginInstalledWithName": "{0} was installed",
+ "PluginUpdatedWithName": "{0} was updated",
+ "PluginUninstalledWithName": "{0} was uninstalled",
+ "ItemAddedWithName": "{0} was added to the library",
+ "ItemRemovedWithName": "{0} was removed from the library",
+ "LabelIpAddressValue": "Ip address: {0}",
+ "DeviceOnlineWithName": "{0} is connected",
+ "UserOnlineFromDevice": "{0} is online from {1}",
+ "ProviderValue": "Provider: {0}",
+ "SubtitlesDownloadedForItem": "Subtitles downloaded for {0}",
+ "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
+ "UserCreatedWithName": "User {0} has been created",
+ "UserPasswordChangedWithName": "Password has been changed for user {0}",
+ "UserDeletedWithName": "User {0} has been deleted",
+ "MessageServerConfigurationUpdated": "Server configuration has been updated",
+ "MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated",
+ "MessageApplicationUpdated": "Emby Server has been updated",
+ "FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
+ "AuthenticationSucceededWithUserName": "{0} successfully authenticated",
+ "DeviceOfflineWithName": "{0} has disconnected",
+ "UserLockedOutWithName": "User {0} has been locked out",
+ "UserOfflineFromDevice": "{0} has disconnected from {1}",
+ "UserStartedPlayingItemWithValues": "{0} has started playing {1}",
+ "UserStoppedPlayingItemWithValues": "{0} has stopped playing {1}",
+ "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
+ "HeaderUnidentified": "Unidentified",
+ "HeaderImagePrimary": "Primary",
+ "HeaderImageBackdrop": "Backdrop",
+ "HeaderImageLogo": "Logo",
+ "HeaderUserPrimaryImage": "User Image",
+ "HeaderOverview": "Overview",
+ "HeaderShortOverview": "Short Overview",
+ "HeaderType": "Type",
+ "HeaderSeverity": "Severity",
+ "HeaderUser": "User",
+ "HeaderName": "Name",
+ "HeaderDate": "\u65e5\u671f",
+ "HeaderPremiereDate": "Premiere Date",
+ "HeaderDateAdded": "Date Added",
+ "HeaderReleaseDate": "Release date",
+ "HeaderRuntime": "Runtime",
+ "HeaderPlayCount": "Play Count",
+ "HeaderSeason": "Season",
+ "HeaderSeasonNumber": "Season number",
+ "HeaderSeries": "Series:",
+ "HeaderNetwork": "Network",
+ "HeaderYear": "Year:",
+ "HeaderYears": "Years:",
+ "HeaderParentalRating": "Parental Rating",
+ "HeaderCommunityRating": "Community rating",
+ "HeaderTrailers": "Trailers",
+ "HeaderSpecials": "Specials",
+ "HeaderGameSystems": "Game Systems",
+ "HeaderPlayers": "Players:",
+ "HeaderAlbumArtists": "Album Artists",
+ "HeaderAlbums": "Albums",
+ "HeaderDisc": "Disc",
+ "HeaderTrack": "Track",
+ "HeaderAudio": "Audio",
+ "HeaderVideo": "Video",
+ "HeaderEmbeddedImage": "Embedded image",
+ "HeaderResolution": "Resolution",
+ "HeaderSubtitles": "Subtitles",
+ "HeaderGenres": "Genres",
+ "HeaderCountries": "Countries",
+ "HeaderStatus": "\u72c0\u614b",
+ "HeaderTracks": "Tracks",
+ "HeaderMusicArtist": "Music artist",
+ "HeaderLocked": "Locked",
+ "HeaderStudios": "Studios",
+ "HeaderActor": "Actors",
+ "HeaderComposer": "Composers",
+ "HeaderDirector": "Directors",
+ "HeaderGuestStar": "Guest star",
+ "HeaderProducer": "Producers",
+ "HeaderWriter": "Writers",
+ "HeaderParentalRatings": "Parental Ratings",
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
+} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/zh-TW.json b/MediaBrowser.Server.Implementations/Localization/Core/zh-TW.json
index 787508176..2bcb5c132 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/zh-TW.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/zh-TW.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/LocalizationManager.cs b/MediaBrowser.Server.Implementations/Localization/LocalizationManager.cs
index 8c893c8d1..e776f4311 100644
--- a/MediaBrowser.Server.Implementations/Localization/LocalizationManager.cs
+++ b/MediaBrowser.Server.Implementations/Localization/LocalizationManager.cs
@@ -58,7 +58,7 @@ namespace MediaBrowser.Server.Implementations.Localization
var localizationPath = LocalizationPath;
- Directory.CreateDirectory(localizationPath);
+ _fileSystem.CreateDirectory(localizationPath);
var existingFiles = Directory.EnumerateFiles(localizationPath, "ratings-*.txt", SearchOption.TopDirectoryOnly)
.Select(Path.GetFileName)
@@ -212,7 +212,7 @@ namespace MediaBrowser.Server.Implementations.Localization
/// <returns>Dictionary{System.StringParentalRating}.</returns>
private void LoadRatings(string file)
{
- var dict = File.ReadAllLines(file).Select(i =>
+ var dict = File.ReadAllLines(file).Select(i =>
{
if (!string.IsNullOrWhiteSpace(i))
{
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index f0312cef6..7d2d74140 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -11,10 +11,10 @@
<AssemblyName>MediaBrowser.Server.Implementations</AssemblyName>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
- <ProductVersion>10.0.0</ProductVersion>
- <SchemaVersion>2.0</SchemaVersion>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<RestorePackages>true</RestorePackages>
+ <ReleaseVersion>
+ </ReleaseVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -24,7 +24,6 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
@@ -33,7 +32,6 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release Mono|AnyCPU' ">
<DebugType>none</DebugType>
@@ -42,35 +40,17 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<ItemGroup>
<Reference Include="Interfaces.IO">
<HintPath>..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll</HintPath>
</Reference>
- <Reference Include="MediaBrowser.Naming, Version=1.0.5614.25103, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\MediaBrowser.Naming.1.0.0.37\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
- </Reference>
- <Reference Include="Mono.Nat, Version=1.2.24.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Mono.Nat.1.2.24.0\lib\net40\Mono.Nat.dll</HintPath>
- </Reference>
- <Reference Include="MoreLinq, Version=1.1.17511.0, Culture=neutral, PublicKeyToken=384d532d7e88985d, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\morelinq.1.1.0\lib\net35\MoreLinq.dll</HintPath>
- </Reference>
<Reference Include="Patterns.Logging">
<HintPath>..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll</HintPath>
- <Private>True</Private>
</Reference>
<Reference Include="ServiceStack.Api.Swagger">
<HintPath>..\ThirdParty\ServiceStack\ServiceStack.Api.Swagger.dll</HintPath>
</Reference>
- <Reference Include="SocketHttpListener, Version=1.0.5634.16042, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\SocketHttpListener.1.0.0.7\lib\net45\SocketHttpListener.dll</HintPath>
- </Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data.SQLite">
@@ -100,6 +80,18 @@
<Reference Include="UniversalDetector">
<HintPath>..\ThirdParty\UniversalDetector\UniversalDetector.dll</HintPath>
</Reference>
+ <Reference Include="MediaBrowser.Naming">
+ <HintPath>..\packages\MediaBrowser.Naming.1.0.0.37\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
+ </Reference>
+ <Reference Include="Mono.Nat">
+ <HintPath>..\packages\Mono.Nat.1.2.24.0\lib\net40\Mono.Nat.dll</HintPath>
+ </Reference>
+ <Reference Include="MoreLinq">
+ <HintPath>..\packages\morelinq.1.1.1\lib\net35\MoreLinq.dll</HintPath>
+ </Reference>
+ <Reference Include="SocketHttpListener">
+ <HintPath>..\packages\SocketHttpListener.1.0.0.7\lib\net45\SocketHttpListener.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\SharedVersion.cs">
@@ -334,7 +326,6 @@
<Compile Include="Sync\SyncRepository.cs" />
<Compile Include="Sync\SyncConvertScheduledTask.cs" />
<Compile Include="Sync\TargetDataProvider.cs" />
- <Compile Include="Themes\AppThemeManager.cs" />
<Compile Include="TV\TVSeriesManager.cs" />
<Compile Include="Udp\UdpMessageReceivedEventArgs.cs" />
<Compile Include="Udp\UdpServer.cs" />
@@ -413,6 +404,7 @@
<EmbeddedResource Include="Localization\Core\vi.json" />
<EmbeddedResource Include="Localization\Core\zh-CN.json" />
<EmbeddedResource Include="Localization\Core\zh-TW.json" />
+ <EmbeddedResource Include="Localization\Core\zh-HK.json" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs b/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs
index 6b99883a5..9ea553d2d 100644
--- a/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs
+++ b/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs
@@ -138,7 +138,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
try
{
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
using (var stream = await _encoder.ExtractVideoImage(inputPath, protocol, video.Video3DFormat, time, cancellationToken).ConfigureAwait(false))
{
diff --git a/MediaBrowser.Server.Implementations/News/NewsEntryPoint.cs b/MediaBrowser.Server.Implementations/News/NewsEntryPoint.cs
index 619384b6f..0266756c3 100644
--- a/MediaBrowser.Server.Implementations/News/NewsEntryPoint.cs
+++ b/MediaBrowser.Server.Implementations/News/NewsEntryPoint.cs
@@ -71,7 +71,7 @@ namespace MediaBrowser.Server.Implementations.News
{
DateTime? lastUpdate = null;
- if (File.Exists(path))
+ if (_fileSystem.FileExists(path))
{
lastUpdate = _fileSystem.GetLastWriteTimeUtc(path);
}
diff --git a/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs b/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs
index 9f87483ba..c9f7165cb 100644
--- a/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs
@@ -1,15 +1,18 @@
-using MediaBrowser.Common.Progress;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Progress;
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Controller.Entities.Audio;
namespace MediaBrowser.Server.Implementations.Persistence
{
@@ -19,13 +22,15 @@ namespace MediaBrowser.Server.Implementations.Persistence
private readonly IItemRepository _itemRepo;
private readonly ILogger _logger;
private readonly IServerConfigurationManager _config;
+ private readonly IFileSystem _fileSystem;
- public CleanDatabaseScheduledTask(ILibraryManager libraryManager, IItemRepository itemRepo, ILogger logger, IServerConfigurationManager config)
+ public CleanDatabaseScheduledTask(ILibraryManager libraryManager, IItemRepository itemRepo, ILogger logger, IServerConfigurationManager config, IFileSystem fileSystem)
{
_libraryManager = libraryManager;
_itemRepo = itemRepo;
_logger = logger;
_config = config;
+ _fileSystem = fileSystem;
}
public string Name
@@ -46,15 +51,18 @@ namespace MediaBrowser.Server.Implementations.Persistence
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
{
var innerProgress = new ActionableProgress<double>();
- innerProgress.RegisterAction(p => progress.Report(.95 * p));
+ innerProgress.RegisterAction(p => progress.Report(.4 * p));
await UpdateToLatestSchema(cancellationToken, innerProgress).ConfigureAwait(false);
innerProgress = new ActionableProgress<double>();
- innerProgress.RegisterAction(p => progress.Report(95 + (.05 * p)));
-
- //await CleanDeadItems(cancellationToken, innerProgress).ConfigureAwait(false);
+ innerProgress.RegisterAction(p => progress.Report(40 + (.05 * p)));
+ await CleanDeadItems(cancellationToken, innerProgress).ConfigureAwait(false);
+ progress.Report(45);
+ innerProgress = new ActionableProgress<double>();
+ innerProgress.RegisterAction(p => progress.Report(45 + (.55 * p)));
+ await CleanDeletedItems(cancellationToken, innerProgress).ConfigureAwait(false);
progress.Report(100);
}
@@ -77,6 +85,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
cancellationToken.ThrowIfCancellationRequested();
+ if (itemId == Guid.Empty)
+ {
+ // Somehow some invalid data got into the db. It probably predates the boundary checking
+ continue;
+ }
+
var item = _libraryManager.GetItemById(itemId);
if (item != null)
@@ -147,11 +161,60 @@ namespace MediaBrowser.Server.Implementations.Persistence
progress.Report(100);
}
+ private async Task CleanDeletedItems(CancellationToken cancellationToken, IProgress<double> progress)
+ {
+ var result = _itemRepo.GetItemIdsWithPath(new InternalItemsQuery
+ {
+ IsOffline = false,
+ LocationType = LocationType.FileSystem,
+ //Limit = limit,
+
+ // These have their own cleanup routines
+ ExcludeItemTypes = new[] { typeof(Person).Name, typeof(Genre).Name, typeof(MusicGenre).Name, typeof(GameGenre).Name, typeof(Studio).Name, typeof(Year).Name }
+ });
+
+ var numComplete = 0;
+ var numItems = result.Items.Length;
+
+ foreach (var item in result.Items)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ var path = item.Item2;
+
+ try
+ {
+ if (!_fileSystem.FileExists(path) && !_fileSystem.DirectoryExists(path))
+ {
+ var libraryItem = _libraryManager.GetItemById(item.Item1);
+
+ await _libraryManager.DeleteItem(libraryItem, new DeleteOptions
+ {
+ DeleteFileLocation = false
+ });
+ }
+ }
+ catch (OperationCanceledException)
+ {
+ throw;
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error in CleanDeletedItems. File {0}", ex, path);
+ }
+
+ numComplete++;
+ double percent = numComplete;
+ percent /= numItems;
+ progress.Report(percent * 100);
+ }
+ }
+
public IEnumerable<ITaskTrigger> GetDefaultTriggers()
{
return new ITaskTrigger[]
{
- new IntervalTrigger{ Interval = TimeSpan.FromDays(1)}
+ new IntervalTrigger{ Interval = TimeSpan.FromHours(6)}
};
}
}
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
index 00ebf7ea6..3c06973b4 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
@@ -72,7 +72,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
private IDbCommand _deletePeopleCommand;
private IDbCommand _savePersonCommand;
- private const int LatestSchemaVersion = 6;
+ private const int LatestSchemaVersion = 7;
/// <summary>
/// Initializes a new instance of the <see cref="SqliteItemRepository"/> class.
@@ -175,6 +175,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
_connection.AddColumn(_logger, "TypedBaseItems", "ForcedSortName", "Text");
_connection.AddColumn(_logger, "TypedBaseItems", "IsOffline", "BIT");
+ _connection.AddColumn(_logger, "TypedBaseItems", "LocationType", "Text");
PrepareStatements();
@@ -187,11 +188,21 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// </summary>
private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
- private string[] _retriveItemColumns =
+ private readonly string[] _retriveItemColumns =
{
"type",
"data",
- "IsOffline"
+ "StartDate",
+ "EndDate",
+ "IsOffline",
+ "ChannelId",
+ "IsMovie",
+ "IsSports",
+ "IsKids",
+ "CommunityRating",
+ "CustomRating",
+ "IndexNumber",
+ "IsLocked"
};
/// <summary>
@@ -235,7 +246,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
"DateCreated",
"DateModified",
"ForcedSortName",
- "IsOffline"
+ "IsOffline",
+ "LocationType"
};
_saveItemCommand = _connection.CreateCommand();
_saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values (";
@@ -405,6 +417,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveItemCommand.GetParameter(index++).Value = item.ForcedSortName;
_saveItemCommand.GetParameter(index++).Value = item.IsOffline;
+ _saveItemCommand.GetParameter(index++).Value = item.LocationType.ToString();
_saveItemCommand.Transaction = transaction;
@@ -511,7 +524,65 @@ namespace MediaBrowser.Server.Implementations.Persistence
if (!reader.IsDBNull(2))
{
- item.IsOffline = reader.GetBoolean(2);
+ var hasStartDate = item as IHasStartDate;
+ if (hasStartDate != null)
+ {
+ hasStartDate.StartDate = reader.GetDateTime(2).ToUniversalTime();
+ }
+ }
+
+ if (!reader.IsDBNull(3))
+ {
+ item.EndDate = reader.GetDateTime(3).ToUniversalTime();
+ }
+
+ if (!reader.IsDBNull(4))
+ {
+ item.IsOffline = reader.GetBoolean(4);
+ }
+
+ if (!reader.IsDBNull(5))
+ {
+ item.ChannelId = reader.GetString(5);
+ }
+
+ var hasProgramAttributes = item as IHasProgramAttributes;
+ if (hasProgramAttributes != null)
+ {
+ if (!reader.IsDBNull(6))
+ {
+ hasProgramAttributes.IsMovie = reader.GetBoolean(6);
+ }
+
+ if (!reader.IsDBNull(7))
+ {
+ hasProgramAttributes.IsSports = reader.GetBoolean(7);
+ }
+
+ if (!reader.IsDBNull(8))
+ {
+ hasProgramAttributes.IsKids = reader.GetBoolean(8);
+ }
+ }
+
+ if (!reader.IsDBNull(9))
+ {
+ item.CommunityRating = reader.GetFloat(9);
+ }
+
+ if (!reader.IsDBNull(10))
+ {
+ item.CustomRating = reader.GetString(10);
+ }
+
+ if (!reader.IsDBNull(11))
+ {
+ item.IndexNumber = reader.GetInt32(11);
+ }
+
+ if (!reader.IsDBNull(12))
+ {
+ item.IsLocked = reader.GetBoolean(12);
}
return item;
@@ -882,6 +953,75 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
+ public QueryResult<Tuple<Guid, string>> GetItemIdsWithPath(InternalItemsQuery query)
+ {
+ if (query == null)
+ {
+ throw new ArgumentNullException("query");
+ }
+
+ CheckDisposed();
+
+ using (var cmd = _connection.CreateCommand())
+ {
+ cmd.CommandText = "select guid,path from TypedBaseItems";
+
+ var whereClauses = GetWhereClauses(query, cmd, false);
+
+ var whereTextWithoutPaging = whereClauses.Count == 0 ?
+ string.Empty :
+ " where " + string.Join(" AND ", whereClauses.ToArray());
+
+ whereClauses = GetWhereClauses(query, cmd, true);
+
+ var whereText = whereClauses.Count == 0 ?
+ string.Empty :
+ " where " + string.Join(" AND ", whereClauses.ToArray());
+
+ cmd.CommandText += whereText;
+
+ cmd.CommandText += GetOrderByText(query);
+
+ if (query.Limit.HasValue)
+ {
+ cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture);
+ }
+
+ cmd.CommandText += "; select count (guid) from TypedBaseItems" + whereTextWithoutPaging;
+
+ var list = new List<Tuple<Guid, string>>();
+ var count = 0;
+
+ _logger.Debug(cmd.CommandText);
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
+ {
+ while (reader.Read())
+ {
+ var id = reader.GetGuid(0);
+ string path = null;
+
+ if (!reader.IsDBNull(1))
+ {
+ path = reader.GetString(1);
+ }
+ list.Add(new Tuple<Guid, string>(id, path));
+ }
+
+ if (reader.NextResult() && reader.Read())
+ {
+ count = reader.GetInt32(0);
+ }
+ }
+
+ return new QueryResult<Tuple<Guid, string>>()
+ {
+ Items = list.ToArray(),
+ TotalRecordCount = count
+ };
+ }
+ }
+
public QueryResult<Guid> GetItemIds(InternalItemsQuery query)
{
if (query == null)
@@ -960,6 +1100,16 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
cmd.Parameters.Add(cmd, "@SchemaVersion", DbType.Int32).Value = LatestSchemaVersion;
}
+ if (query.IsOffline.HasValue)
+ {
+ whereClauses.Add("IsOffline=@IsOffline");
+ cmd.Parameters.Add(cmd, "@IsOffline", DbType.Boolean).Value = query.IsOffline;
+ }
+ if (query.LocationType.HasValue)
+ {
+ whereClauses.Add("LocationType=@LocationType");
+ cmd.Parameters.Add(cmd, "@LocationType", DbType.String).Value = query.LocationType.Value;
+ }
if (query.IsMovie.HasValue)
{
whereClauses.Add("IsMovie=@IsMovie");
diff --git a/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs b/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs
index 4b7e1c3a7..bd5c571fe 100644
--- a/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs
@@ -92,7 +92,7 @@ namespace MediaBrowser.Server.Implementations.Photos
CancellationToken cancellationToken)
{
var outputPath = Path.Combine(ApplicationPaths.TempDirectory, Guid.NewGuid() + ".png");
- Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
+ FileSystem.CreateDirectory(Path.GetDirectoryName(outputPath));
var imageCreated = await CreateImage(item, itemsWithImages, outputPath, imageType, 0).ConfigureAwait(false);
if (!imageCreated)
@@ -145,7 +145,7 @@ namespace MediaBrowser.Server.Implementations.Photos
private Task<bool> CreateCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height)
{
- Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
+ FileSystem.CreateDirectory(Path.GetDirectoryName(outputPath));
var options = new ImageCollageOptions
{
diff --git a/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs b/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs
index 3ec41b6dc..0daef052d 100644
--- a/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs
+++ b/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs
@@ -4,6 +4,7 @@ using MediaBrowser.Controller.Playlists;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.Playlists
{
@@ -46,17 +47,19 @@ namespace MediaBrowser.Server.Implementations.Playlists
public class PlaylistsDynamicFolder : IVirtualFolderCreator
{
private readonly IApplicationPaths _appPaths;
+ private readonly IFileSystem _fileSystem;
- public PlaylistsDynamicFolder(IApplicationPaths appPaths)
+ public PlaylistsDynamicFolder(IApplicationPaths appPaths, IFileSystem fileSystem)
{
_appPaths = appPaths;
+ _fileSystem = fileSystem;
}
public BasePluginFolder GetFolder()
{
var path = Path.Combine(_appPaths.DataPath, "playlists");
- Directory.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
return new PlaylistsFolder
{
diff --git a/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs b/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs
index 857cf743f..53f2211d3 100644
--- a/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs
+++ b/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs
@@ -110,7 +110,7 @@ namespace MediaBrowser.Server.Implementations.Playlists
try
{
- Directory.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
var playlist = new Playlist
{
@@ -128,7 +128,7 @@ namespace MediaBrowser.Server.Implementations.Playlists
await parentFolder.AddChild(playlist, CancellationToken.None).ConfigureAwait(false);
- await playlist.RefreshMetadata(new MetadataRefreshOptions { ForceSave = true }, CancellationToken.None)
+ await playlist.RefreshMetadata(new MetadataRefreshOptions(_fileSystem) { ForceSave = true }, CancellationToken.None)
.ConfigureAwait(false);
if (options.ItemIdList.Count > 0)
@@ -150,7 +150,7 @@ namespace MediaBrowser.Server.Implementations.Playlists
private string GetTargetPath(string path)
{
- while (Directory.Exists(path))
+ while (_fileSystem.DirectoryExists(path))
{
path += "1";
}
@@ -196,7 +196,7 @@ namespace MediaBrowser.Server.Implementations.Playlists
await playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
- _providerManager.QueueRefresh(playlist.Id, new MetadataRefreshOptions
+ _providerManager.QueueRefresh(playlist.Id, new MetadataRefreshOptions(_fileSystem)
{
ForceSave = true
});
@@ -223,7 +223,7 @@ namespace MediaBrowser.Server.Implementations.Playlists
await playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
- _providerManager.QueueRefresh(playlist.Id, new MetadataRefreshOptions
+ _providerManager.QueueRefresh(playlist.Id, new MetadataRefreshOptions(_fileSystem)
{
ForceSave = true
});
diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
index b23aaeeff..f8dc08e26 100644
--- a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
+++ b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
@@ -11,6 +11,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.ScheduledTasks
{
@@ -39,6 +40,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
private readonly IApplicationPaths _appPaths;
private readonly IEncodingManager _encodingManager;
+ private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="ChapterImagesTask" /> class.
@@ -46,13 +48,14 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
/// <param name="logManager">The log manager.</param>
/// <param name="libraryManager">The library manager.</param>
/// <param name="itemRepo">The item repo.</param>
- public ChapterImagesTask(ILogManager logManager, ILibraryManager libraryManager, IItemRepository itemRepo, IApplicationPaths appPaths, IEncodingManager encodingManager)
+ public ChapterImagesTask(ILogManager logManager, ILibraryManager libraryManager, IItemRepository itemRepo, IApplicationPaths appPaths, IEncodingManager encodingManager, IFileSystem fileSystem)
{
_logger = logManager.GetLogger(GetType().Name);
_libraryManager = libraryManager;
_itemRepo = itemRepo;
_appPaths = appPaths;
_encodingManager = encodingManager;
+ _fileSystem = fileSystem;
}
/// <summary>
@@ -94,7 +97,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
try
{
- previouslyFailedImages = File.ReadAllText(failHistoryPath)
+ previouslyFailedImages = _fileSystem.ReadAllText(failHistoryPath)
.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries)
.ToList();
}
@@ -132,9 +135,9 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
var parentPath = Path.GetDirectoryName(failHistoryPath);
- Directory.CreateDirectory(parentPath);
+ _fileSystem.CreateDirectory(parentPath);
- File.WriteAllText(failHistoryPath, string.Join("|", previouslyFailedImages.ToArray()));
+ _fileSystem.WriteAllText(failHistoryPath, string.Join("|", previouslyFailedImages.ToArray()));
}
numComplete++;
diff --git a/MediaBrowser.Server.Implementations/Sync/MediaSync.cs b/MediaBrowser.Server.Implementations/Sync/MediaSync.cs
index 86ef58e42..83dd13c05 100644
--- a/MediaBrowser.Server.Implementations/Sync/MediaSync.cs
+++ b/MediaBrowser.Server.Implementations/Sync/MediaSync.cs
@@ -147,7 +147,14 @@ namespace MediaBrowser.Server.Implementations.Sync
progress.Report(totalProgress);
});
- await GetItem(provider, dataProvider, target, serverId, serverName, jobItem, innerProgress, cancellationToken).ConfigureAwait(false);
+ try
+ {
+ await GetItem(provider, dataProvider, target, serverId, serverName, jobItem, innerProgress, cancellationToken).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error syncing item", ex);
+ }
numComplete++;
startingPercent = numComplete;
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
index 1061a373e..c9099dbe7 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
@@ -702,7 +702,7 @@ namespace MediaBrowser.Server.Implementations.Sync
var path = Path.Combine(temporaryPath, filename);
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
using (var stream = await _subtitleEncoder.GetSubtitles(streamInfo.ItemId, streamInfo.MediaSourceId, subtitleStreamIndex, subtitleStreamInfo.Format, 0, null, cancellationToken).ConfigureAwait(false))
{
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs
index 18fcb4e79..15d196877 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs
@@ -516,60 +516,25 @@ namespace MediaBrowser.Server.Implementations.Sync
return false;
}
- if (!item.RunTimeTicks.HasValue)
- {
- return false;
- }
-
var video = item as Video;
if (video != null)
{
- if (video.VideoType == VideoType.Iso || video.VideoType == VideoType.HdDvd)
- {
- return false;
- }
-
if (video.IsPlaceHolder)
{
return false;
}
- if (video.IsArchive)
- {
- return false;
- }
-
- if (video.IsStacked)
- {
- return false;
- }
-
if (video.IsShortcut)
{
return false;
}
}
- var game = item as Game;
- if (game != null)
- {
- if (game.IsMultiPart)
- {
- return false;
- }
- }
-
if (item is LiveTvChannel || item is IChannelItem)
{
return false;
}
- // It would be nice to support these later
- if (item is Game || item is Book)
- {
- return false;
- }
-
return true;
}
@@ -997,8 +962,6 @@ namespace MediaBrowser.Server.Implementations.Sync
return false;
}
- // TODO: Make sure it hasn't been deleted
-
return true;
}
diff --git a/MediaBrowser.Server.Implementations/Themes/AppThemeManager.cs b/MediaBrowser.Server.Implementations/Themes/AppThemeManager.cs
deleted file mode 100644
index 2711c08aa..000000000
--- a/MediaBrowser.Server.Implementations/Themes/AppThemeManager.cs
+++ /dev/null
@@ -1,168 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.Themes;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Themes;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-
-namespace MediaBrowser.Server.Implementations.Themes
-{
- public class AppThemeManager : IAppThemeManager
- {
- private readonly IServerApplicationPaths _appPaths;
- private readonly IFileSystem _fileSystem;
- private readonly IJsonSerializer _json;
- private readonly ILogger _logger;
-
- private readonly string[] _supportedImageExtensions = { ".png", ".jpg", ".jpeg" };
-
- public AppThemeManager(IServerApplicationPaths appPaths, IFileSystem fileSystem, IJsonSerializer json, ILogger logger)
- {
- _appPaths = appPaths;
- _fileSystem = fileSystem;
- _json = json;
- _logger = logger;
- }
-
- private string ThemePath
- {
- get
- {
- return Path.Combine(_appPaths.ProgramDataPath, "appthemes");
- }
- }
-
- private string GetThemesPath(string applicationName)
- {
- if (string.IsNullOrWhiteSpace(applicationName))
- {
- throw new ArgumentNullException("applicationName");
- }
-
- // Force everything lowercase for consistency and maximum compatibility with case-sensitive file systems
- var name = _fileSystem.GetValidFilename(applicationName.ToLower());
-
- return Path.Combine(ThemePath, name);
- }
-
- private string GetThemePath(string applicationName, string name)
- {
- if (string.IsNullOrWhiteSpace(name))
- {
- throw new ArgumentNullException("name");
- }
-
- // Force everything lowercase for consistency and maximum compatibility with case-sensitive file systems
- name = _fileSystem.GetValidFilename(name.ToLower());
-
- return Path.Combine(GetThemesPath(applicationName), name);
- }
-
- private string GetImagesPath(string applicationName, string themeName)
- {
- return Path.Combine(GetThemePath(applicationName, themeName), "images");
- }
-
- public IEnumerable<AppThemeInfo> GetThemes(string applicationName)
- {
- var path = GetThemesPath(applicationName);
-
- try
- {
- return Directory
- .EnumerateFiles(path, "*", SearchOption.AllDirectories)
- .Where(i => string.Equals(Path.GetExtension(i), ".json", StringComparison.OrdinalIgnoreCase))
- .Select(i =>
- {
- try
- {
- return _json.DeserializeFromFile<AppThemeInfo>(i);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error deserializing {0}", ex, i);
- return null;
- }
-
- }).Where(i => i != null);
- }
- catch (DirectoryNotFoundException)
- {
- return new List<AppThemeInfo>();
- }
- }
-
- public AppTheme GetTheme(string applicationName, string name)
- {
- var themePath = GetThemePath(applicationName, name);
- var file = Path.Combine(themePath, "theme.json");
-
- var imagesPath = GetImagesPath(applicationName, name);
-
- var theme = _json.DeserializeFromFile<AppTheme>(file);
-
- theme.Images = new DirectoryInfo(imagesPath)
- .EnumerateFiles("*", SearchOption.TopDirectoryOnly)
- .Where(i => _supportedImageExtensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase))
- .Select(GetThemeImage)
- .ToList();
-
- return theme;
- }
-
- private ThemeImage GetThemeImage(FileInfo file)
- {
- var dateModified = _fileSystem.GetLastWriteTimeUtc(file);
-
- var cacheTag = (file.FullName + dateModified.Ticks).GetMD5().ToString("N");
-
- return new ThemeImage
- {
- CacheTag = cacheTag,
- Name = file.Name
- };
- }
-
- public void SaveTheme(AppTheme theme)
- {
- var themePath = GetThemePath(theme.AppName, theme.Name);
- var file = Path.Combine(themePath, "theme.json");
-
- Directory.CreateDirectory(themePath);
-
- // Clone it so that we don't serialize all the images - they're always dynamic
- var clone = new AppTheme
- {
- AppName = theme.AppName,
- Name = theme.Name,
- Options = theme.Options,
- Images = null
- };
-
- _json.SerializeToFile(clone, file);
- }
-
- public InternalThemeImage GetImageImageInfo(string applicationName, string themeName, string imageName)
- {
- var imagesPath = GetImagesPath(applicationName, themeName);
-
- var file = new DirectoryInfo(imagesPath).EnumerateFiles("*", SearchOption.TopDirectoryOnly)
- .First(i => string.Equals(i.Name, imageName, StringComparison.OrdinalIgnoreCase));
-
- var themeImage = GetThemeImage(file);
-
- return new InternalThemeImage
- {
- CacheTag = themeImage.CacheTag,
- Name = themeImage.Name,
- Path = file.FullName,
- DateModified = _fileSystem.GetLastWriteTimeUtc(file)
- };
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs b/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs
index 8321ab952..2f5702983 100644
--- a/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs
@@ -66,14 +66,14 @@ namespace MediaBrowser.Server.Implementations.UserViews
}
var isUsingCollectionStrip = IsUsingCollectionStrip(view);
- var recursive = isUsingCollectionStrip && !new[] { CollectionType.Playlists, CollectionType.Channels }.Contains(view.ViewType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
+ var recursive = isUsingCollectionStrip && !new[] { CollectionType.Channels, CollectionType.BoxSets, CollectionType.Playlists }.Contains(view.ViewType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
var result = await view.GetItems(new InternalItemsQuery
{
User = (view.UserId.HasValue ? _userManager.GetUserById(view.UserId.Value) : null),
CollapseBoxSetItems = false,
Recursive = recursive,
- ExcludeItemTypes = new[] { "UserView", "CollectionFolder", "Playlist" }
+ ExcludeItemTypes = new[] { "UserView", "CollectionFolder" }
}).ConfigureAwait(false);
@@ -147,7 +147,14 @@ namespace MediaBrowser.Server.Implementations.UserViews
{
CollectionType.Movies,
CollectionType.TvShows,
- CollectionType.Music
+ CollectionType.Music,
+ CollectionType.Games,
+ CollectionType.Books,
+ CollectionType.MusicVideos,
+ CollectionType.HomeVideos,
+ CollectionType.BoxSets,
+ CollectionType.Playlists,
+ CollectionType.Photos
};
return collectionStripViewTypes.Contains(view.ViewType ?? string.Empty);
diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config
index 92388c99e..758791868 100644
--- a/MediaBrowser.Server.Implementations/packages.config
+++ b/MediaBrowser.Server.Implementations/packages.config
@@ -3,7 +3,7 @@
<package id="Interfaces.IO" version="1.0.0.5" targetFramework="net45" />
<package id="MediaBrowser.Naming" version="1.0.0.37" targetFramework="net45" />
<package id="Mono.Nat" version="1.2.24.0" targetFramework="net45" />
- <package id="morelinq" version="1.1.0" targetFramework="net45" />
+ <package id="morelinq" version="1.1.1" targetFramework="net45" />
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
<package id="SocketHttpListener" version="1.0.0.7" targetFramework="net45" />
</packages> \ No newline at end of file