aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MediaBrowser.Api/ApiEntryPoint.cs23
-rw-r--r--MediaBrowser.Api/ConfigurationService.cs2
-rw-r--r--MediaBrowser.Api/IHasDtoOptions.cs12
-rw-r--r--MediaBrowser.Api/Images/ImageService.cs13
-rw-r--r--MediaBrowser.Api/ItemUpdateService.cs160
-rw-r--r--MediaBrowser.Api/Library/LibraryService.cs47
-rw-r--r--MediaBrowser.Api/LiveTv/LiveTvService.cs2
-rw-r--r--MediaBrowser.Api/Movies/CollectionService.cs5
-rw-r--r--MediaBrowser.Api/Movies/MoviesService.cs28
-rw-r--r--MediaBrowser.Api/NotificationsService.cs2
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs89
-rw-r--r--MediaBrowser.Api/Playback/Hls/BaseHlsService.cs29
-rw-r--r--MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs22
-rw-r--r--MediaBrowser.Api/Playback/Hls/MpegDashService.cs18
-rw-r--r--MediaBrowser.Api/Playback/Hls/VideoHlsService.cs17
-rw-r--r--MediaBrowser.Api/Playback/Progressive/AudioService.cs2
-rw-r--r--MediaBrowser.Api/Playback/Progressive/VideoService.cs14
-rw-r--r--MediaBrowser.Api/Playback/StreamState.cs1
-rw-r--r--MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs1
-rw-r--r--MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs1
-rw-r--r--MediaBrowser.Api/Session/SessionsService.cs26
-rw-r--r--MediaBrowser.Api/Subtitles/SubtitleService.cs7
-rw-r--r--MediaBrowser.Api/Sync/SyncService.cs76
-rw-r--r--MediaBrowser.Api/System/ActivityLogWebSocketListener.cs4
-rw-r--r--MediaBrowser.Api/System/SystemInfoWebSocketListener.cs1
-rw-r--r--MediaBrowser.Api/UserLibrary/ArtistsService.cs9
-rw-r--r--MediaBrowser.Api/UserLibrary/GameGenresService.cs7
-rw-r--r--MediaBrowser.Api/UserLibrary/GenresService.cs7
-rw-r--r--MediaBrowser.Api/UserLibrary/MusicGenresService.cs7
-rw-r--r--MediaBrowser.Api/UserLibrary/PersonsService.cs7
-rw-r--r--MediaBrowser.Api/UserLibrary/StudiosService.cs7
-rw-r--r--MediaBrowser.Api/UserLibrary/UserLibraryService.cs45
-rw-r--r--MediaBrowser.Api/UserLibrary/YearsService.cs7
-rw-r--r--MediaBrowser.Api/UserService.cs150
-rw-r--r--MediaBrowser.Api/VideosService.cs16
-rw-r--r--MediaBrowser.Common.Implementations/BaseApplicationHost.cs2
-rw-r--r--MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs51
-rw-r--r--MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs (renamed from MediaBrowser.Common/Configuration/ConfigurationHelper.cs)17
-rw-r--r--MediaBrowser.Common.Implementations/Devices/DeviceId.cs5
-rw-r--r--MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs4
-rw-r--r--MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj1
-rw-r--r--MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs4
-rw-r--r--MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs17
-rw-r--r--MediaBrowser.Common.Implementations/packages.config1
-rw-r--r--MediaBrowser.Common/Configuration/IConfigurationFactory.cs5
-rw-r--r--MediaBrowser.Common/Extensions/BaseExtensions.cs11
-rw-r--r--MediaBrowser.Common/MediaBrowser.Common.csproj8
-rw-r--r--MediaBrowser.Common/Plugins/BasePlugin.cs43
-rw-r--r--MediaBrowser.Controller/Channels/Channel.cs2
-rw-r--r--MediaBrowser.Controller/Channels/ChannelAudioItem.cs5
-rw-r--r--MediaBrowser.Controller/Channels/ChannelFolderItem.cs3
-rw-r--r--MediaBrowser.Controller/Channels/ChannelVideoItem.cs3
-rw-r--r--MediaBrowser.Controller/Devices/IDeviceManager.cs8
-rw-r--r--MediaBrowser.Controller/Entities/Audio/Audio.cs18
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs3
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicArtist.cs37
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs13
-rw-r--r--MediaBrowser.Controller/Entities/Book.cs3
-rw-r--r--MediaBrowser.Controller/Entities/CollectionFolder.cs16
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs8
-rw-r--r--MediaBrowser.Controller/Entities/Game.cs3
-rw-r--r--MediaBrowser.Controller/Entities/GameSystem.cs3
-rw-r--r--MediaBrowser.Controller/Entities/IHasMediaSources.cs4
-rw-r--r--MediaBrowser.Controller/Entities/Movies/BoxSet.cs14
-rw-r--r--MediaBrowser.Controller/Entities/Movies/Movie.cs12
-rw-r--r--MediaBrowser.Controller/Entities/MusicVideo.cs3
-rw-r--r--MediaBrowser.Controller/Entities/Photo.cs5
-rw-r--r--MediaBrowser.Controller/Entities/PhotoAlbum.cs5
-rw-r--r--MediaBrowser.Controller/Entities/TV/Episode.cs61
-rw-r--r--MediaBrowser.Controller/Entities/TV/Season.cs79
-rw-r--r--MediaBrowser.Controller/Entities/TV/Series.cs15
-rw-r--r--MediaBrowser.Controller/Entities/Trailer.cs3
-rw-r--r--MediaBrowser.Controller/Entities/User.cs72
-rw-r--r--MediaBrowser.Controller/Entities/UserView.cs3
-rw-r--r--MediaBrowser.Controller/Entities/Video.cs17
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs37
-rw-r--r--MediaBrowser.Controller/Library/IUserDataManager.cs4
-rw-r--r--MediaBrowser.Controller/Library/IUserManager.cs29
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs3
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvChannel.cs3
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvProgram.cs3
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs3
-rw-r--r--MediaBrowser.Controller/LiveTv/RecordingGroup.cs3
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj9
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingOptions.cs80
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingResult.cs13
-rw-r--r--MediaBrowser.Controller/MediaEncoding/MediaStreamSelector.cs12
-rw-r--r--MediaBrowser.Controller/MediaEncoding/VideoEncodingOptions.cs26
-rw-r--r--MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs (renamed from MediaBrowser.Common/Net/BasePeriodicWebSocketListener.cs)5
-rw-r--r--MediaBrowser.Controller/Net/IWebSocket.cs (renamed from MediaBrowser.Common/Net/IWebSocket.cs)2
-rw-r--r--MediaBrowser.Controller/Net/IWebSocketConnection.cs (renamed from MediaBrowser.Common/Net/IWebSocketConnection.cs)2
-rw-r--r--MediaBrowser.Controller/Net/IWebSocketListener.cs (renamed from MediaBrowser.Common/Net/IWebSocketListener.cs)5
-rw-r--r--MediaBrowser.Controller/Net/WebSocketConnectEventArgs.cs (renamed from MediaBrowser.Common/Net/WebSocketConnectEventArgs.cs)2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessageInfo.cs (renamed from MediaBrowser.Common/Net/WebSocketMessageInfo.cs)2
-rw-r--r--MediaBrowser.Controller/Providers/DirectoryService.cs5
-rw-r--r--MediaBrowser.Controller/Sync/ISyncManager.cs22
-rw-r--r--MediaBrowser.Controller/Sync/ISyncProvider.cs5
-rw-r--r--MediaBrowser.Dlna/Didl/DidlBuilder.cs1
-rw-r--r--MediaBrowser.LocalMetadata/BaseXmlProvider.cs8
-rw-r--r--MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs19
-rw-r--r--MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs2
-rw-r--r--MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs2
-rw-r--r--MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs45
-rw-r--r--MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj1
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs4
-rw-r--r--MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj52
-rw-r--r--MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj48
-rw-r--r--MediaBrowser.Model/ApiClient/IApiClient.cs73
-rw-r--r--MediaBrowser.Model/Configuration/CinemaModeConfiguration.cs1
-rw-r--r--MediaBrowser.Model/Configuration/EncodingOptions.cs19
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs26
-rw-r--r--MediaBrowser.Model/Configuration/UserConfiguration.cs13
-rw-r--r--MediaBrowser.Model/Dlna/StreamInfo.cs14
-rw-r--r--MediaBrowser.Model/Dto/BaseItemDto.cs13
-rw-r--r--MediaBrowser.Model/Dto/DtoOptions.cs17
-rw-r--r--MediaBrowser.Model/Dto/MetadataEditorInfo.cs27
-rw-r--r--MediaBrowser.Model/Dto/NameValuePair.cs17
-rw-r--r--MediaBrowser.Model/Dto/StreamOptions.cs67
-rw-r--r--MediaBrowser.Model/Dto/VideoStreamOptions.cs58
-rw-r--r--MediaBrowser.Model/MediaBrowser.Model.csproj15
-rw-r--r--MediaBrowser.Model/Net/HttpResponse.cs64
-rw-r--r--MediaBrowser.Model/Net/MimeTypes.cs (renamed from MediaBrowser.Common/Net/MimeTypes.cs)153
-rw-r--r--MediaBrowser.Model/Querying/ItemFields.cs32
-rw-r--r--MediaBrowser.Model/Session/TranscodingInfo.cs2
-rw-r--r--MediaBrowser.Model/Sync/DeviceFileInfo.cs9
-rw-r--r--MediaBrowser.Model/Sync/ItemFIleInfo.cs28
-rw-r--r--MediaBrowser.Model/Sync/ItemFileType.cs19
-rw-r--r--MediaBrowser.Model/Sync/LocalItem.cs33
-rw-r--r--MediaBrowser.Model/Sync/SyncDataRequest.cs16
-rw-r--r--MediaBrowser.Model/Sync/SyncDataResponse.cs14
-rw-r--r--MediaBrowser.Model/Sync/SyncHelper.cs1
-rw-r--r--MediaBrowser.Model/Sync/SyncJobItem.cs6
-rw-r--r--MediaBrowser.Model/Sync/SyncJobItemQuery.cs5
-rw-r--r--MediaBrowser.Model/Sync/SyncJobItemStatus.cs5
-rw-r--r--MediaBrowser.Model/Sync/SyncedItem.cs38
-rw-r--r--MediaBrowser.Model/Users/UserAction.cs15
-rw-r--r--MediaBrowser.Model/Users/UserActionType.cs8
-rw-r--r--MediaBrowser.Model/Users/UserPolicy.cs69
-rw-r--r--MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs2
-rw-r--r--MediaBrowser.Providers/Manager/ImageSaver.cs1
-rw-r--r--MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs5
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs23
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs7
-rw-r--r--MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs2
-rw-r--r--MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs4
-rw-r--r--MediaBrowser.Providers/Music/AlbumMetadataService.cs20
-rw-r--r--MediaBrowser.Providers/Music/ArtistMetadataService.cs21
-rw-r--r--MediaBrowser.Providers/Music/FanArtAlbumProvider.cs4
-rw-r--r--MediaBrowser.Providers/Music/FanArtArtistProvider.cs4
-rw-r--r--MediaBrowser.Providers/People/TvdbPersonImageProvider.cs4
-rw-r--r--MediaBrowser.Providers/TV/FanArtSeasonProvider.cs4
-rw-r--r--MediaBrowser.Providers/TV/FanartSeriesProvider.cs4
-rw-r--r--MediaBrowser.Providers/TV/MissingEpisodeProvider.cs63
-rw-r--r--MediaBrowser.Providers/TV/MovieDbSeasonProvider.cs8
-rw-r--r--MediaBrowser.Providers/TV/SeriesMetadataService.cs25
-rw-r--r--MediaBrowser.Providers/TV/SeriesPostScanTask.cs15
-rw-r--r--MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs15
-rw-r--r--MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs4
-rw-r--r--MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Channels/ChannelManager.cs35
-rw-r--r--MediaBrowser.Server.Implementations/Channels/ChannelPostScanTask.cs37
-rw-r--r--MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs49
-rw-r--r--MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Connect/ConnectManager.cs38
-rw-r--r--MediaBrowser.Server.Implementations/Devices/DeviceManager.cs37
-rw-r--r--MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs5
-rw-r--r--MediaBrowser.Server.Implementations/Dto/DtoService.cs45
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/UsageEntryPoint.cs1
-rw-r--r--MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs31
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs16
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs2
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs4
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs6
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/NetListener/HttpListenerServer.cs2
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs64
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/SocketSharp/SharpWebSocket.cs6
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs75
-rw-r--r--MediaBrowser.Server.Implementations/Library/LibraryManager.cs212
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs63
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs18
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs50
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs18
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs120
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs12
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs79
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs15
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs5
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs479
-rw-r--r--MediaBrowser.Server.Implementations/Library/SearchEngine.cs17
-rw-r--r--MediaBrowser.Server.Implementations/Library/UserDataManager.cs76
-rw-r--r--MediaBrowser.Server.Implementations/Library/UserManager.cs249
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs9
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/da.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/de.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/el.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/es.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/fi.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json32
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/he.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/hr.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/it.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json30
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json26
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/zh_CN.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/ar.json29
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/ca.json29
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/cs.json25
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/da.json25
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/de.json25
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/el.json29
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/en_GB.json29
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/en_US.json29
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/es.json25
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/es_MX.json31
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/fi.json29
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/fr.json41
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/he.json25
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/hr.json25
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/it.json25
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/kk.json35
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/ko.json29
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/ms.json29
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/nb.json33
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/nl.json31
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/pl.json29
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json29
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json39
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/ru.json65
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/server.json29
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/sv.json25
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/tr.json29
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/vi.json29
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/zh_CN.json43
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json25
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj3
-rw-r--r--MediaBrowser.Server.Implementations/News/NewsService.cs8
-rw-r--r--MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs2
-rw-r--r--MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Session/SessionManager.cs88
-rw-r--r--MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs1
-rw-r--r--MediaBrowser.Server.Implementations/Session/WebSocketController.cs13
-rw-r--r--MediaBrowser.Server.Implementations/Sync/AppSyncProvider.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs151
-rw-r--r--MediaBrowser.Server.Implementations/Sync/SyncManager.cs163
-rw-r--r--MediaBrowser.Server.Implementations/Sync/SyncRepository.cs72
-rw-r--r--MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs11
-rw-r--r--MediaBrowser.Server.Implementations/packages.config2
-rw-r--r--MediaBrowser.Server.Mac/Native/BaseMonoApp.cs2
-rw-r--r--MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj4
-rw-r--r--MediaBrowser.Server.Mono/Native/BaseMonoApp.cs2
-rw-r--r--MediaBrowser.Server.Startup.Common/ApplicationHost.cs89
-rw-r--r--MediaBrowser.Server.Startup.Common/INativeApp.cs5
-rw-r--r--MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj2
-rw-r--r--MediaBrowser.Server.Startup.Common/Migrations/MigrateTranscodingPath.cs30
-rw-r--r--MediaBrowser.Server.Startup.Common/Migrations/PlaylistImages.cs55
-rw-r--r--MediaBrowser.Server.Startup.Common/Migrations/RenameXmlOptions.cs4
-rw-r--r--MediaBrowser.ServerApplication/Native/RegisterServer.bat18
-rw-r--r--MediaBrowser.ServerApplication/Native/ServerAuthorization.cs9
-rw-r--r--MediaBrowser.ServerApplication/Native/WindowsApp.cs4
-rw-r--r--MediaBrowser.Tests/MediaBrowser.Tests.csproj1
-rw-r--r--MediaBrowser.Tests/Resolvers/TvUtilTests.cs246
-rw-r--r--MediaBrowser.WebDashboard/Api/DashboardService.cs1
-rw-r--r--MediaBrowser.WebDashboard/Api/PackageCreator.cs4
-rw-r--r--MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj746
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs4
-rw-r--r--MediaBrowser.sln5
-rw-r--r--Nuget/MediaBrowser.Common.Internal.nuspec5
-rw-r--r--Nuget/MediaBrowser.Common.nuspec2
-rw-r--r--Nuget/MediaBrowser.Model.Signed.nuspec2
-rw-r--r--Nuget/MediaBrowser.Server.Core.nuspec4
-rw-r--r--SharedVersion.cs4
290 files changed, 4603 insertions, 3650 deletions
diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs
index d386373d4..a05d7d1b2 100644
--- a/MediaBrowser.Api/ApiEntryPoint.cs
+++ b/MediaBrowser.Api/ApiEntryPoint.cs
@@ -1,7 +1,9 @@
using MediaBrowser.Api.Playback;
-using MediaBrowser.Controller;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Session;
using System;
@@ -33,7 +35,7 @@ namespace MediaBrowser.Api
/// <summary>
/// The application paths
/// </summary>
- private readonly IServerApplicationPaths _appPaths;
+ private readonly IServerConfigurationManager _config;
private readonly ISessionManager _sessionManager;
@@ -43,13 +45,13 @@ namespace MediaBrowser.Api
/// Initializes a new instance of the <see cref="ApiEntryPoint" /> class.
/// </summary>
/// <param name="logger">The logger.</param>
- /// <param name="appPaths">The application paths.</param>
/// <param name="sessionManager">The session manager.</param>
- public ApiEntryPoint(ILogger logger, IServerApplicationPaths appPaths, ISessionManager sessionManager)
+ /// <param name="config">The configuration.</param>
+ public ApiEntryPoint(ILogger logger, ISessionManager sessionManager, IServerConfigurationManager config)
{
Logger = logger;
- _appPaths = appPaths;
_sessionManager = sessionManager;
+ _config = config;
Instance = this;
}
@@ -73,12 +75,17 @@ namespace MediaBrowser.Api
}
}
+ public EncodingOptions GetEncodingOptions()
+ {
+ return _config.GetConfiguration<EncodingOptions>("encoding");
+ }
+
/// <summary>
/// Deletes the encoded media cache.
/// </summary>
private void DeleteEncodedMediaCache()
{
- foreach (var file in Directory.EnumerateFiles(_appPaths.TranscodingTempPath, "*", SearchOption.AllDirectories)
+ foreach (var file in Directory.EnumerateFiles(_config.ApplicationPaths.TranscodingTempPath, "*", SearchOption.AllDirectories)
.ToList())
{
File.Delete(file);
@@ -185,7 +192,9 @@ namespace MediaBrowser.Api
CompletionPercentage = percentComplete,
Width = state.OutputWidth,
Height = state.OutputHeight,
- AudioChannels = state.OutputAudioChannels
+ AudioChannels = state.OutputAudioChannels,
+ IsAudioDirect = string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase),
+ IsVideoDirect = string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)
});
}
}
diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs
index 5fe606e16..3eb0296fc 100644
--- a/MediaBrowser.Api/ConfigurationService.cs
+++ b/MediaBrowser.Api/ConfigurationService.cs
@@ -123,7 +123,7 @@ namespace MediaBrowser.Api
public void Post(AutoSetMetadataOptions request)
{
- _configurationManager.DisableMetadataService("Media Browser Legacy Xml");
+ _configurationManager.DisableMetadataService("Media Browser Xml");
_configurationManager.SaveConfiguration();
}
diff --git a/MediaBrowser.Api/IHasDtoOptions.cs b/MediaBrowser.Api/IHasDtoOptions.cs
index f7fb57f01..2e677e816 100644
--- a/MediaBrowser.Api/IHasDtoOptions.cs
+++ b/MediaBrowser.Api/IHasDtoOptions.cs
@@ -28,17 +28,7 @@ namespace MediaBrowser.Api
options.ImageTypeLimit = request.ImageTypeLimit.Value;
}
- if (string.IsNullOrWhiteSpace(request.EnableImageTypes))
- {
- if (options.EnableImages)
- {
- // Get everything
- options.ImageTypes = Enum.GetNames(typeof(ImageType))
- .Select(i => (ImageType)Enum.Parse(typeof(ImageType), i, true))
- .ToList();
- }
- }
- else
+ if (!string.IsNullOrWhiteSpace(request.EnableImageTypes))
{
options.ImageTypes = (request.EnableImageTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).Select(v => (ImageType)Enum.Parse(typeof(ImageType), v, true)).ToList();
}
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index 0e4ccf0b1..f2586b043 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -18,6 +18,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
namespace MediaBrowser.Api.Images
{
@@ -668,26 +669,26 @@ namespace MediaBrowser.Api.Images
{
if (format == ImageFormat.Bmp)
{
- return Common.Net.MimeTypes.GetMimeType("i.bmp");
+ return MimeTypes.GetMimeType("i.bmp");
}
if (format == ImageFormat.Gif)
{
- return Common.Net.MimeTypes.GetMimeType("i.gif");
+ return MimeTypes.GetMimeType("i.gif");
}
if (format == ImageFormat.Jpg)
{
- return Common.Net.MimeTypes.GetMimeType("i.jpg");
+ return MimeTypes.GetMimeType("i.jpg");
}
if (format == ImageFormat.Png)
{
- return Common.Net.MimeTypes.GetMimeType("i.png");
+ return MimeTypes.GetMimeType("i.png");
}
if (format == ImageFormat.Webp)
{
- return Common.Net.MimeTypes.GetMimeType("i.webp");
+ return MimeTypes.GetMimeType("i.webp");
}
- return Common.Net.MimeTypes.GetMimeType(path);
+ return MimeTypes.GetMimeType(path);
}
/// <summary>
diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs
index 65c51beff..272dff3ec 100644
--- a/MediaBrowser.Api/ItemUpdateService.cs
+++ b/MediaBrowser.Api/ItemUpdateService.cs
@@ -1,9 +1,14 @@
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Net;
+using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Entities;
using ServiceStack;
using System;
using System.Collections.Generic;
@@ -20,14 +25,165 @@ namespace MediaBrowser.Api
public string ItemId { get; set; }
}
+ [Route("/Items/{ItemId}/MetadataEditor", "GET", Summary = "Gets metadata editor info for an item")]
+ public class GetMetadataEditorInfo : IReturn<MetadataEditorInfo>
+ {
+ [ApiMember(Name = "ItemId", Description = "The id of the item", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string ItemId { get; set; }
+ }
+
+ [Route("/Items/{ItemId}/ContentType", "POST", Summary = "Updates an item's content type")]
+ public class UpdateItemContentType : IReturnVoid
+ {
+ [ApiMember(Name = "ItemId", Description = "The id of the item", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
+ public string ItemId { get; set; }
+
+ [ApiMember(Name = "ContentType", Description = "The content type of the item", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
+ public string ContentType { get; set; }
+ }
+
[Authenticated]
public class ItemUpdateService : BaseApiService
{
private readonly ILibraryManager _libraryManager;
+ private readonly IProviderManager _providerManager;
+ private readonly ILocalizationManager _localizationManager;
+ private readonly IServerConfigurationManager _config;
- public ItemUpdateService(ILibraryManager libraryManager)
+ public ItemUpdateService(ILibraryManager libraryManager, IProviderManager providerManager, ILocalizationManager localizationManager, IServerConfigurationManager config)
{
_libraryManager = libraryManager;
+ _providerManager = providerManager;
+ _localizationManager = localizationManager;
+ _config = config;
+ }
+
+ public object Get(GetMetadataEditorInfo request)
+ {
+ var item = _libraryManager.GetItemById(request.ItemId);
+
+ var info = new MetadataEditorInfo
+ {
+ ParentalRatingOptions = _localizationManager.GetParentalRatings().ToList(),
+ ExternalIdInfos = _providerManager.GetExternalIdInfos(item).ToList(),
+ Countries = _localizationManager.GetCountries().ToList(),
+ Cultures = _localizationManager.GetCultures().ToList()
+ };
+
+ var locationType = item.LocationType;
+ if (locationType == LocationType.FileSystem ||
+ locationType == LocationType.Offline)
+ {
+ if (!(item is ICollectionFolder) && !(item is UserView) && !(item is AggregateFolder) && !(item is LiveTvChannel) && !(item is IItemByName))
+ {
+ var collectionType = _libraryManager.GetInheritedContentType(item);
+ if (string.IsNullOrWhiteSpace(collectionType))
+ {
+ info.ContentTypeOptions = GetContentTypeOptions(true);
+ info.ContentType = _libraryManager.GetContentType(item);
+ }
+ }
+ }
+
+ return ToOptimizedResult(info);
+ }
+
+ public void Post(UpdateItemContentType request)
+ {
+ var item = _libraryManager.GetItemById(request.ItemId);
+ var path = item.ContainingFolderPath;
+
+ var types = _config.Configuration.ContentTypes
+ .Where(i => !string.Equals(i.Name, path, StringComparison.OrdinalIgnoreCase))
+ .ToList();
+
+ if (!string.IsNullOrWhiteSpace(request.ContentType))
+ {
+ types.Add(new NameValuePair
+ {
+ Name = path,
+ Value = request.ContentType
+ });
+ }
+
+ _config.Configuration.ContentTypes = types.ToArray();
+ _config.SaveConfiguration();
+ }
+
+ private List<NameValuePair> GetContentTypeOptions(bool isForItem)
+ {
+ var list = new List<NameValuePair>();
+
+ if (isForItem)
+ {
+ list.Add(new NameValuePair
+ {
+ Name = "FolderTypeInherit",
+ Value = ""
+ });
+ }
+
+ list.Add(new NameValuePair
+ {
+ Name = "FolderTypeMovies",
+ Value = "movies"
+ });
+ list.Add(new NameValuePair
+ {
+ Name = "FolderTypeMusic",
+ Value = "music"
+ });
+ list.Add(new NameValuePair
+ {
+ Name = "FolderTypeTvShows",
+ Value = "tvshows"
+ });
+
+ if (!isForItem)
+ {
+ list.Add(new NameValuePair
+ {
+ Name = "FolderTypeBooks",
+ Value = "books"
+ });
+ list.Add(new NameValuePair
+ {
+ Name = "FolderTypeGames",
+ Value = "games"
+ });
+ }
+
+ list.Add(new NameValuePair
+ {
+ Name = "FolderTypeHomeVideos",
+ Value = "homevideos"
+ });
+ list.Add(new NameValuePair
+ {
+ Name = "FolderTypeMusicVideos",
+ Value = "musicvideos"
+ });
+ list.Add(new NameValuePair
+ {
+ Name = "FolderTypePhotos",
+ Value = "photos"
+ });
+
+ if (!isForItem)
+ {
+ list.Add(new NameValuePair
+ {
+ Name = "FolderTypeMixed",
+ Value = ""
+ });
+ }
+
+ foreach (var val in list)
+ {
+ val.Name = _localizationManager.GetLocalizedString(val.Name);
+ }
+
+ return list;
}
public void Post(UpdateItem request)
diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs
index 5cb007f8f..5e1619672 100644
--- a/MediaBrowser.Api/Library/LibraryService.cs
+++ b/MediaBrowser.Api/Library/LibraryService.cs
@@ -272,16 +272,13 @@ namespace MediaBrowser.Api.Library
items = items.Where(i => i.IsHidden == val).ToList();
}
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields))
- .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
- .ToList();
+ var dtoOptions = new DtoOptions();
var result = new ItemsResult
{
TotalRecordCount = items.Count,
- Items = items.Select(i => _dtoService.GetBaseItemDto(i, fields)).ToArray()
+ Items = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions)).ToArray()
};
return ToOptimizedResult(result);
@@ -347,10 +344,7 @@ namespace MediaBrowser.Api.Library
var user = request.UserId.HasValue ? _userManager.GetUserById(request.UserId.Value) : null;
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields))
- .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
- .ToList();
+ var dtoOptions = new DtoOptions();
BaseItem parent = item.Parent;
@@ -361,7 +355,7 @@ namespace MediaBrowser.Api.Library
parent = TranslateParentItem(parent, user);
}
- baseItemDtos.Add(_dtoService.GetBaseItemDto(parent, fields, user));
+ baseItemDtos.Add(_dtoService.GetBaseItemDto(parent, dtoOptions, user));
parent = parent.Parent;
}
@@ -473,20 +467,20 @@ namespace MediaBrowser.Api.Library
var auth = _authContext.GetAuthorizationInfo(Request);
var user = _userManager.GetUserById(auth.UserId);
- if (item is Playlist)
+ if (item is Playlist || item is BoxSet)
{
// For now this is allowed if user can see the playlist
}
else if (item is ILiveTvRecording)
{
- if (!user.Configuration.EnableLiveTvManagement)
+ if (!user.Policy.EnableLiveTvManagement)
{
throw new UnauthorizedAccessException();
}
}
else
{
- if (!user.Configuration.EnableContentDeletion)
+ if (!user.Policy.EnableContentDeletion)
{
throw new UnauthorizedAccessException();
}
@@ -583,11 +577,6 @@ namespace MediaBrowser.Api.Library
item = item.Parent;
}
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields))
- .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
- .ToList();
-
var themeSongIds = GetThemeSongIds(item);
if (themeSongIds.Count == 0 && request.InheritFromParent)
@@ -607,10 +596,12 @@ namespace MediaBrowser.Api.Library
}
}
}
-
+
+ var dtoOptions = new DtoOptions();
+
var dtos = themeSongIds.Select(_libraryManager.GetItemById)
.OrderBy(i => i.SortName)
- .Select(i => _dtoService.GetBaseItemDto(i, fields, user, item));
+ .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
var items = dtos.ToArray();
@@ -651,11 +642,6 @@ namespace MediaBrowser.Api.Library
item = item.Parent;
}
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields))
- .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
- .ToList();
-
var themeVideoIds = GetThemeVideoIds(item);
if (themeVideoIds.Count == 0 && request.InheritFromParent)
@@ -681,9 +667,11 @@ namespace MediaBrowser.Api.Library
}
}
+ var dtoOptions = new DtoOptions();
+
var dtos = themeVideoIds.Select(_libraryManager.GetItemById)
.OrderBy(i => i.SortName)
- .Select(i => _dtoService.GetBaseItemDto(i, fields, user, item));
+ .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
var items = dtos.ToArray();
@@ -754,10 +742,7 @@ namespace MediaBrowser.Api.Library
: (Folder)_libraryManager.RootFolder)
: _libraryManager.GetItemById(id);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields))
- .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
- .ToList();
+ var dtoOptions = new DtoOptions();
var dtos = GetSoundtrackSongIds(item, inheritFromParent)
.Select(_libraryManager.GetItemById)
@@ -765,7 +750,7 @@ namespace MediaBrowser.Api.Library
.SelectMany(i => i.RecursiveChildren)
.OfType<Audio>()
.OrderBy(i => i.SortName)
- .Select(i => _dtoService.GetBaseItemDto(i, fields, user, item));
+ .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
var items = dtos.ToArray();
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index 3afe72866..f3dcf57e0 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -319,7 +319,7 @@ namespace MediaBrowser.Api.LiveTv
throw new UnauthorizedAccessException("Anonymous live tv management is not allowed.");
}
- if (!user.Configuration.EnableLiveTvManagement)
+ if (!user.Policy.EnableLiveTvManagement)
{
throw new UnauthorizedAccessException("The current user does not have permission to manage live tv.");
}
diff --git a/MediaBrowser.Api/Movies/CollectionService.cs b/MediaBrowser.Api/Movies/CollectionService.cs
index 346c085f8..97c6cd87d 100644
--- a/MediaBrowser.Api/Movies/CollectionService.cs
+++ b/MediaBrowser.Api/Movies/CollectionService.cs
@@ -2,6 +2,7 @@
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Collections;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying;
using ServiceStack;
using System;
@@ -70,7 +71,9 @@ namespace MediaBrowser.Api.Movies
}).ConfigureAwait(false);
- var dto = _dtoService.GetBaseItemDto(item, new List<ItemFields>());
+ var dtoOptions = new DtoOptions();
+
+ var dto = _dtoService.GetBaseItemDto(item, dtoOptions);
return ToOptimizedResult(new CollectionCreationResult
{
diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs
index fc03ab466..ba3c15a90 100644
--- a/MediaBrowser.Api/Movies/MoviesService.cs
+++ b/MediaBrowser.Api/Movies/MoviesService.cs
@@ -157,7 +157,11 @@ namespace MediaBrowser.Api.Movies
.DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString(), StringComparer.OrdinalIgnoreCase)
.ToList();
- var result = GetRecommendationCategories(user, listEligibleForCategories, listEligibleForSuggestion, request.CategoryLimit, request.ItemLimit, request.GetItemFields().ToList());
+ var dtoOptions = new DtoOptions();
+
+ dtoOptions.Fields = request.GetItemFields().ToList();
+
+ var result = GetRecommendationCategories(user, listEligibleForCategories, listEligibleForSuggestion, request.CategoryLimit, request.ItemLimit, dtoOptions);
return ToOptimizedResult(result);
}
@@ -232,7 +236,7 @@ namespace MediaBrowser.Api.Movies
return result;
}
- private IEnumerable<RecommendationDto> GetRecommendationCategories(User user, List<BaseItem> allMoviesForCategories, List<BaseItem> allMovies, int categoryLimit, int itemLimit, List<ItemFields> fields)
+ private IEnumerable<RecommendationDto> GetRecommendationCategories(User user, List<BaseItem> allMoviesForCategories, List<BaseItem> allMovies, int categoryLimit, int itemLimit, DtoOptions dtoOptions)
{
var categories = new List<RecommendationDto>();
@@ -282,11 +286,11 @@ namespace MediaBrowser.Api.Movies
.OrderBy(i => Guid.NewGuid())
.ToList();
- var similarToRecentlyPlayed = GetSimilarTo(user, allMovies, recentlyPlayedMovies.Take(7).OrderBy(i => Guid.NewGuid()), itemLimit, fields, RecommendationType.SimilarToRecentlyPlayed).GetEnumerator();
- var similarToLiked = GetSimilarTo(user, allMovies, likedMovies, itemLimit, fields, RecommendationType.SimilarToLikedItem).GetEnumerator();
+ var similarToRecentlyPlayed = GetSimilarTo(user, allMovies, recentlyPlayedMovies.Take(7).OrderBy(i => Guid.NewGuid()), itemLimit, dtoOptions, RecommendationType.SimilarToRecentlyPlayed).GetEnumerator();
+ var similarToLiked = GetSimilarTo(user, allMovies, likedMovies, itemLimit, dtoOptions, RecommendationType.SimilarToLikedItem).GetEnumerator();
- var hasDirectorFromRecentlyPlayed = GetWithDirector(user, allMovies, recentDirectors, itemLimit, fields, RecommendationType.HasDirectorFromRecentlyPlayed).GetEnumerator();
- var hasActorFromRecentlyPlayed = GetWithActor(user, allMovies, recentActors, itemLimit, fields, RecommendationType.HasActorFromRecentlyPlayed).GetEnumerator();
+ var hasDirectorFromRecentlyPlayed = GetWithDirector(user, allMovies, recentDirectors, itemLimit, dtoOptions, RecommendationType.HasDirectorFromRecentlyPlayed).GetEnumerator();
+ var hasActorFromRecentlyPlayed = GetWithActor(user, allMovies, recentActors, itemLimit, dtoOptions, RecommendationType.HasActorFromRecentlyPlayed).GetEnumerator();
var categoryTypes = new List<IEnumerator<RecommendationDto>>
{
@@ -329,7 +333,7 @@ namespace MediaBrowser.Api.Movies
return categories.OrderBy(i => i.RecommendationType).ThenBy(i => Guid.NewGuid());
}
- private IEnumerable<RecommendationDto> GetWithDirector(User user, List<BaseItem> allMovies, IEnumerable<string> directors, int itemLimit, List<ItemFields> fields, RecommendationType type)
+ private IEnumerable<RecommendationDto> GetWithDirector(User user, List<BaseItem> allMovies, IEnumerable<string> directors, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
{
var userId = user.Id;
@@ -347,13 +351,13 @@ namespace MediaBrowser.Api.Movies
BaselineItemName = director,
CategoryId = director.GetMD5().ToString("N"),
RecommendationType = type,
- Items = items.Select(i => _dtoService.GetBaseItemDto(i, fields, user)).ToArray()
+ Items = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray()
};
}
}
}
- private IEnumerable<RecommendationDto> GetWithActor(User user, List<BaseItem> allMovies, IEnumerable<string> names, int itemLimit, List<ItemFields> fields, RecommendationType type)
+ private IEnumerable<RecommendationDto> GetWithActor(User user, List<BaseItem> allMovies, IEnumerable<string> names, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
{
var userId = user.Id;
@@ -371,13 +375,13 @@ namespace MediaBrowser.Api.Movies
BaselineItemName = name,
CategoryId = name.GetMD5().ToString("N"),
RecommendationType = type,
- Items = items.Select(i => _dtoService.GetBaseItemDto(i, fields, user)).ToArray()
+ Items = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray()
};
}
}
}
- private IEnumerable<RecommendationDto> GetSimilarTo(User user, List<BaseItem> allMovies, IEnumerable<BaseItem> baselineItems, int itemLimit, List<ItemFields> fields, RecommendationType type)
+ private IEnumerable<RecommendationDto> GetSimilarTo(User user, List<BaseItem> allMovies, IEnumerable<BaseItem> baselineItems, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
{
var userId = user.Id;
@@ -395,7 +399,7 @@ namespace MediaBrowser.Api.Movies
BaselineItemName = item.Name,
CategoryId = item.Id.ToString("N"),
RecommendationType = type,
- Items = similar.Select(i => _dtoService.GetBaseItemDto(i, fields, user)).ToArray()
+ Items = similar.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray()
};
}
}
diff --git a/MediaBrowser.Api/NotificationsService.cs b/MediaBrowser.Api/NotificationsService.cs
index 69f1f3489..5103d1b5c 100644
--- a/MediaBrowser.Api/NotificationsService.cs
+++ b/MediaBrowser.Api/NotificationsService.cs
@@ -135,7 +135,7 @@ namespace MediaBrowser.Api
Level = request.Level,
Name = request.Name,
Url = request.Url,
- UserIds = _userManager.Users.Where(i => i.Configuration.IsAdministrator).Select(i => i.Id.ToString("N")).ToList()
+ UserIds = _userManager.Users.Where(i => i.Policy.IsAdministrator).Select(i => i.Id.ToString("N")).ToList()
};
await _notificationManager.SendNotification(notification, CancellationToken.None).ConfigureAwait(false);
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index 12ccfb6b1..03106b6e7 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
@@ -202,6 +203,10 @@ namespace MediaBrowser.Api.Playback
{
args += " -map -0:s";
}
+ else if (state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream)
+ {
+ args += " -map 1:0 -sn";
+ }
return args;
}
@@ -245,7 +250,7 @@ namespace MediaBrowser.Api.Playback
protected EncodingQuality GetQualitySetting()
{
- var quality = ServerConfigurationManager.Configuration.MediaEncodingQuality;
+ var quality = ApiEntryPoint.Instance.GetEncodingOptions().EncodingQuality;
if (quality == EncodingQuality.Auto)
{
@@ -273,7 +278,7 @@ namespace MediaBrowser.Api.Playback
// Recommended per docs
return Math.Max(Environment.ProcessorCount - 1, 2);
}
-
+
// Use more when this is true. -re will keep cpu usage under control
if (state.ReadInputAtNativeFramerate)
{
@@ -302,6 +307,21 @@ namespace MediaBrowser.Api.Playback
}
}
+ protected string H264Encoder
+ {
+ get
+ {
+ var lib = ApiEntryPoint.Instance.GetEncodingOptions().H264Encoder;
+
+ if (!string.IsNullOrWhiteSpace(lib))
+ {
+ return lib;
+ }
+
+ return "libx264";
+ }
+ }
+
/// <summary>
/// Gets the video bitrate to specify on the command line
/// </summary>
@@ -318,7 +338,7 @@ namespace MediaBrowser.Api.Playback
var qualitySetting = GetQualitySetting();
- if (string.Equals(videoCodec, "libx264", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(videoCodec, H264Encoder, StringComparison.OrdinalIgnoreCase))
{
switch (qualitySetting)
{
@@ -442,7 +462,7 @@ namespace MediaBrowser.Api.Playback
{
if (state.AudioStream != null && state.AudioStream.Channels.HasValue && state.AudioStream.Channels.Value > 5)
{
- volParam = ",volume=" + ServerConfigurationManager.Configuration.DownMixAudioBoost.ToString(UsCulture);
+ volParam = ",volume=" + ApiEntryPoint.Instance.GetEncodingOptions().DownMixAudioBoost.ToString(UsCulture);
}
}
@@ -651,9 +671,18 @@ namespace MediaBrowser.Api.Playback
videoSizeParam = string.Format(",scale={0}:{1}", state.VideoStream.Width.Value.ToString(UsCulture), state.VideoStream.Height.Value.ToString(UsCulture));
}
- return string.Format(" -filter_complex \"[0:{0}]format=yuva444p{3},lut=u=128:v=128:y=gammaval(.3)[sub] ; [0:{1}] [sub] overlay{2}\"",
- state.SubtitleStream.Index,
- state.VideoStream.Index,
+ var mapPrefix = state.SubtitleStream.IsExternal ?
+ 1 :
+ 0;
+
+ var subtitleStreamIndex = state.SubtitleStream.IsExternal
+ ? 0
+ : state.SubtitleStream.Index;
+
+ return string.Format(" -filter_complex \"[{0}:{1}]format=yuva444p{4},lut=u=128:v=128:y=gammaval(.3)[sub] ; [0:{2}] [sub] overlay{3}\"",
+ mapPrefix.ToString(UsCulture),
+ subtitleStreamIndex.ToString(UsCulture),
+ state.VideoStream.Index.ToString(UsCulture),
outputSizeParam,
videoSizeParam);
}
@@ -700,7 +729,8 @@ namespace MediaBrowser.Api.Playback
return Math.Min(request.MaxAudioChannels.Value, audioStream.Channels.Value);
}
- return request.MaxAudioChannels.Value;
+ // If we don't have any media info then limit it to 5 to prevent encoding errors due to asking for too many channels
+ return Math.Min(request.MaxAudioChannels.Value, 5);
}
return request.AudioChannels;
@@ -761,7 +791,7 @@ namespace MediaBrowser.Api.Playback
{
if (string.Equals(codec, "h264", StringComparison.OrdinalIgnoreCase))
{
- return "libx264";
+ return H264Encoder;
}
if (string.Equals(codec, "vpx", StringComparison.OrdinalIgnoreCase))
{
@@ -798,6 +828,21 @@ namespace MediaBrowser.Api.Playback
/// <returns>System.String.</returns>
protected string GetInputArgument(string transcodingJobId, StreamState state)
{
+ var arg = "-i " + GetInputPathArgument(transcodingJobId, state);
+
+ if (state.SubtitleStream != null)
+ {
+ if (state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream)
+ {
+ arg += " -i " + state.SubtitleStream.Path;
+ }
+ }
+
+ return arg;
+ }
+
+ private string GetInputPathArgument(string transcodingJobId, StreamState state)
+ {
if (state.InputProtocol == MediaProtocol.File &&
state.RunTimeTicks.HasValue &&
state.VideoType == VideoType.VideoFile &&
@@ -868,7 +913,7 @@ namespace MediaBrowser.Api.Playback
state.InputProtocol = streamInfo.Protocol;
await Task.Delay(1500, cancellationTokenSource.Token).ConfigureAwait(false);
-
+
AttachMediaStreamInfo(state, streamInfo, state.VideoRequest, state.RequestedUrl);
checkCodecs = true;
}
@@ -898,8 +943,8 @@ namespace MediaBrowser.Api.Playback
/// <param name="cancellationTokenSource">The cancellation token source.</param>
/// <param name="workingDirectory">The working directory.</param>
/// <returns>Task.</returns>
- protected async Task<TranscodingJob> StartFfMpeg(StreamState state,
- string outputPath,
+ protected async Task<TranscodingJob> StartFfMpeg(StreamState state,
+ string outputPath,
CancellationTokenSource cancellationTokenSource,
string workingDirectory = null)
{
@@ -910,7 +955,7 @@ namespace MediaBrowser.Api.Playback
var transcodingId = Guid.NewGuid().ToString("N");
var commandLineArgs = GetCommandLineArguments(outputPath, transcodingId, state, true);
- if (ServerConfigurationManager.Configuration.EnableDebugEncodingLogging)
+ if (ApiEntryPoint.Instance.GetEncodingOptions().EnableDebugLogging)
{
commandLineArgs = "-loglevel debug " + commandLineArgs;
}
@@ -1088,7 +1133,7 @@ namespace MediaBrowser.Api.Playback
if (scale.HasValue)
{
long val;
-
+
if (long.TryParse(size, NumberStyles.Any, UsCulture, out val))
{
bytesTranscoded = val * scale.Value;
@@ -1562,9 +1607,6 @@ namespace MediaBrowser.Api.Playback
mediaStreams = new List<MediaStream>();
state.DeInterlace = true;
- state.OutputAudioSync = "1000";
- state.InputVideoSync = "-1";
- state.InputAudioSync = "1";
// Just to prevent this from being null and causing other methods to fail
state.MediaPath = string.Empty;
@@ -1630,7 +1672,7 @@ namespace MediaBrowser.Api.Playback
if (string.IsNullOrEmpty(container))
{
- container = request.Static ?
+ container = request.Static ?
state.InputContainer :
(Path.GetExtension(GetOutputFilePath(state)) ?? string.Empty).TrimStart('.');
}
@@ -1696,9 +1738,16 @@ namespace MediaBrowser.Api.Playback
state.InputFileSize = mediaSource.Size;
state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate;
+ if (state.ReadInputAtNativeFramerate)
+ {
+ state.OutputAudioSync = "1000";
+ state.InputVideoSync = "-1";
+ state.InputAudioSync = "1";
+ }
+
AttachMediaStreamInfo(state, mediaSource.MediaStreams, videoRequest, requestedUrl);
}
-
+
private void AttachMediaStreamInfo(StreamState state,
List<MediaStream> mediaStreams,
VideoStreamRequest videoRequest,
diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
index c963636fd..8a33a88f2 100644
--- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
@@ -6,7 +7,6 @@ using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.IO;
using System;
using System.Collections.Generic;
@@ -14,6 +14,7 @@ using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Model.Net;
namespace MediaBrowser.Api.Playback.Hls
{
@@ -119,11 +120,7 @@ namespace MediaBrowser.Api.Playback.Hls
if (isLive)
{
- //var file = request.PlaylistId + Path.GetExtension(Request.PathInfo);
-
- //file = Path.Combine(ServerConfigurationManager.ApplicationPaths.TranscodingTempPath, file);
-
- return ResultFactory.GetStaticFileResult(Request, playlist, FileShare.ReadWrite);
+ return ResultFactory.GetResult(GetLivePlaylistText(playlist, state.SegmentLength), MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
}
var audioBitrate = state.OutputAudioBitrate ?? 0;
@@ -144,6 +141,22 @@ namespace MediaBrowser.Api.Playback.Hls
return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
}
+ private string GetLivePlaylistText(string path, int segmentLength)
+ {
+ using (var stream = FileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
+ {
+ using (var reader = new StreamReader(stream))
+ {
+ var text = reader.ReadToEnd();
+
+ var newDuration = "#EXT-X-TARGETDURATION:" + segmentLength.ToString(UsCulture) + Environment.NewLine + "#EXT-X-ALLOW-CACHE:NO";
+
+ // ffmpeg pads the reported length by a full second
+ return text.Replace("#EXT-X-TARGETDURATION:" + (segmentLength + 1).ToString(UsCulture), newDuration, StringComparison.OrdinalIgnoreCase);
+ }
+ }
+ }
+
private string GetMasterPlaylistFileText(string firstPlaylist, int bitrate, bool includeBaselineStream, int baselineStreamBitrate)
{
var builder = new StringBuilder();
@@ -227,7 +240,7 @@ namespace MediaBrowser.Api.Playback.Hls
"hls/" + Path.GetFileNameWithoutExtension(outputPath));
}
- var args = string.Format("{0} {1} -i {2} -map_metadata -1 -threads {3} {4} {5} -sc_threshold 0 {6} -hls_time {7} -start_number {8} -hls_list_size {9}{10} -y \"{11}\"",
+ var args = string.Format("{0} {1} {2} -map_metadata -1 -threads {3} {4} {5} -sc_threshold 0 {6} -hls_time {7} -start_number {8} -hls_list_size {9}{10} -y \"{11}\"",
itsOffset,
inputModifier,
GetInputArgument(transcodingJobId, state),
diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
index fe3bd12fb..86866bdf5 100644
--- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
@@ -20,6 +20,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
namespace MediaBrowser.Api.Playback.Hls
{
@@ -387,7 +388,7 @@ namespace MediaBrowser.Api.Playback.Hls
playlistText = GetMasterPlaylistFileText(state, videoBitrate + audioBitrate);
}
- return ResultFactory.GetResult(playlistText, Common.Net.MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
+ return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
}
private string GetMasterPlaylistFileText(StreamState state, int totalBitrate)
@@ -603,7 +604,7 @@ namespace MediaBrowser.Api.Playback.Hls
var playlistText = builder.ToString();
- return ResultFactory.GetResult(playlistText, Common.Net.MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
+ return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
}
protected override string GetAudioArguments(StreamState state)
@@ -640,10 +641,19 @@ namespace MediaBrowser.Api.Playback.Hls
{
var codec = state.OutputVideoCodec;
+ var args = "-codec:v:0 " + codec;
+
+ if (state.EnableMpegtsM2TsMode)
+ {
+ args += " -mpegts_m2ts_mode 1";
+ }
+
// See if we can save come cpu cycles by avoiding encoding
- if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
+ if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
{
- return state.VideoStream != null && IsH264(state.VideoStream) ? "-codec:v:0 copy -bsf:v h264_mp4toannexb" : "-codec:v:0 copy";
+ return state.VideoStream != null && IsH264(state.VideoStream) ?
+ args + " -bsf:v h264_mp4toannexb" :
+ args;
}
var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})",
@@ -651,7 +661,7 @@ namespace MediaBrowser.Api.Playback.Hls
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
- var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, "libx264", true) + keyFrameArg;
+ args += " " + GetVideoQualityParam(state, H264Encoder, true) + keyFrameArg;
// Add resolution params, if specified
if (!hasGraphicalSubs)
@@ -677,7 +687,7 @@ namespace MediaBrowser.Api.Playback.Hls
// If isEncoding is true we're actually starting ffmpeg
var startNumberParam = isEncoding ? GetStartNumber(state).ToString(UsCulture) : "0";
- var args = string.Format("{0} -i {1} -map_metadata -1 -threads {2} {3} {4} -copyts -flags -global_header {5} -hls_time {6} -start_number {7} -hls_list_size {8} -y \"{9}\"",
+ var args = string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -copyts -flags -global_header {5} -hls_time {6} -start_number {7} -hls_list_size {8} -y \"{9}\"",
inputModifier,
GetInputArgument(transcodingJobId, state),
threads,
diff --git a/MediaBrowser.Api/Playback/Hls/MpegDashService.cs b/MediaBrowser.Api/Playback/Hls/MpegDashService.cs
index 260a4c467..87e2eedcf 100644
--- a/MediaBrowser.Api/Playback/Hls/MpegDashService.cs
+++ b/MediaBrowser.Api/Playback/Hls/MpegDashService.cs
@@ -18,6 +18,7 @@ using System.Security;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
namespace MediaBrowser.Api.Playback.Hls
{
@@ -97,7 +98,7 @@ namespace MediaBrowser.Api.Playback.Hls
playlistText = GetManifestText(state);
}
- return ResultFactory.GetResult(playlistText, Common.Net.MimeTypes.GetMimeType("playlist.mpd"), new Dictionary<string, string>());
+ return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.mpd"), new Dictionary<string, string>());
}
private string GetManifestText(StreamState state)
@@ -583,10 +584,19 @@ namespace MediaBrowser.Api.Playback.Hls
{
var codec = state.OutputVideoCodec;
+ var args = "-codec:v:0 " + codec;
+
+ if (state.EnableMpegtsM2TsMode)
+ {
+ args += " -mpegts_m2ts_mode 1";
+ }
+
// See if we can save come cpu cycles by avoiding encoding
if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
{
- return IsH264(state.VideoStream) ? "-codec:v:0 copy -bsf:v h264_mp4toannexb" : "-codec:v:0 copy";
+ return state.VideoStream != null && IsH264(state.VideoStream) ?
+ args + " -bsf:v h264_mp4toannexb" :
+ args;
}
var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})",
@@ -594,7 +604,7 @@ namespace MediaBrowser.Api.Playback.Hls
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
- var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, "libx264", true) + keyFrameArg;
+ args+= " " + GetVideoQualityParam(state, H264Encoder, true) + keyFrameArg;
args += " -r 24 -g 24";
@@ -627,7 +637,7 @@ namespace MediaBrowser.Api.Playback.Hls
var segmentFilename = Path.GetFileNameWithoutExtension(outputPath) + "%03d" + GetSegmentFileExtension(state);
- var args = string.Format("{0} -i {1} -map_metadata -1 -threads {2} {3} {4} -copyts {5} -f ssegment -segment_time {6} -segment_list_size {8} -segment_list \"{9}\" {10}",
+ var args = string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -copyts {5} -f ssegment -segment_time {6} -segment_list_size {8} -segment_list \"{9}\" {10}",
inputModifier,
GetInputArgument(transcodingJobId, state),
threads,
diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
index 06fa4065c..de845c88d 100644
--- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
@@ -9,8 +9,6 @@ using MediaBrowser.Model.IO;
using ServiceStack;
using System;
using System.IO;
-using System.Linq;
-using System.Threading.Tasks;
namespace MediaBrowser.Api.Playback.Hls
{
@@ -136,18 +134,27 @@ namespace MediaBrowser.Api.Playback.Hls
{
var codec = state.OutputVideoCodec;
+ var args = "-codec:v:0 " + codec;
+
+ if (state.EnableMpegtsM2TsMode)
+ {
+ args += " -mpegts_m2ts_mode 1";
+ }
+
// See if we can save come cpu cycles by avoiding encoding
if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
{
- return state.VideoStream != null && IsH264(state.VideoStream) ? "-codec:v:0 copy -bsf:v h264_mp4toannexb" : "-codec:v:0 copy";
+ return state.VideoStream != null && IsH264(state.VideoStream) ?
+ args + " -bsf:v h264_mp4toannexb" :
+ args;
}
-
+
var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})",
state.SegmentLength.ToString(UsCulture));
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
- var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, "libx264", true) + keyFrameArg;
+ args += " " + GetVideoQualityParam(state, H264Encoder, true) + keyFrameArg;
// Add resolution params, if specified
if (!hasGraphicalSubs)
diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
index ae592c428..725526ecd 100644
--- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
@@ -82,7 +82,7 @@ namespace MediaBrowser.Api.Playback.Progressive
var inputModifier = GetInputModifier(state);
- return string.Format("{0} -i {1} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1 -y \"{5}\"",
+ return string.Format("{0} {1} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1 -y \"{5}\"",
inputModifier,
GetInputArgument(transcodingJobId, state),
threads,
diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
index a64866d68..5ef72a495 100644
--- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
@@ -103,7 +103,7 @@ namespace MediaBrowser.Api.Playback.Progressive
var inputModifier = GetInputModifier(state);
- return string.Format("{0} -i {1}{2} {3} {4} -map_metadata -1 -threads {5} {6}{7} -y \"{8}\"",
+ return string.Format("{0} {1}{2} {3} {4} -map_metadata -1 -threads {5} {6}{7} -y \"{8}\"",
inputModifier,
GetInputArgument(transcodingJobId, state),
keyFrame,
@@ -124,7 +124,7 @@ namespace MediaBrowser.Api.Playback.Progressive
/// <returns>System.String.</returns>
private string GetVideoArguments(StreamState state, string codec)
{
- var args = "-vcodec " + codec;
+ var args = "-codec:v:0 " + codec;
if (state.EnableMpegtsM2TsMode)
{
@@ -134,7 +134,9 @@ namespace MediaBrowser.Api.Playback.Progressive
// See if we can save come cpu cycles by avoiding encoding
if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
{
- return state.VideoStream != null && IsH264(state.VideoStream) ? args + " -bsf:v h264_mp4toannexb" : args;
+ return state.VideoStream != null && IsH264(state.VideoStream) && string.Equals(state.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) ?
+ args + " -bsf:v h264_mp4toannexb" :
+ args;
}
var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})",
@@ -182,13 +184,13 @@ namespace MediaBrowser.Api.Playback.Progressive
// Get the output codec name
var codec = state.OutputAudioCodec;
+ var args = "-codec:a:0 " + codec;
+
if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
{
- return "-acodec copy";
+ return args;
}
- var args = "-acodec " + codec;
-
// Add the number of audio channels
var channels = state.OutputAudioChannels;
diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs
index d26259a3a..40e765f1a 100644
--- a/MediaBrowser.Api/Playback/StreamState.cs
+++ b/MediaBrowser.Api/Playback/StreamState.cs
@@ -11,6 +11,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Threading;
+using MediaBrowser.Model.Net;
namespace MediaBrowser.Api.Playback
{
diff --git a/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs b/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs
index f34c53b16..cb8f91ab6 100644
--- a/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs
+++ b/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Tasks;
diff --git a/MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs b/MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs
index e6b525e53..25130776e 100644
--- a/MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs
+++ b/MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Session;
diff --git a/MediaBrowser.Api/Session/SessionsService.cs b/MediaBrowser.Api/Session/SessionsService.cs
index d2881893b..59b8e85c2 100644
--- a/MediaBrowser.Api/Session/SessionsService.cs
+++ b/MediaBrowser.Api/Session/SessionsService.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Devices;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Security;
using MediaBrowser.Controller.Session;
@@ -299,6 +300,7 @@ namespace MediaBrowser.Api.Session
private readonly IUserManager _userManager;
private readonly IAuthorizationContext _authContext;
private readonly IAuthenticationRepository _authRepo;
+ private readonly IDeviceManager _deviceManager;
/// <summary>
/// Initializes a new instance of the <see cref="SessionsService" /> class.
@@ -307,12 +309,13 @@ namespace MediaBrowser.Api.Session
/// <param name="userManager">The user manager.</param>
/// <param name="authContext">The authentication context.</param>
/// <param name="authRepo">The authentication repo.</param>
- public SessionsService(ISessionManager sessionManager, IUserManager userManager, IAuthorizationContext authContext, IAuthenticationRepository authRepo)
+ public SessionsService(ISessionManager sessionManager, IUserManager userManager, IAuthorizationContext authContext, IAuthenticationRepository authRepo, IDeviceManager deviceManager)
{
_sessionManager = sessionManager;
_userManager = userManager;
_authContext = authContext;
_authRepo = authRepo;
+ _deviceManager = deviceManager;
}
public void Delete(RevokeKey request)
@@ -373,15 +376,30 @@ namespace MediaBrowser.Api.Session
var user = _userManager.GetUserById(request.ControllableByUserId.Value);
- if (!user.Configuration.EnableRemoteControlOfOtherUsers)
+ if (!user.Policy.EnableRemoteControlOfOtherUsers)
{
result = result.Where(i => i.ContainsUser(request.ControllableByUserId.Value));
}
- if (!user.Configuration.EnableSharedDeviceControl)
+ if (!user.Policy.EnableSharedDeviceControl)
{
result = result.Where(i => !i.UserId.HasValue);
}
+
+ result = result.Where(i =>
+ {
+ var deviceId = i.DeviceId;
+
+ if (!string.IsNullOrWhiteSpace(deviceId))
+ {
+ if (!_deviceManager.CanAccessDevice(user.Id.ToString("N"), deviceId))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ });
}
return ToOptimizedResult(result.Select(_sessionManager.GetSessionInfoDto).ToList());
diff --git a/MediaBrowser.Api/Subtitles/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs
index a2a93d50e..32e6ba076 100644
--- a/MediaBrowser.Api/Subtitles/SubtitleService.cs
+++ b/MediaBrowser.Api/Subtitles/SubtitleService.cs
@@ -15,6 +15,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
namespace MediaBrowser.Api.Subtitles
{
@@ -175,7 +176,7 @@ namespace MediaBrowser.Api.Subtitles
builder.AppendLine("#EXT-X-ENDLIST");
- return ResultFactory.GetResult(builder.ToString(), Common.Net.MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
+ return ResultFactory.GetResult(builder.ToString(), MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
}
public object Get(GetSubtitle request)
@@ -199,7 +200,7 @@ namespace MediaBrowser.Api.Subtitles
var stream = GetSubtitles(request).Result;
- return ResultFactory.GetResult(stream, Common.Net.MimeTypes.GetMimeType("file." + request.Format));
+ return ResultFactory.GetResult(stream, MimeTypes.GetMimeType("file." + request.Format));
}
private async Task<Stream> GetSubtitles(GetSubtitle request)
@@ -240,7 +241,7 @@ namespace MediaBrowser.Api.Subtitles
{
var result = _subtitleManager.GetRemoteSubtitles(request.Id, CancellationToken.None).Result;
- return ResultFactory.GetResult(result.Stream, Common.Net.MimeTypes.GetMimeType("file." + result.Format));
+ return ResultFactory.GetResult(result.Stream, MimeTypes.GetMimeType("file." + result.Format));
}
public void Post(DownloadRemoteSubtitles request)
diff --git a/MediaBrowser.Api/Sync/SyncService.cs b/MediaBrowser.Api/Sync/SyncService.cs
index cefb0e46e..31442c1d9 100644
--- a/MediaBrowser.Api/Sync/SyncService.cs
+++ b/MediaBrowser.Api/Sync/SyncService.cs
@@ -5,6 +5,7 @@ using MediaBrowser.Controller.Sync;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Sync;
+using MediaBrowser.Model.Users;
using ServiceStack;
using System;
using System.Collections.Generic;
@@ -55,8 +56,14 @@ namespace MediaBrowser.Api.Sync
[ApiMember(Name = "UserId", Description = "UserId", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
public string UserId { get; set; }
- [ApiMember(Name = "ItemIds", Description = "ItemIds", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+ [ApiMember(Name = "ItemIds", Description = "ItemIds", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string ItemIds { get; set; }
+
+ [ApiMember(Name = "ParentId", Description = "ParentId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string ParentId { get; set; }
+
+ [ApiMember(Name = "Category", Description = "Category", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public SyncCategory? Category { get; set; }
}
[Route("/Sync/JobItems/{Id}/Transferred", "POST", Summary = "Reports that a sync job item has successfully been transferred.")]
@@ -73,6 +80,23 @@ namespace MediaBrowser.Api.Sync
public string Id { get; set; }
}
+ [Route("/Sync/OfflineActions", "POST", Summary = "Reports an action that occurred while offline.")]
+ public class ReportOfflineActions : List<UserAction>, IReturnVoid
+ {
+ }
+
+ [Route("/Sync/Items/Ready", "GET", Summary = "Gets ready to download sync items.")]
+ public class GetReadySyncItems : IReturn<List<SyncedItem>>
+ {
+ [ApiMember(Name = "TargetId", Description = "TargetId", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string TargetId { get; set; }
+ }
+
+ [Route("/Sync/Data", "POST", Summary = "Syncs data between device and server")]
+ public class SyncData : SyncDataRequest, IReturn<SyncDataResponse>
+ {
+ }
+
[Authenticated]
public class SyncService : BaseApiService
{
@@ -155,21 +179,57 @@ namespace MediaBrowser.Api.Sync
result.Targets = _syncManager.GetSyncTargets(request.UserId)
.ToList();
- var dtos = request.ItemIds.Split(',')
- .Select(_libraryManager.GetItemById)
- .Where(i => i != null)
- .Select(i => _dtoService.GetBaseItemDto(i, new DtoOptions
+ if (request.Category.HasValue)
+ {
+ result.Options = SyncHelper.GetSyncOptions(request.Category.Value);
+ }
+ else
+ {
+ var dtoOptions = new DtoOptions
{
Fields = new List<ItemFields>
{
ItemFields.SyncInfo
}
- }))
- .ToList();
+ };
- result.Options = SyncHelper.GetSyncOptions(dtos);
+ var dtos = request.ItemIds.Split(',')
+ .Select(_libraryManager.GetItemById)
+ .Where(i => i != null)
+ .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions))
+ .ToList();
+
+ result.Options = SyncHelper.GetSyncOptions(dtos);
+ }
return ToOptimizedResult(result);
}
+
+ public void Post(ReportOfflineActions request)
+ {
+ var task = PostAsync(request);
+
+ Task.WaitAll(task);
+ }
+
+ public async Task PostAsync(ReportOfflineActions request)
+ {
+ foreach (var action in request)
+ {
+ await _syncManager.ReportOfflineAction(action).ConfigureAwait(false);
+ }
+ }
+
+ public object Get(GetReadySyncItems request)
+ {
+ return ToOptimizedResult(_syncManager.GetReadySyncItems(request.TargetId));
+ }
+
+ public async Task<object> Post(SyncData request)
+ {
+ var response = await _syncManager.SyncData(request).ConfigureAwait(false);
+
+ return ToOptimizedResult(response);
+ }
}
}
diff --git a/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs b/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs
index 4629b2a8c..a951cd3d6 100644
--- a/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs
+++ b/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs
@@ -1,5 +1,5 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Activity;
+using MediaBrowser.Controller.Activity;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Activity;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Logging;
diff --git a/MediaBrowser.Api/System/SystemInfoWebSocketListener.cs b/MediaBrowser.Api/System/SystemInfoWebSocketListener.cs
index c20cef3b3..49a3e3291 100644
--- a/MediaBrowser.Api/System/SystemInfoWebSocketListener.cs
+++ b/MediaBrowser.Api/System/SystemInfoWebSocketListener.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.System;
using System.Threading.Tasks;
diff --git a/MediaBrowser.Api/UserLibrary/ArtistsService.cs b/MediaBrowser.Api/UserLibrary/ArtistsService.cs
index 2299b2b1a..128423238 100644
--- a/MediaBrowser.Api/UserLibrary/ArtistsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ArtistsService.cs
@@ -83,17 +83,16 @@ namespace MediaBrowser.Api.UserLibrary
{
var item = GetArtist(request.Name, LibraryManager);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
+ var dtoOptions = new DtoOptions();
if (request.UserId.HasValue)
{
var user = UserManager.GetUserById(request.UserId.Value);
-
- return DtoService.GetBaseItemDto(item, fields.ToList(), user);
+
+ return DtoService.GetBaseItemDto(item, dtoOptions, user);
}
- return DtoService.GetBaseItemDto(item, fields.ToList());
+ return DtoService.GetBaseItemDto(item, dtoOptions);
}
/// <summary>
diff --git a/MediaBrowser.Api/UserLibrary/GameGenresService.cs b/MediaBrowser.Api/UserLibrary/GameGenresService.cs
index adc21c362..2f1c73ace 100644
--- a/MediaBrowser.Api/UserLibrary/GameGenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/GameGenresService.cs
@@ -69,17 +69,16 @@ namespace MediaBrowser.Api.UserLibrary
{
var item = GetGameGenre(request.Name, LibraryManager);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
+ var dtoOptions = new DtoOptions();
if (request.UserId.HasValue)
{
var user = UserManager.GetUserById(request.UserId.Value);
- return DtoService.GetBaseItemDto(item, fields.ToList(), user);
+ return DtoService.GetBaseItemDto(item, dtoOptions, user);
}
- return DtoService.GetBaseItemDto(item, fields.ToList());
+ return DtoService.GetBaseItemDto(item, dtoOptions);
}
/// <summary>
diff --git a/MediaBrowser.Api/UserLibrary/GenresService.cs b/MediaBrowser.Api/UserLibrary/GenresService.cs
index 7b6b18c9c..db0b0fe61 100644
--- a/MediaBrowser.Api/UserLibrary/GenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/GenresService.cs
@@ -74,17 +74,16 @@ namespace MediaBrowser.Api.UserLibrary
{
var item = GetGenre(request.Name, LibraryManager);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
+ var dtoOptions = new DtoOptions();
if (request.UserId.HasValue)
{
var user = UserManager.GetUserById(request.UserId.Value);
- return DtoService.GetBaseItemDto(item, fields.ToList(), user);
+ return DtoService.GetBaseItemDto(item, dtoOptions, user);
}
- return DtoService.GetBaseItemDto(item, fields.ToList());
+ return DtoService.GetBaseItemDto(item, dtoOptions);
}
/// <summary>
diff --git a/MediaBrowser.Api/UserLibrary/MusicGenresService.cs b/MediaBrowser.Api/UserLibrary/MusicGenresService.cs
index 1088ada02..f8575aa7c 100644
--- a/MediaBrowser.Api/UserLibrary/MusicGenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/MusicGenresService.cs
@@ -69,17 +69,16 @@ namespace MediaBrowser.Api.UserLibrary
{
var item = GetMusicGenre(request.Name, LibraryManager);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
+ var dtoOptions = new DtoOptions();
if (request.UserId.HasValue)
{
var user = UserManager.GetUserById(request.UserId.Value);
- return DtoService.GetBaseItemDto(item, fields.ToList(), user);
+ return DtoService.GetBaseItemDto(item, dtoOptions, user);
}
- return DtoService.GetBaseItemDto(item, fields.ToList());
+ return DtoService.GetBaseItemDto(item, dtoOptions);
}
/// <summary>
diff --git a/MediaBrowser.Api/UserLibrary/PersonsService.cs b/MediaBrowser.Api/UserLibrary/PersonsService.cs
index dd80801ee..33ce6cd80 100644
--- a/MediaBrowser.Api/UserLibrary/PersonsService.cs
+++ b/MediaBrowser.Api/UserLibrary/PersonsService.cs
@@ -86,17 +86,16 @@ namespace MediaBrowser.Api.UserLibrary
{
var item = GetPerson(request.Name, LibraryManager);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
+ var dtoOptions = new DtoOptions();
if (request.UserId.HasValue)
{
var user = UserManager.GetUserById(request.UserId.Value);
- return DtoService.GetBaseItemDto(item, fields.ToList(), user);
+ return DtoService.GetBaseItemDto(item, dtoOptions, user);
}
- return DtoService.GetBaseItemDto(item, fields.ToList());
+ return DtoService.GetBaseItemDto(item, dtoOptions);
}
/// <summary>
diff --git a/MediaBrowser.Api/UserLibrary/StudiosService.cs b/MediaBrowser.Api/UserLibrary/StudiosService.cs
index 2024d779b..272134b70 100644
--- a/MediaBrowser.Api/UserLibrary/StudiosService.cs
+++ b/MediaBrowser.Api/UserLibrary/StudiosService.cs
@@ -73,17 +73,16 @@ namespace MediaBrowser.Api.UserLibrary
{
var item = GetStudio(request.Name, LibraryManager);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
+ var dtoOptions = new DtoOptions();
if (request.UserId.HasValue)
{
var user = UserManager.GetUserById(request.UserId.Value);
- return DtoService.GetBaseItemDto(item, fields.ToList(), user);
+ return DtoService.GetBaseItemDto(item, dtoOptions, user);
}
- return DtoService.GetBaseItemDto(item, fields.ToList());
+ return DtoService.GetBaseItemDto(item, dtoOptions);
}
/// <summary>
diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
index 040cad436..45a330a50 100644
--- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
+++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
@@ -407,9 +407,6 @@ namespace MediaBrowser.Api.UserLibrary
{
var user = _userManager.GetUserById(request.UserId);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
-
var query = new UserViewQuery
{
UserId = request.UserId
@@ -423,7 +420,9 @@ namespace MediaBrowser.Api.UserLibrary
var folders = await _userViewManager.GetUserViews(query, CancellationToken.None).ConfigureAwait(false);
- var dtos = folders.Select(i => _dtoService.GetBaseItemDto(i, fields, user))
+ var dtoOptions = new DtoOptions();
+
+ var dtos = folders.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
.ToArray();
var result = new QueryResult<BaseItemDto>
@@ -443,14 +442,16 @@ namespace MediaBrowser.Api.UserLibrary
user.RootFolder :
_libraryManager.GetItemById(request.Id);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
-
var series = item as Series;
// Get them from the child tree
if (series != null)
{
+ var dtoOptions = new DtoOptions();
+
+ // Avoid implicitly captured closure
+ var currentUser = user;
+
var dtos = series
.GetRecursiveChildren()
.Where(i => i is Episode && i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == 0)
@@ -468,7 +469,7 @@ namespace MediaBrowser.Api.UserLibrary
return DateTime.MinValue;
})
.ThenBy(i => i.SortName)
- .Select(i => _dtoService.GetBaseItemDto(i, fields, user));
+ .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, currentUser));
return dtos.ToList();
}
@@ -478,10 +479,12 @@ namespace MediaBrowser.Api.UserLibrary
// Get them from the db
if (movie != null)
{
+ var dtoOptions = new DtoOptions();
+
var dtos = movie.SpecialFeatureIds
.Select(_libraryManager.GetItemById)
.OrderBy(i => i.SortName)
- .Select(i => _dtoService.GetBaseItemDto(i, fields, user, item));
+ .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
return dtos.ToList();
}
@@ -507,9 +510,6 @@ namespace MediaBrowser.Api.UserLibrary
var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : _libraryManager.GetItemById(request.Id);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
-
var trailerIds = new List<Guid>();
var hasTrailers = item as IHasTrailers;
@@ -518,10 +518,12 @@ namespace MediaBrowser.Api.UserLibrary
trailerIds = hasTrailers.GetTrailerIds();
}
+ var dtoOptions = new DtoOptions();
+
var dtos = trailerIds
.Select(_libraryManager.GetItemById)
.OrderBy(i => i.SortName)
- .Select(i => _dtoService.GetBaseItemDto(i, fields, user, item));
+ .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
return dtos.ToList();
}
@@ -537,10 +539,9 @@ namespace MediaBrowser.Api.UserLibrary
var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : _libraryManager.GetItemById(request.Id);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
+ var dtoOptions = new DtoOptions();
- var result = _dtoService.GetBaseItemDto(item, fields, user);
+ var result = _dtoService.GetBaseItemDto(item, dtoOptions, user);
return ToOptimizedSerializedResultUsingCache(result);
}
@@ -556,10 +557,9 @@ namespace MediaBrowser.Api.UserLibrary
var item = user.RootFolder;
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
+ var dtoOptions = new DtoOptions();
- var result = _dtoService.GetBaseItemDto(item, fields, user);
+ var result = _dtoService.GetBaseItemDto(item, dtoOptions, user);
return ToOptimizedSerializedResultUsingCache(result);
}
@@ -577,12 +577,9 @@ namespace MediaBrowser.Api.UserLibrary
var items = await _libraryManager.GetIntros(item, user).ConfigureAwait(false);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields))
- .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
- .ToList();
+ var dtoOptions = new DtoOptions();
- var dtos = items.Select(i => _dtoService.GetBaseItemDto(i, fields, user))
+ var dtos = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
.ToArray();
var result = new ItemsResult
diff --git a/MediaBrowser.Api/UserLibrary/YearsService.cs b/MediaBrowser.Api/UserLibrary/YearsService.cs
index 2b300f900..b1b0aeb63 100644
--- a/MediaBrowser.Api/UserLibrary/YearsService.cs
+++ b/MediaBrowser.Api/UserLibrary/YearsService.cs
@@ -73,17 +73,16 @@ namespace MediaBrowser.Api.UserLibrary
{
var item = LibraryManager.GetYear(request.Year);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
+ var dtoOptions = new DtoOptions();
if (request.UserId.HasValue)
{
var user = UserManager.GetUserById(request.UserId.Value);
- return DtoService.GetBaseItemDto(item, fields.ToList(), user);
+ return DtoService.GetBaseItemDto(item, dtoOptions, user);
}
- return DtoService.GetBaseItemDto(item, fields.ToList());
+ return DtoService.GetBaseItemDto(item, dtoOptions);
}
/// <summary>
diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs
index 4b720c775..51a7584b8 100644
--- a/MediaBrowser.Api/UserService.cs
+++ b/MediaBrowser.Api/UserService.cs
@@ -1,10 +1,12 @@
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Connect;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Users;
@@ -51,7 +53,7 @@ namespace MediaBrowser.Api
/// </summary>
/// <value>The id.</value>
[ApiMember(Name = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public Guid Id { get; set; }
+ public string Id { get; set; }
}
/// <summary>
@@ -66,7 +68,7 @@ namespace MediaBrowser.Api
/// </summary>
/// <value>The id.</value>
[ApiMember(Name = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
- public Guid Id { get; set; }
+ public string Id { get; set; }
}
/// <summary>
@@ -80,7 +82,7 @@ namespace MediaBrowser.Api
/// </summary>
/// <value>The id.</value>
[ApiMember(Name = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public Guid Id { get; set; }
+ public string Id { get; set; }
/// <summary>
/// Gets or sets the password.
@@ -125,7 +127,7 @@ namespace MediaBrowser.Api
/// Gets or sets the id.
/// </summary>
/// <value>The id.</value>
- public Guid Id { get; set; }
+ public string Id { get; set; }
/// <summary>
/// Gets or sets the password.
@@ -156,6 +158,28 @@ namespace MediaBrowser.Api
}
/// <summary>
+ /// Class UpdateUser
+ /// </summary>
+ [Route("/Users/{Id}/Policy", "POST", Summary = "Updates a user policy")]
+ [Authenticated(Roles = "admin")]
+ public class UpdateUserPolicy : UserPolicy, IReturnVoid
+ {
+ [ApiMember(Name = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
+ public string Id { get; set; }
+ }
+
+ /// <summary>
+ /// Class UpdateUser
+ /// </summary>
+ [Route("/Users/{Id}/Configuration", "POST", Summary = "Updates a user configuration")]
+ [Authenticated]
+ public class UpdateUserConfiguration : UserConfiguration, IReturnVoid
+ {
+ [ApiMember(Name = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
+ public string Id { get; set; }
+ }
+
+ /// <summary>
/// Class CreateUser
/// </summary>
[Route("/Users/New", "POST", Summary = "Creates a user")]
@@ -193,22 +217,18 @@ namespace MediaBrowser.Api
private readonly ISessionManager _sessionMananger;
private readonly IServerConfigurationManager _config;
private readonly INetworkManager _networkManager;
+ private readonly IDeviceManager _deviceManager;
public IAuthorizationContext AuthorizationContext { get; set; }
- /// <summary>
- /// Initializes a new instance of the <see cref="UserService" /> class.
- /// </summary>
- /// <param name="userManager">The user manager.</param>
- /// <param name="dtoService">The dto service.</param>
- /// <param name="sessionMananger">The session mananger.</param>
- public UserService(IUserManager userManager, IDtoService dtoService, ISessionManager sessionMananger, IServerConfigurationManager config, INetworkManager networkManager)
+ public UserService(IUserManager userManager, IDtoService dtoService, ISessionManager sessionMananger, IServerConfigurationManager config, INetworkManager networkManager, IDeviceManager deviceManager)
{
_userManager = userManager;
_dtoService = dtoService;
_sessionMananger = sessionMananger;
_config = config;
_networkManager = networkManager;
+ _deviceManager = deviceManager;
}
public object Get(GetPublicUsers request)
@@ -222,18 +242,12 @@ namespace MediaBrowser.Api
});
}
- // TODO: Uncomment once clients can handle an empty user list (and below)
- //if (Request.IsLocal || IsInLocalNetwork(Request.RemoteIp))
+ return Get(new GetUsers
{
- return Get(new GetUsers
- {
- IsHidden = false,
- IsDisabled = false
- });
- }
+ IsHidden = false,
+ IsDisabled = false
- //// Return empty when external
- //return ToOptimizedResult(new List<UserDto>());
+ }, true);
}
/// <summary>
@@ -243,24 +257,38 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns>
public object Get(GetUsers request)
{
+ return Get(request, false);
+ }
+
+ private object Get(GetUsers request, bool filterByDevice)
+ {
var users = _userManager.Users;
if (request.IsDisabled.HasValue)
{
- users = users.Where(i => i.Configuration.IsDisabled == request.IsDisabled.Value);
+ users = users.Where(i => i.Policy.IsDisabled == request.IsDisabled.Value);
}
if (request.IsHidden.HasValue)
{
- users = users.Where(i => i.Configuration.IsHidden == request.IsHidden.Value);
+ users = users.Where(i => i.Policy.IsHidden == request.IsHidden.Value);
}
if (request.IsGuest.HasValue)
{
-
users = users.Where(i => (i.ConnectLinkType.HasValue && i.ConnectLinkType.Value == UserLinkType.Guest) == request.IsGuest.Value);
}
+ if (filterByDevice)
+ {
+ var deviceId = AuthorizationContext.GetAuthorizationInfo(Request).DeviceId;
+
+ if (!string.IsNullOrWhiteSpace(deviceId))
+ {
+ users = users.Where(i => _deviceManager.CanAccessDevice(i.Id.ToString("N"), deviceId));
+ }
+ }
+
var result = users
.OrderBy(u => u.Name)
.Select(i => _userManager.GetUserDto(i, Request.RemoteIp))
@@ -428,39 +456,13 @@ namespace MediaBrowser.Api
var user = _userManager.GetUserById(id);
- // If removing admin access
- if (!dtoUser.Configuration.IsAdministrator && user.Configuration.IsAdministrator)
- {
- if (_userManager.Users.Count(i => i.Configuration.IsAdministrator) == 1)
- {
- throw new ArgumentException("There must be at least one user in the system with administrative access.");
- }
- }
-
- // If disabling
- if (dtoUser.Configuration.IsDisabled && user.Configuration.IsAdministrator)
- {
- throw new ArgumentException("Administrators cannot be disabled.");
- }
-
- // If disabling
- if (dtoUser.Configuration.IsDisabled && !user.Configuration.IsDisabled)
- {
- if (_userManager.Users.Count(i => !i.Configuration.IsDisabled) == 1)
- {
- throw new ArgumentException("There must be at least one enabled user in the system.");
- }
-
- await _sessionMananger.RevokeUserTokens(user.Id.ToString("N")).ConfigureAwait(false);
- }
-
var task = user.Name.Equals(dtoUser.Name, StringComparison.Ordinal) ?
_userManager.UpdateUser(user) :
_userManager.RenameUser(user, dtoUser.Name);
await task.ConfigureAwait(false);
- user.UpdateConfiguration(dtoUser.Configuration);
+ await _userManager.UpdateConfiguration(dtoUser.Id, dtoUser.Configuration);
}
/// <summary>
@@ -495,5 +497,51 @@ namespace MediaBrowser.Api
{
return _userManager.RedeemPasswordResetPin(request.Pin);
}
+
+ public void Post(UpdateUserConfiguration request)
+ {
+ var task = _userManager.UpdateConfiguration(request.Id, request);
+
+ Task.WaitAll(task);
+ }
+
+ public void Post(UpdateUserPolicy request)
+ {
+ var task = UpdateUserPolicy(request);
+ Task.WaitAll(task);
+ }
+
+ private async Task UpdateUserPolicy(UpdateUserPolicy request)
+ {
+ var user = _userManager.GetUserById(request.Id);
+
+ // If removing admin access
+ if (!request.IsAdministrator && user.Policy.IsAdministrator)
+ {
+ if (_userManager.Users.Count(i => i.Policy.IsAdministrator) == 1)
+ {
+ throw new ArgumentException("There must be at least one user in the system with administrative access.");
+ }
+ }
+
+ // If disabling
+ if (request.IsDisabled && user.Policy.IsAdministrator)
+ {
+ throw new ArgumentException("Administrators cannot be disabled.");
+ }
+
+ // If disabling
+ if (request.IsDisabled && !user.Policy.IsDisabled)
+ {
+ if (_userManager.Users.Count(i => !i.Policy.IsDisabled) == 1)
+ {
+ throw new ArgumentException("There must be at least one enabled user in the system.");
+ }
+
+ await _sessionMananger.RevokeUserTokens(user.Id.ToString("N")).ConfigureAwait(false);
+ }
+
+ await _userManager.UpdateUserPolicy(request.Id, request).ConfigureAwait(false);
+ }
}
}
diff --git a/MediaBrowser.Api/VideosService.cs b/MediaBrowser.Api/VideosService.cs
index fbf9cec2e..28db46b98 100644
--- a/MediaBrowser.Api/VideosService.cs
+++ b/MediaBrowser.Api/VideosService.cs
@@ -5,6 +5,7 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying;
using ServiceStack;
using System;
@@ -79,15 +80,12 @@ namespace MediaBrowser.Api
: _libraryManager.RootFolder)
: _libraryManager.GetItemById(request.Id);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields))
- .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
- .ToList();
+ var dtoOptions = new DtoOptions();
var video = (Video)item;
var items = video.GetAdditionalParts()
- .Select(i => _dtoService.GetBaseItemDto(i, fields, user, video))
+ .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, video))
.ToArray();
var result = new ItemsResult
@@ -114,11 +112,11 @@ namespace MediaBrowser.Api
{
link.PrimaryVersionId = null;
- await link.UpdateToRepository(ItemUpdateType.MetadataDownload, CancellationToken.None).ConfigureAwait(false);
+ await link.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
}
video.LinkedAlternateVersions.Clear();
- await video.UpdateToRepository(ItemUpdateType.MetadataDownload, CancellationToken.None).ConfigureAwait(false);
+ await video.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
}
public void Post(MergeVersions request)
@@ -186,7 +184,7 @@ namespace MediaBrowser.Api
{
item.PrimaryVersionId = primaryVersion.Id;
- await item.UpdateToRepository(ItemUpdateType.MetadataDownload, CancellationToken.None).ConfigureAwait(false);
+ await item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
primaryVersion.LinkedAlternateVersions.Add(new LinkedChild
{
@@ -195,7 +193,7 @@ namespace MediaBrowser.Api
});
}
- await primaryVersion.UpdateToRepository(ItemUpdateType.MetadataDownload, CancellationToken.None).ConfigureAwait(false);
+ await primaryVersion.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
}
}
}
diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
index 9e14d0ee8..4de1adcfa 100644
--- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
+++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
@@ -466,7 +466,7 @@ namespace MediaBrowser.Common.Implementations
RegisterSingleInstance(FileSystemManager);
- HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, Logger, FileSystemManager, ConfigurationManager);
+ HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, Logger, FileSystemManager);
RegisterSingleInstance(HttpClient);
NetworkManager = CreateNetworkManager(LogManager.GetLogger("NetworkManager"));
diff --git a/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs b/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs
index 4a70697fa..c53947e44 100644
--- a/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs
+++ b/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs
@@ -105,7 +105,7 @@ namespace MediaBrowser.Common.Implementations.Configuration
UpdateCachePath();
}
- public void AddParts(IEnumerable<IConfigurationFactory> factories)
+ public virtual void AddParts(IEnumerable<IConfigurationFactory> factories)
{
_configurationFactories = factories.ToArray();
@@ -208,20 +208,51 @@ namespace MediaBrowser.Common.Implementations.Configuration
lock (_configurationSyncLock)
{
- return ConfigurationHelper.GetXmlConfiguration(configurationType, file, XmlSerializer);
+ return LoadConfiguration(file, configurationType);
}
});
}
+ private object LoadConfiguration(string path, Type configurationType)
+ {
+ try
+ {
+ return XmlSerializer.DeserializeFromFile(configurationType, path);
+ }
+ catch (FileNotFoundException)
+ {
+ return Activator.CreateInstance(configurationType);
+ }
+ catch (DirectoryNotFoundException)
+ {
+ return Activator.CreateInstance(configurationType);
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error loading configuration file: {0}", ex, path);
+
+ return Activator.CreateInstance(configurationType);
+ }
+ }
+
public void SaveConfiguration(string key, object configuration)
{
- var configurationType = GetConfigurationType(key);
+ var configurationStore = GetConfigurationStore(key);
+ var configurationType = configurationStore.ConfigurationType;
if (configuration.GetType() != configurationType)
{
throw new ArgumentException("Expected configuration type is " + configurationType.Name);
}
+ var validatingStore = configurationStore as IValidatingConfiguration;
+ if (validatingStore != null)
+ {
+ var currentConfiguration = GetConfiguration(key);
+
+ validatingStore.Validate(currentConfiguration, configuration);
+ }
+
EventHelper.FireEventIfNotNull(NamedConfigurationUpdating, this, new ConfigurationUpdateEventArgs
{
Key = key,
@@ -239,6 +270,11 @@ namespace MediaBrowser.Common.Implementations.Configuration
XmlSerializer.SerializeToFile(configuration, path);
}
+ OnNamedConfigurationUpdated(key, configuration);
+ }
+
+ protected virtual void OnNamedConfigurationUpdated(string key, object configuration)
+ {
EventHelper.FireEventIfNotNull(NamedConfigurationUpdated, this, new ConfigurationUpdateEventArgs
{
Key = key,
@@ -249,9 +285,14 @@ namespace MediaBrowser.Common.Implementations.Configuration
public Type GetConfigurationType(string key)
{
- return _configurationStores
- .First(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase))
+ return GetConfigurationStore(key)
.ConfigurationType;
}
+
+ private ConfigurationStore GetConfigurationStore(string key)
+ {
+ return _configurationStores
+ .First(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase));
+ }
}
}
diff --git a/MediaBrowser.Common/Configuration/ConfigurationHelper.cs b/MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs
index 8c904b0db..ff5b8bd59 100644
--- a/MediaBrowser.Common/Configuration/ConfigurationHelper.cs
+++ b/MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs
@@ -3,7 +3,7 @@ using System;
using System.IO;
using System.Linq;
-namespace MediaBrowser.Common.Configuration
+namespace MediaBrowser.Common.Implementations.Configuration
{
/// <summary>
/// Class ConfigurationHelper
@@ -55,20 +55,5 @@ namespace MediaBrowser.Common.Configuration
return configuration;
}
}
-
- /// <summary>
- /// Reads an xml configuration file from the file system
- /// It will immediately save the configuration after loading it, just
- /// in case there are new serializable properties
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="path">The path.</param>
- /// <param name="xmlSerializer">The XML serializer.</param>
- /// <returns>``0.</returns>
- public static T GetXmlConfiguration<T>(string path, IXmlSerializer xmlSerializer)
- where T : class
- {
- return GetXmlConfiguration(typeof(T), path, xmlSerializer) as T;
- }
}
}
diff --git a/MediaBrowser.Common.Implementations/Devices/DeviceId.cs b/MediaBrowser.Common.Implementations/Devices/DeviceId.cs
index 5af236026..7c0dc1e1f 100644
--- a/MediaBrowser.Common.Implementations/Devices/DeviceId.cs
+++ b/MediaBrowser.Common.Implementations/Devices/DeviceId.cs
@@ -38,7 +38,10 @@ namespace MediaBrowser.Common.Implementations.Devices
_logger.Error("Invalid value found in device id file");
}
}
- catch (FileNotFoundException ex)
+ catch (DirectoryNotFoundException)
+ {
+ }
+ catch (FileNotFoundException)
{
}
catch (Exception ex)
diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
index 89d00b87d..1f82c5eb0 100644
--- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
+++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
@@ -41,7 +41,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
private readonly IApplicationPaths _appPaths;
private readonly IFileSystem _fileSystem;
- private readonly IConfigurationManager _config;
/// <summary>
/// Initializes a new instance of the <see cref="HttpClientManager" /> class.
@@ -52,7 +51,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
/// <exception cref="System.ArgumentNullException">appPaths
/// or
/// logger</exception>
- public HttpClientManager(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem, IConfigurationManager config)
+ public HttpClientManager(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem)
{
if (appPaths == null)
{
@@ -65,7 +64,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
_logger = logger;
_fileSystem = fileSystem;
- _config = config;
_appPaths = appPaths;
// http://stackoverflow.com/questions/566437/http-post-returns-the-error-417-expectation-failed-c
diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
index 39fa9e802..ff08c31bc 100644
--- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
+++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
@@ -81,6 +81,7 @@
<Compile Include="BaseApplicationHost.cs" />
<Compile Include="BaseApplicationPaths.cs" />
<Compile Include="Configuration\BaseConfigurationManager.cs" />
+ <Compile Include="Configuration\ConfigurationHelper.cs" />
<Compile Include="Devices\DeviceId.cs" />
<Compile Include="HttpClientManager\HttpClientInfo.cs" />
<Compile Include="HttpClientManager\HttpClientManager.cs" />
diff --git a/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs b/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs
index 8f3225f4e..63381efcd 100644
--- a/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs
+++ b/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs
@@ -101,6 +101,10 @@ namespace MediaBrowser.Common.Implementations.Security
{
contents = File.ReadAllLines(licenseFile);
}
+ catch (DirectoryNotFoundException)
+ {
+ (File.Create(licenseFile)).Close();
+ }
catch (FileNotFoundException)
{
(File.Create(licenseFile)).Close();
diff --git a/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs b/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs
index cef744753..04030522f 100644
--- a/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs
+++ b/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Model.Serialization;
using System;
+using System.Collections.Concurrent;
using System.IO;
using System.Xml;
@@ -10,6 +11,17 @@ namespace MediaBrowser.Common.Implementations.Serialization
/// </summary>
public class XmlSerializer : IXmlSerializer
{
+ // Need to cache these
+ // http://dotnetcodebox.blogspot.com/2013/01/xmlserializer-class-may-result-in.html
+ private readonly ConcurrentDictionary<string, System.Xml.Serialization.XmlSerializer> _serializers =
+ new ConcurrentDictionary<string, System.Xml.Serialization.XmlSerializer>();
+
+ private System.Xml.Serialization.XmlSerializer GetSerializer(Type type)
+ {
+ var key = type.FullName;
+ return _serializers.GetOrAdd(key, k => new System.Xml.Serialization.XmlSerializer(type));
+ }
+
/// <summary>
/// Serializes to writer.
/// </summary>
@@ -18,7 +30,7 @@ namespace MediaBrowser.Common.Implementations.Serialization
private void SerializeToWriter(object obj, XmlTextWriter writer)
{
writer.Formatting = Formatting.Indented;
- var netSerializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
+ var netSerializer = GetSerializer(obj.GetType());
netSerializer.Serialize(writer, obj);
}
@@ -32,8 +44,7 @@ namespace MediaBrowser.Common.Implementations.Serialization
{
using (var reader = new XmlTextReader(stream))
{
- var netSerializer = new System.Xml.Serialization.XmlSerializer(type);
-
+ var netSerializer = GetSerializer(type);
return netSerializer.Deserialize(reader);
}
}
diff --git a/MediaBrowser.Common.Implementations/packages.config b/MediaBrowser.Common.Implementations/packages.config
index c57aea0b5..63d288bbb 100644
--- a/MediaBrowser.Common.Implementations/packages.config
+++ b/MediaBrowser.Common.Implementations/packages.config
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NLog" version="3.1.0.0" targetFramework="net45" />
- <package id="SharpCompress" version="0.10.2" targetFramework="net45" />
<package id="SimpleInjector" version="2.6.1" targetFramework="net45" />
</packages>
diff --git a/MediaBrowser.Common/Configuration/IConfigurationFactory.cs b/MediaBrowser.Common/Configuration/IConfigurationFactory.cs
index d418d0a42..6ed638536 100644
--- a/MediaBrowser.Common/Configuration/IConfigurationFactory.cs
+++ b/MediaBrowser.Common/Configuration/IConfigurationFactory.cs
@@ -14,4 +14,9 @@ namespace MediaBrowser.Common.Configuration
public Type ConfigurationType { get; set; }
}
+
+ public interface IValidatingConfiguration
+ {
+ void Validate(object oldConfig, object newConfig);
+ }
}
diff --git a/MediaBrowser.Common/Extensions/BaseExtensions.cs b/MediaBrowser.Common/Extensions/BaseExtensions.cs
index 8e96373f4..4c94f3aa2 100644
--- a/MediaBrowser.Common/Extensions/BaseExtensions.cs
+++ b/MediaBrowser.Common/Extensions/BaseExtensions.cs
@@ -1,4 +1,6 @@
using System;
+using System.Globalization;
+using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
@@ -54,6 +56,15 @@ namespace MediaBrowser.Common.Extensions
return sb.ToString();
}
+ public static string RemoveDiacritics(this string text)
+ {
+ return String.Concat(
+ text.Normalize(NormalizationForm.FormD)
+ .Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) !=
+ UnicodeCategory.NonSpacingMark)
+ ).Normalize(NormalizationForm.FormC);
+ }
+
/// <summary>
/// Gets the M d5.
/// </summary>
diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj
index 9fdfccaaf..c46dd4a4f 100644
--- a/MediaBrowser.Common/MediaBrowser.Common.csproj
+++ b/MediaBrowser.Common/MediaBrowser.Common.csproj
@@ -53,7 +53,6 @@
<Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
- <Compile Include="Configuration\ConfigurationHelper.cs" />
<Compile Include="Configuration\ConfigurationUpdateEventArgs.cs" />
<Compile Include="Configuration\IConfigurationManager.cs" />
<Compile Include="Configuration\IConfigurationFactory.cs" />
@@ -64,19 +63,12 @@
<Compile Include="IO\IFileSystem.cs" />
<Compile Include="IO\ProgressStream.cs" />
<Compile Include="IO\StreamDefaults.cs" />
- <Compile Include="Net\BasePeriodicWebSocketListener.cs" />
<Compile Include="Configuration\IApplicationPaths.cs" />
<Compile Include="Net\HttpRequestOptions.cs" />
<Compile Include="Net\HttpResponseInfo.cs" />
- <Compile Include="Net\IWebSocketListener.cs" />
<Compile Include="IApplicationHost.cs" />
<Compile Include="Net\IHttpClient.cs" />
<Compile Include="Net\INetworkManager.cs" />
- <Compile Include="Net\IWebSocket.cs" />
- <Compile Include="Net\IWebSocketConnection.cs" />
- <Compile Include="Net\MimeTypes.cs" />
- <Compile Include="Net\WebSocketConnectEventArgs.cs" />
- <Compile Include="Net\WebSocketMessageInfo.cs" />
<Compile Include="Plugins\IDependencyModule.cs" />
<Compile Include="Plugins\IPlugin.cs" />
<Compile Include="Progress\ActionableProgress.cs" />
diff --git a/MediaBrowser.Common/Plugins/BasePlugin.cs b/MediaBrowser.Common/Plugins/BasePlugin.cs
index 6bbd69f04..9d0133c67 100644
--- a/MediaBrowser.Common/Plugins/BasePlugin.cs
+++ b/MediaBrowser.Common/Plugins/BasePlugin.cs
@@ -5,7 +5,6 @@ using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
-using System.Threading;
namespace MediaBrowser.Common.Plugins
{
@@ -164,11 +163,7 @@ namespace MediaBrowser.Common.Plugins
/// <summary>
/// The _configuration sync lock
/// </summary>
- private object _configurationSyncLock = new object();
- /// <summary>
- /// The _configuration initialized
- /// </summary>
- private bool _configurationInitialized;
+ private readonly object _configurationSyncLock = new object();
/// <summary>
/// The _configuration
/// </summary>
@@ -182,17 +177,43 @@ namespace MediaBrowser.Common.Plugins
get
{
// Lazy load
- LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationInitialized, ref _configurationSyncLock, () => ConfigurationHelper.GetXmlConfiguration(ConfigurationType, ConfigurationFilePath, XmlSerializer) as TConfigurationType);
+ if (_configuration == null)
+ {
+ lock (_configurationSyncLock)
+ {
+ if (_configuration == null)
+ {
+ _configuration = LoadConfiguration();
+ }
+ }
+ }
return _configuration;
}
protected set
{
_configuration = value;
+ }
+ }
- if (value == null)
- {
- _configurationInitialized = false;
- }
+ private TConfigurationType LoadConfiguration()
+ {
+ var path = ConfigurationFilePath;
+
+ try
+ {
+ return (TConfigurationType)XmlSerializer.DeserializeFromFile(typeof(TConfigurationType), path);
+ }
+ catch (DirectoryNotFoundException)
+ {
+ return (TConfigurationType)Activator.CreateInstance(typeof(TConfigurationType));
+ }
+ catch (FileNotFoundException)
+ {
+ return (TConfigurationType)Activator.CreateInstance(typeof(TConfigurationType));
+ }
+ catch (Exception ex)
+ {
+ return (TConfigurationType)Activator.CreateInstance(typeof(TConfigurationType));
}
}
diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs
index f618c8a25..5a9fc3322 100644
--- a/MediaBrowser.Controller/Channels/Channel.cs
+++ b/MediaBrowser.Controller/Channels/Channel.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.Controller.Channels
public override bool IsVisible(User user)
{
- if (user.Configuration.BlockedChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
+ if (user.Policy.BlockedChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
{
return false;
}
diff --git a/MediaBrowser.Controller/Channels/ChannelAudioItem.cs b/MediaBrowser.Controller/Channels/ChannelAudioItem.cs
index ede366dab..896d598bb 100644
--- a/MediaBrowser.Controller/Channels/ChannelAudioItem.cs
+++ b/MediaBrowser.Controller/Channels/ChannelAudioItem.cs
@@ -6,6 +6,7 @@ using MediaBrowser.Model.Entities;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Channels
{
@@ -25,8 +26,8 @@ namespace MediaBrowser.Controller.Channels
public string OriginalImageUrl { get; set; }
public List<ChannelMediaInfo> ChannelMediaSources { get; set; }
-
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.ChannelContent);
}
diff --git a/MediaBrowser.Controller/Channels/ChannelFolderItem.cs b/MediaBrowser.Controller/Channels/ChannelFolderItem.cs
index 5362cc195..8482e38df 100644
--- a/MediaBrowser.Controller/Channels/ChannelFolderItem.cs
+++ b/MediaBrowser.Controller/Channels/ChannelFolderItem.cs
@@ -5,6 +5,7 @@ using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Querying;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Channels
{
@@ -20,7 +21,7 @@ namespace MediaBrowser.Controller.Channels
public string OriginalImageUrl { get; set; }
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
// Don't block.
return false;
diff --git a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs
index 72e2b110a..f0eafcbdf 100644
--- a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs
+++ b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs
@@ -8,6 +8,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Channels
{
@@ -51,7 +52,7 @@ namespace MediaBrowser.Controller.Channels
return ExternalId;
}
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.ChannelContent);
}
diff --git a/MediaBrowser.Controller/Devices/IDeviceManager.cs b/MediaBrowser.Controller/Devices/IDeviceManager.cs
index efd24336a..f5010bb45 100644
--- a/MediaBrowser.Controller/Devices/IDeviceManager.cs
+++ b/MediaBrowser.Controller/Devices/IDeviceManager.cs
@@ -85,5 +85,13 @@ namespace MediaBrowser.Controller.Devices
/// <param name="file">The file.</param>
/// <returns>Task.</returns>
Task AcceptCameraUpload(string deviceId, Stream stream, LocalFileInfo file);
+
+ /// <summary>
+ /// Determines whether this instance [can access device] the specified user identifier.
+ /// </summary>
+ /// <param name="userId">The user identifier.</param>
+ /// <param name="deviceId">The device identifier.</param>
+ /// <returns><c>true</c> if this instance [can access device] the specified user identifier; otherwise, <c>false</c>.</returns>
+ bool CanAccessDevice(string userId, string deviceId);
}
}
diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs
index 447328ea1..c5ed09016 100644
--- a/MediaBrowser.Controller/Entities/Audio/Audio.cs
+++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs
@@ -8,6 +8,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities.Audio
{
@@ -88,6 +89,21 @@ namespace MediaBrowser.Controller.Entities.Audio
}
}
+ [IgnoreDataMember]
+ public bool IsArchive
+ {
+ get
+ {
+ if (string.IsNullOrWhiteSpace(Path))
+ {
+ return false;
+ }
+ var ext = System.IO.Path.GetExtension(Path) ?? string.Empty;
+
+ return new[] { ".zip", ".rar", ".7z" }.Contains(ext, StringComparer.OrdinalIgnoreCase);
+ }
+ }
+
/// <summary>
/// Gets or sets the artist.
/// </summary>
@@ -173,7 +189,7 @@ namespace MediaBrowser.Controller.Entities.Audio
return base.GetUserDataKey();
}
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.Music);
}
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
index 1f7c62de0..90edfcce7 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities.Audio
{
@@ -154,7 +155,7 @@ namespace MediaBrowser.Controller.Entities.Audio
return base.GetUserDataKey();
}
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.Music);
}
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
index 2d9e052b1..a60258d1a 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
@@ -8,6 +8,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities.Audio
{
@@ -114,7 +115,7 @@ namespace MediaBrowser.Controller.Entities.Audio
return "Artist-" + item.Name;
}
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.Music);
}
@@ -135,7 +136,7 @@ namespace MediaBrowser.Controller.Entities.Audio
// Refresh songs
foreach (var item in songs)
{
- if (tasks.Count >= 3)
+ if (tasks.Count >= 2)
{
await Task.WhenAll(tasks).ConfigureAwait(false);
tasks.Clear();
@@ -172,37 +173,23 @@ namespace MediaBrowser.Controller.Entities.Audio
// Refresh all non-songs
foreach (var item in others)
{
- if (tasks.Count >= 3)
- {
- await Task.WhenAll(tasks).ConfigureAwait(false);
- tasks.Clear();
- }
-
cancellationToken.ThrowIfCancellationRequested();
- var innerProgress = new ActionableProgress<double>();
// Avoid implicitly captured closure
var currentChild = item;
- innerProgress.RegisterAction(p =>
- {
- lock (percentages)
- {
- percentages[currentChild.Id] = p / 100;
- var percent = percentages.Values.Sum();
- percent /= totalItems;
- percent *= 100;
- progress.Report(percent);
- }
- });
+ await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
+ lock (percentages)
+ {
+ percentages[currentChild.Id] = 1;
- // Avoid implicitly captured closure
- var taskChild = item;
- tasks.Add(Task.Run(async () => await RefreshItem(taskChild, refreshOptions, innerProgress, cancellationToken).ConfigureAwait(false), cancellationToken));
+ var percent = percentages.Values.Sum();
+ percent /= totalItems;
+ percent *= 100;
+ progress.Report(percent);
+ }
}
- await Task.WhenAll(tasks).ConfigureAwait(false);
-
progress.Report(100);
}
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index ed950b1c5..90427de75 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -14,6 +14,7 @@ using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Library;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Users;
using System;
using System.Collections.Generic;
using System.IO;
@@ -45,6 +46,8 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public static readonly string[] SupportedImageExtensions = { ".png", ".jpg", ".jpeg", ".tbn" };
+ public static readonly List<string> SupportedImageExtensionsList = SupportedImageExtensions.ToList();
+
/// <summary>
/// The trailer folder name
/// </summary>
@@ -593,7 +596,7 @@ namespace MediaBrowser.Controller.Entities
/// <returns>PlayAccess.</returns>
public PlayAccess GetPlayAccess(User user)
{
- if (!user.Configuration.EnableMediaPlayback)
+ if (!user.Policy.EnableMediaPlayback)
{
return PlayAccess.None;
}
@@ -985,7 +988,7 @@ namespace MediaBrowser.Controller.Entities
return false;
}
- var maxAllowedRating = user.Configuration.MaxParentalRating;
+ var maxAllowedRating = user.Policy.MaxParentalRating;
if (maxAllowedRating == null)
{
@@ -1001,7 +1004,7 @@ namespace MediaBrowser.Controller.Entities
if (string.IsNullOrWhiteSpace(rating))
{
- return !GetBlockUnratedValue(user.Configuration);
+ return !GetBlockUnratedValue(user.Policy);
}
var value = LocalizationManager.GetRatingLevel(rating);
@@ -1021,7 +1024,7 @@ namespace MediaBrowser.Controller.Entities
if (hasTags != null)
{
- if (user.Configuration.BlockedTags.Any(i => hasTags.Tags.Contains(i, StringComparer.OrdinalIgnoreCase)))
+ if (user.Policy.BlockedTags.Any(i => hasTags.Tags.Contains(i, StringComparer.OrdinalIgnoreCase)))
{
return false;
}
@@ -1035,7 +1038,7 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <param name="config">The configuration.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
- protected virtual bool GetBlockUnratedValue(UserConfiguration config)
+ protected virtual bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.Other);
}
diff --git a/MediaBrowser.Controller/Entities/Book.cs b/MediaBrowser.Controller/Entities/Book.cs
index ea7ecfb4a..381b2101d 100644
--- a/MediaBrowser.Controller/Entities/Book.cs
+++ b/MediaBrowser.Controller/Entities/Book.cs
@@ -2,6 +2,7 @@
using MediaBrowser.Model.Configuration;
using System.Collections.Generic;
using System.Linq;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities
{
@@ -36,7 +37,7 @@ namespace MediaBrowser.Controller.Entities
Tags = new List<string>();
}
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.Book);
}
diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs
index a10742f01..f47a439a7 100644
--- a/MediaBrowser.Controller/Entities/CollectionFolder.cs
+++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs
@@ -66,6 +66,22 @@ namespace MediaBrowser.Controller.Entities
return CreateResolveArgs(directoryService).FileSystemChildren;
}
+ internal override bool IsValidFromResolver(BaseItem newItem)
+ {
+ var newCollectionFolder = newItem as CollectionFolder;
+
+ if (newCollectionFolder != null)
+ {
+ if (!string.Equals(CollectionType, newCollectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+ }
+
+
+ return base.IsValidFromResolver(newItem);
+ }
+
private ItemResolveArgs CreateResolveArgs(IDirectoryService directoryService)
{
var path = ContainingFolderPath;
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 87ad9c380..2761aa5d7 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -303,10 +303,10 @@ namespace MediaBrowser.Controller.Entities
{
if (this is ICollectionFolder)
{
- if (user.Configuration.BlockedMediaFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase) ||
+ if (user.Policy.BlockedMediaFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase) ||
// Backwards compatibility
- user.Configuration.BlockedMediaFolders.Contains(Name, StringComparer.OrdinalIgnoreCase))
+ user.Policy.BlockedMediaFolders.Contains(Name, StringComparer.OrdinalIgnoreCase))
{
return false;
}
@@ -545,7 +545,7 @@ namespace MediaBrowser.Controller.Entities
foreach (var child in children)
{
- if (tasks.Count >= 3)
+ if (tasks.Count >= 2)
{
await Task.WhenAll(tasks).ConfigureAwait(false);
tasks.Clear();
@@ -708,7 +708,7 @@ namespace MediaBrowser.Controller.Entities
/// <returns>IEnumerable{BaseItem}.</returns>
protected virtual IEnumerable<BaseItem> GetNonCachedChildren(IDirectoryService directoryService)
{
- var collectionType = LibraryManager.FindCollectionType(this);
+ var collectionType = LibraryManager.GetContentType(this);
return LibraryManager.ResolvePaths(GetFileSystemChildren(directoryService), directoryService, this, collectionType);
}
diff --git a/MediaBrowser.Controller/Entities/Game.cs b/MediaBrowser.Controller/Entities/Game.cs
index e4d032359..bf32d3e63 100644
--- a/MediaBrowser.Controller/Entities/Game.cs
+++ b/MediaBrowser.Controller/Entities/Game.cs
@@ -4,6 +4,7 @@ using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities
{
@@ -108,7 +109,7 @@ namespace MediaBrowser.Controller.Entities
return base.GetDeletePaths();
}
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.Game);
}
diff --git a/MediaBrowser.Controller/Entities/GameSystem.cs b/MediaBrowser.Controller/Entities/GameSystem.cs
index f2fec4397..758498977 100644
--- a/MediaBrowser.Controller/Entities/GameSystem.cs
+++ b/MediaBrowser.Controller/Entities/GameSystem.cs
@@ -2,6 +2,7 @@
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using System;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities
{
@@ -43,7 +44,7 @@ namespace MediaBrowser.Controller.Entities
return base.GetUserDataKey();
}
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
// Don't block. Determine by game
return false;
diff --git a/MediaBrowser.Controller/Entities/IHasMediaSources.cs b/MediaBrowser.Controller/Entities/IHasMediaSources.cs
index d487362f5..98d268298 100644
--- a/MediaBrowser.Controller/Entities/IHasMediaSources.cs
+++ b/MediaBrowser.Controller/Entities/IHasMediaSources.cs
@@ -49,8 +49,8 @@ namespace MediaBrowser.Controller.Entities
: new[] { user.Configuration.AudioLanguagePreference };
var preferredSubs = string.IsNullOrEmpty(user.Configuration.SubtitleLanguagePreference)
- ? new string[] { }
- : new[] { user.Configuration.SubtitleLanguagePreference };
+ ? new List<string> { }
+ : new List<string> { user.Configuration.SubtitleLanguagePreference };
foreach (var source in sources)
{
diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
index 9dc600675..4483c7b0f 100644
--- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
+++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
@@ -9,6 +9,7 @@ using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities.Movies
{
@@ -18,7 +19,7 @@ namespace MediaBrowser.Controller.Entities.Movies
public class BoxSet : Folder, IHasTrailers, IHasKeywords, IHasPreferredMetadataLanguage, IHasDisplayOrder, IHasLookupInfo<BoxSetInfo>, IMetadataContainer, IHasShares
{
public List<Share> Shares { get; set; }
-
+
public BoxSet()
{
RemoteTrailers = new List<MediaUrl>();
@@ -67,7 +68,7 @@ namespace MediaBrowser.Controller.Entities.Movies
/// <value>The display order.</value>
public string DisplayOrder { get; set; }
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.Movie);
}
@@ -170,10 +171,13 @@ namespace MediaBrowser.Controller.Entities.Movies
{
var userId = user.Id.ToString("N");
- return Shares.Any(i => string.Equals(userId, i.UserId, StringComparison.OrdinalIgnoreCase)) ||
+ // Need to check Count > 0 for boxsets created prior to the introduction of Shares
+ if (Shares.Count > 0 && !Shares.Any(i => string.Equals(userId, i.UserId, StringComparison.OrdinalIgnoreCase)))
+ {
+ //return false;
+ }
- // Need to support this for boxsets created prior to the creation of Shares
- Shares.Count == 0;
+ return true;
}
return false;
diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs
index e749d89e4..4c1aac700 100644
--- a/MediaBrowser.Controller/Entities/Movies/Movie.cs
+++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs
@@ -8,6 +8,7 @@ using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities.Movies
{
@@ -146,14 +147,21 @@ namespace MediaBrowser.Controller.Entities.Movies
return itemsChanged;
}
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.Movie);
}
public MovieInfo GetLookupInfo()
{
- return GetItemLookupInfo<MovieInfo>();
+ var info = GetItemLookupInfo<MovieInfo>();
+
+ if (!IsInMixedFolder)
+ {
+ info.Name = System.IO.Path.GetFileName(ContainingFolderPath);
+ }
+
+ return info;
}
public override bool BeforeMetadataRefresh()
diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs
index d7cd62aa6..4ca8cf1c5 100644
--- a/MediaBrowser.Controller/Entities/MusicVideo.cs
+++ b/MediaBrowser.Controller/Entities/MusicVideo.cs
@@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities
{
@@ -80,7 +81,7 @@ namespace MediaBrowser.Controller.Entities
return this.GetProviderId(MetadataProviders.Tmdb) ?? this.GetProviderId(MetadataProviders.Imdb) ?? base.GetUserDataKey();
}
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.Music);
}
diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs
index 367db5dcb..a3d892181 100644
--- a/MediaBrowser.Controller/Entities/Photo.cs
+++ b/MediaBrowser.Controller/Entities/Photo.cs
@@ -3,6 +3,7 @@ using MediaBrowser.Model.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities
{
@@ -69,8 +70,8 @@ namespace MediaBrowser.Controller.Entities
public double? Longitude { get; set; }
public double? Altitude { get; set; }
public int? IsoSpeedRating { get; set; }
-
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.Other);
}
diff --git a/MediaBrowser.Controller/Entities/PhotoAlbum.cs b/MediaBrowser.Controller/Entities/PhotoAlbum.cs
index 982b1ef17..24ebf8815 100644
--- a/MediaBrowser.Controller/Entities/PhotoAlbum.cs
+++ b/MediaBrowser.Controller/Entities/PhotoAlbum.cs
@@ -1,6 +1,7 @@
using MediaBrowser.Model.Configuration;
using System.Linq;
using System.Runtime.Serialization;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities
{
@@ -22,8 +23,8 @@ namespace MediaBrowser.Controller.Entities
return true;
}
}
-
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.Other);
}
diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs
index cc0fc6812..6b67cebc8 100644
--- a/MediaBrowser.Controller/Entities/TV/Episode.cs
+++ b/MediaBrowser.Controller/Entities/TV/Episode.cs
@@ -1,7 +1,7 @@
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
+using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Users;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -179,6 +179,15 @@ namespace MediaBrowser.Controller.Entities.TV
}
[IgnoreDataMember]
+ public bool IsInSeasonFolder
+ {
+ get
+ {
+ return FindParent<Season>() != null;
+ }
+ }
+
+ [IgnoreDataMember]
public string SeriesName
{
get
@@ -275,7 +284,7 @@ namespace MediaBrowser.Controller.Entities.TV
return new[] { Path };
}
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.Series);
}
@@ -301,51 +310,9 @@ namespace MediaBrowser.Controller.Entities.TV
{
var hasChanges = base.BeforeMetadataRefresh();
- var locationType = LocationType;
- if (locationType == LocationType.FileSystem || locationType == LocationType.Offline)
- {
- if (!IndexNumber.HasValue && !string.IsNullOrEmpty(Path))
- {
- IndexNumber = LibraryManager.GetEpisodeNumberFromFile(Path, true);
-
- // If a change was made record it
- if (IndexNumber.HasValue)
- {
- hasChanges = true;
- }
- }
-
- if (!IndexNumberEnd.HasValue && !string.IsNullOrEmpty(Path))
- {
- IndexNumberEnd = LibraryManager.GetEndingEpisodeNumberFromFile(Path);
-
- // If a change was made record it
- if (IndexNumberEnd.HasValue)
- {
- hasChanges = true;
- }
- }
- }
-
- if (!ParentIndexNumber.HasValue)
+ if (LibraryManager.FillMissingEpisodeNumbersFromPath(this))
{
- var season = Season;
-
- if (season != null)
- {
- ParentIndexNumber = season.IndexNumber;
- }
-
- if (!ParentIndexNumber.HasValue && !string.IsNullOrEmpty(Path))
- {
- ParentIndexNumber = LibraryManager.GetSeasonNumberFromEpisodeFile(Path);
- }
-
- // If a change was made record it
- if (ParentIndexNumber.HasValue)
- {
- hasChanges = true;
- }
+ hasChanges = true;
}
return hasChanges;
diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs
index 2df90244c..54db12b6f 100644
--- a/MediaBrowser.Controller/Entities/TV/Season.cs
+++ b/MediaBrowser.Controller/Entities/TV/Season.cs
@@ -1,9 +1,9 @@
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Localization;
+using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
+using MediaBrowser.Model.Users;
+using MoreLinq;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
@@ -155,24 +155,6 @@ namespace MediaBrowser.Controller.Entities.TV
return IndexNumber != null ? IndexNumber.Value.ToString("0000") : Name;
}
- private IEnumerable<Episode> GetEpisodes()
- {
- var series = Series;
-
- if (series != null && series.ContainsEpisodesWithoutSeasonFolders)
- {
- var seasonNumber = IndexNumber;
-
- if (seasonNumber.HasValue)
- {
- return series.RecursiveChildren.OfType<Episode>()
- .Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == seasonNumber.Value);
- }
- }
-
- return Children.OfType<Episode>();
- }
-
[IgnoreDataMember]
public bool IsMissingSeason
{
@@ -220,16 +202,32 @@ namespace MediaBrowser.Controller.Entities.TV
var episodes = GetRecursiveChildren(user)
.OfType<Episode>();
- if (IndexNumber.HasValue)
+ var series = Series;
+
+ if (IndexNumber.HasValue && series != null)
{
- var series = Series;
+ return series.GetEpisodes(user, IndexNumber.Value, includeMissingEpisodes, includeVirtualUnairedEpisodes, episodes);
+ }
- if (series != null)
+ if (series != null && series.ContainsEpisodesWithoutSeasonFolders)
+ {
+ var seasonNumber = IndexNumber;
+ var list = episodes.ToList();
+
+ if (seasonNumber.HasValue)
{
- return series.GetEpisodes(user, IndexNumber.Value, includeMissingEpisodes, includeVirtualUnairedEpisodes, episodes);
+ list.AddRange(series.GetRecursiveChildren(user).OfType<Episode>()
+ .Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == seasonNumber.Value));
+ }
+ else
+ {
+ list.AddRange(series.GetRecursiveChildren(user).OfType<Episode>()
+ .Where(i => !i.ParentIndexNumber.HasValue));
}
- }
+ episodes = list.DistinctBy(i => i.Id);
+ }
+
if (!includeMissingEpisodes)
{
episodes = episodes.Where(i => !i.IsMissingEpisode);
@@ -244,12 +242,39 @@ namespace MediaBrowser.Controller.Entities.TV
.Cast<Episode>();
}
+ private IEnumerable<Episode> GetEpisodes()
+ {
+ var episodes = RecursiveChildren.OfType<Episode>();
+ var series = Series;
+
+ if (series != null && series.ContainsEpisodesWithoutSeasonFolders)
+ {
+ var seasonNumber = IndexNumber;
+ var list = episodes.ToList();
+
+ if (seasonNumber.HasValue)
+ {
+ list.AddRange(series.RecursiveChildren.OfType<Episode>()
+ .Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == seasonNumber.Value));
+ }
+ else
+ {
+ list.AddRange(series.RecursiveChildren.OfType<Episode>()
+ .Where(i => !i.ParentIndexNumber.HasValue));
+ }
+
+ episodes = list.DistinctBy(i => i.Id);
+ }
+
+ return episodes;
+ }
+
public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
{
return GetEpisodes(user);
}
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
// Don't block. Let either the entire series rating or episode rating determine it
return false;
diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs
index 4c0d1fdfb..55cfffeb2 100644
--- a/MediaBrowser.Controller/Entities/TV/Series.cs
+++ b/MediaBrowser.Controller/Entities/TV/Series.cs
@@ -3,6 +3,7 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
+using MediaBrowser.Model.Users;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -87,7 +88,17 @@ namespace MediaBrowser.Controller.Entities.TV
/// Gets or sets the date last episode added.
/// </summary>
/// <value>The date last episode added.</value>
- public DateTime DateLastEpisodeAdded { get; set; }
+ [IgnoreDataMember]
+ public DateTime DateLastEpisodeAdded
+ {
+ get
+ {
+ return RecursiveChildren.OfType<Episode>()
+ .Select(i => i.DateCreated)
+ .OrderByDescending(i => i)
+ .FirstOrDefault();
+ }
+ }
/// <summary>
/// Series aren't included directly in indices - Their Episodes will roll up to them
@@ -246,7 +257,7 @@ namespace MediaBrowser.Controller.Entities.TV
});
}
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.Series);
}
diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs
index bb165d790..7a1eef8db 100644
--- a/MediaBrowser.Controller/Entities/Trailer.cs
+++ b/MediaBrowser.Controller/Entities/Trailer.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.Serialization;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities
{
@@ -98,7 +99,7 @@ namespace MediaBrowser.Controller.Entities
return base.GetUserDataKey();
}
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.Trailer);
}
diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs
index 3dfc8cc7d..626afcfdf 100644
--- a/MediaBrowser.Controller/Entities/User.cs
+++ b/MediaBrowser.Controller/Entities/User.cs
@@ -1,5 +1,4 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Connect;
@@ -107,37 +106,27 @@ namespace MediaBrowser.Controller.Entities
/// <value>The last activity date.</value>
public DateTime? LastActivityDate { get; set; }
- /// <summary>
- /// The _configuration
- /// </summary>
- private UserConfiguration _configuration;
- /// <summary>
- /// The _configuration initialized
- /// </summary>
- private bool _configurationInitialized;
- /// <summary>
- /// The _configuration sync lock
- /// </summary>
- private object _configurationSyncLock = new object();
- /// <summary>
- /// Gets the user's configuration
- /// </summary>
- /// <value>The configuration.</value>
+ private UserConfiguration _config;
+ private readonly object _configSyncLock = new object();
[IgnoreDataMember]
public UserConfiguration Configuration
{
get
{
- // Lazy load
- LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationInitialized, ref _configurationSyncLock, () => (UserConfiguration)ConfigurationHelper.GetXmlConfiguration(typeof(UserConfiguration), ConfigurationFilePath, XmlSerializer));
- return _configuration;
- }
- private set
- {
- _configuration = value;
+ if (_config == null)
+ {
+ lock (_configSyncLock)
+ {
+ if (_config == null)
+ {
+ _config = UserManager.GetUserConfiguration(this);
+ }
+ }
+ }
- _configurationInitialized = value != null;
+ return _config;
}
+ set { _config = value; }
}
private UserPolicy _policy;
@@ -256,35 +245,6 @@ namespace MediaBrowser.Controller.Entities
return System.IO.Path.Combine(parentPath, Id.ToString("N"));
}
- /// <summary>
- /// Gets the path to the user's configuration file
- /// </summary>
- /// <value>The configuration file path.</value>
- [IgnoreDataMember]
- public string ConfigurationFilePath
- {
- get
- {
- return System.IO.Path.Combine(ConfigurationDirectoryPath, "config.xml");
- }
- }
-
- /// <summary>
- /// Updates the configuration.
- /// </summary>
- /// <param name="config">The config.</param>
- /// <exception cref="System.ArgumentNullException">config</exception>
- public void UpdateConfiguration(UserConfiguration config)
- {
- if (config == null)
- {
- throw new ArgumentNullException("config");
- }
-
- Configuration = config;
- UserManager.UpdateConfiguration(this, Configuration);
- }
-
public bool IsParentalScheduleAllowed()
{
return IsParentalScheduleAllowed(DateTime.UtcNow);
@@ -292,7 +252,7 @@ namespace MediaBrowser.Controller.Entities
public bool IsParentalScheduleAllowed(DateTime date)
{
- var schedules = Configuration.AccessSchedules;
+ var schedules = Policy.AccessSchedules;
if (schedules.Length == 0)
{
diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs
index 926ffa19c..0364ff678 100644
--- a/MediaBrowser.Controller/Entities/UserView.cs
+++ b/MediaBrowser.Controller/Entities/UserView.cs
@@ -63,7 +63,8 @@ namespace MediaBrowser.Controller.Entities
{
CollectionType.Books,
CollectionType.HomeVideos,
- CollectionType.Photos
+ CollectionType.Photos,
+ string.Empty
};
var collectionFolder = folder as ICollectionFolder;
diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs
index 0c6125dbe..3abaf095c 100644
--- a/MediaBrowser.Controller/Entities/Video.cs
+++ b/MediaBrowser.Controller/Entities/Video.cs
@@ -91,6 +91,21 @@ namespace MediaBrowser.Controller.Entities
get { return LocalAlternateVersions.Count > 0; }
}
+ [IgnoreDataMember]
+ public bool IsArchive
+ {
+ get
+ {
+ if (string.IsNullOrWhiteSpace(Path))
+ {
+ return false;
+ }
+ var ext = System.IO.Path.GetExtension(Path) ?? string.Empty;
+
+ return new[] { ".zip", ".rar", ".7z" }.Contains(ext, StringComparer.OrdinalIgnoreCase);
+ }
+ }
+
public IEnumerable<Guid> GetAdditionalPartIds()
{
return AdditionalParts.Select(i => LibraryManager.GetNewItemId(i, typeof(Video)));
@@ -246,7 +261,7 @@ namespace MediaBrowser.Controller.Entities
{
return System.IO.Path.GetFileName(Path);
}
-
+
return System.IO.Path.GetFileNameWithoutExtension(Path);
}
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index 33dea4dca..8573f32e0 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Controller.Sorting;
@@ -22,11 +23,9 @@ namespace MediaBrowser.Controller.Library
/// </summary>
/// <param name="fileInfo">The file information.</param>
/// <param name="parent">The parent.</param>
- /// <param name="collectionType">Type of the collection.</param>
/// <returns>BaseItem.</returns>
BaseItem ResolvePath(FileSystemInfo fileInfo,
- Folder parent = null,
- string collectionType = null);
+ Folder parent = null);
/// <summary>
/// Resolves a set of files into a list of BaseItem
@@ -258,9 +257,16 @@ namespace MediaBrowser.Controller.Library
/// </summary>
/// <param name="item">The item.</param>
/// <returns>System.String.</returns>
- string FindCollectionType(BaseItem item);
+ string GetContentType(BaseItem item);
/// <summary>
+ /// Gets the type of the inherited content.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <returns>System.String.</returns>
+ string GetInheritedContentType(BaseItem item);
+
+ /// <summary>
/// Normalizes the root path list.
/// </summary>
/// <param name="paths">The paths.</param>
@@ -340,26 +346,11 @@ namespace MediaBrowser.Controller.Library
int? GetSeasonNumberFromPath(string path);
/// <summary>
- /// Gets the season number from episode file.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>System.Nullable&lt;System.Int32&gt;.</returns>
- int? GetSeasonNumberFromEpisodeFile(string path);
-
- /// <summary>
- /// Gets the ending episode number from file.
+ /// Fills the missing episode numbers from path.
/// </summary>
- /// <param name="path">The path.</param>
- /// <returns>System.Nullable&lt;System.Int32&gt;.</returns>
- int? GetEndingEpisodeNumberFromFile(string path);
-
- /// <summary>
- /// Gets the episode number from file.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="considerSeasonless">if set to <c>true</c> [consider seasonless].</param>
- /// <returns>System.Nullable&lt;System.Int32&gt;.</returns>
- int? GetEpisodeNumberFromFile(string path, bool considerSeasonless);
+ /// <param name="episode">The episode.</param>
+ /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
+ bool FillMissingEpisodeNumbersFromPath(Episode episode);
/// <summary>
/// Parses the name.
diff --git a/MediaBrowser.Controller/Library/IUserDataManager.cs b/MediaBrowser.Controller/Library/IUserDataManager.cs
index 226f77525..06e7d1763 100644
--- a/MediaBrowser.Controller/Library/IUserDataManager.cs
+++ b/MediaBrowser.Controller/Library/IUserDataManager.cs
@@ -61,5 +61,9 @@ namespace MediaBrowser.Controller.Library
/// <returns></returns>
Task SaveAllUserData(Guid userId, IEnumerable<UserItemData> userData, CancellationToken cancellationToken);
+ /// <summary>
+ /// Updates playstate for an item and returns true or false indicating if it was played to completion
+ /// </summary>
+ bool UpdatePlayState(BaseItem item, UserItemData data, long positionTicks);
}
}
diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs
index 9dc16ba4d..f5846973e 100644
--- a/MediaBrowser.Controller/Library/IUserManager.cs
+++ b/MediaBrowser.Controller/Library/IUserManager.cs
@@ -36,13 +36,6 @@ namespace MediaBrowser.Controller.Library
event EventHandler<GenericEventArgs<User>> UserPasswordChanged;
/// <summary>
- /// Updates the configuration.
- /// </summary>
- /// <param name="user">The user.</param>
- /// <param name="newConfiguration">The new configuration.</param>
- void UpdateConfiguration(User user, UserConfiguration newConfiguration);
-
- /// <summary>
/// Gets a User by Id
/// </summary>
/// <param name="id">The id.</param>
@@ -173,10 +166,32 @@ namespace MediaBrowser.Controller.Library
UserPolicy GetUserPolicy(User user);
/// <summary>
+ /// Gets the user configuration.
+ /// </summary>
+ /// <param name="user">The user.</param>
+ /// <returns>UserConfiguration.</returns>
+ UserConfiguration GetUserConfiguration(User user);
+
+ /// <summary>
+ /// Updates the configuration.
+ /// </summary>
+ /// <param name="userId">The user identifier.</param>
+ /// <param name="newConfiguration">The new configuration.</param>
+ /// <returns>Task.</returns>
+ Task UpdateConfiguration(string userId, UserConfiguration newConfiguration);
+
+ /// <summary>
/// Updates the user policy.
/// </summary>
/// <param name="userId">The user identifier.</param>
/// <param name="userPolicy">The user policy.</param>
Task UpdateUserPolicy(string userId, UserPolicy userPolicy);
+
+ /// <summary>
+ /// Makes the valid username.
+ /// </summary>
+ /// <param name="username">The username.</param>
+ /// <returns>System.String.</returns>
+ string MakeValidUsername(string username);
}
}
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs
index 9f8d67a48..b95d67ad8 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs
@@ -2,6 +2,7 @@
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using System.Linq;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.LiveTv
{
@@ -78,7 +79,7 @@ namespace MediaBrowser.Controller.LiveTv
}
}
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram);
}
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
index df118b25f..de72accff 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
@@ -6,6 +6,7 @@ using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.MediaInfo;
using System.Collections.Generic;
using System.Linq;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.LiveTv
{
@@ -33,7 +34,7 @@ namespace MediaBrowser.Controller.LiveTv
}
}
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.LiveTvChannel);
}
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
index 266eaabee..29b23a551 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
@@ -6,6 +6,7 @@ using System;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.LiveTv
{
@@ -199,7 +200,7 @@ namespace MediaBrowser.Controller.LiveTv
return ItemRepository.SaveItem(this, cancellationToken);
}
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram);
}
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs
index 66de81213..6fc985643 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs
@@ -2,6 +2,7 @@
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using System.Linq;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.LiveTv
{
@@ -78,7 +79,7 @@ namespace MediaBrowser.Controller.LiveTv
}
}
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram);
}
diff --git a/MediaBrowser.Controller/LiveTv/RecordingGroup.cs b/MediaBrowser.Controller/LiveTv/RecordingGroup.cs
index 7bd810b8d..d7250d9d2 100644
--- a/MediaBrowser.Controller/LiveTv/RecordingGroup.cs
+++ b/MediaBrowser.Controller/LiveTv/RecordingGroup.cs
@@ -1,11 +1,12 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.LiveTv
{
public class RecordingGroup : Folder
{
- protected override bool GetBlockUnratedValue(UserConfiguration config)
+ protected override bool GetBlockUnratedValue(UserPolicy config)
{
// Don't block.
return false;
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index c198a58d4..3ed87ced8 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -198,18 +198,16 @@
<Compile Include="LiveTv\SeriesTimerInfo.cs" />
<Compile Include="LiveTv\TimerInfo.cs" />
<Compile Include="Localization\ILocalizationManager.cs" />
- <Compile Include="MediaEncoding\EncodingOptions.cs" />
<Compile Include="MediaEncoding\ChapterImageRefreshOptions.cs" />
- <Compile Include="MediaEncoding\EncodingResult.cs" />
<Compile Include="MediaEncoding\IEncodingManager.cs" />
<Compile Include="MediaEncoding\ImageEncodingOptions.cs" />
<Compile Include="MediaEncoding\IMediaEncoder.cs" />
<Compile Include="MediaEncoding\InternalMediaInfoResult.cs" />
<Compile Include="MediaEncoding\ISubtitleEncoder.cs" />
<Compile Include="MediaEncoding\MediaStreamSelector.cs" />
- <Compile Include="MediaEncoding\VideoEncodingOptions.cs" />
<Compile Include="Net\AuthenticatedAttribute.cs" />
<Compile Include="Net\AuthorizationInfo.cs" />
+ <Compile Include="Net\BasePeriodicWebSocketListener.cs" />
<Compile Include="Net\IAuthorizationContext.cs" />
<Compile Include="Net\IAuthService.cs" />
<Compile Include="Net\IHasAuthorization.cs" />
@@ -221,10 +219,15 @@
<Compile Include="Net\IServerManager.cs" />
<Compile Include="Net\IServiceRequest.cs" />
<Compile Include="Net\ISessionContext.cs" />
+ <Compile Include="Net\IWebSocket.cs" />
+ <Compile Include="Net\IWebSocketConnection.cs" />
+ <Compile Include="Net\IWebSocketListener.cs" />
<Compile Include="Net\LoggedAttribute.cs" />
<Compile Include="Net\SecurityException.cs" />
<Compile Include="Net\ServiceStackServiceRequest.cs" />
<Compile Include="Net\StaticResultOptions.cs" />
+ <Compile Include="Net\WebSocketConnectEventArgs.cs" />
+ <Compile Include="Net\WebSocketMessageInfo.cs" />
<Compile Include="News\INewsService.cs" />
<Compile Include="Notifications\INotificationManager.cs" />
<Compile Include="Notifications\INotificationService.cs" />
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingOptions.cs
deleted file mode 100644
index 26182ebc4..000000000
--- a/MediaBrowser.Controller/MediaEncoding/EncodingOptions.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Model.Dlna;
-
-namespace MediaBrowser.Controller.MediaEncoding
-{
- public class EncodingOptions
- {
- /// <summary>
- /// Gets or sets the item identifier.
- /// </summary>
- /// <value>The item identifier.</value>
- public string ItemId { get; set; }
-
- /// <summary>
- /// Gets or sets the media source identifier.
- /// </summary>
- /// <value>The media source identifier.</value>
- public string MediaSourceId { get; set; }
-
- /// <summary>
- /// Gets or sets the device profile.
- /// </summary>
- /// <value>The device profile.</value>
- public DeviceProfile DeviceProfile { get; set; }
-
- /// <summary>
- /// Gets or sets the output path.
- /// </summary>
- /// <value>The output path.</value>
- public string OutputPath { get; set; }
-
- /// <summary>
- /// Gets or sets the container.
- /// </summary>
- /// <value>The container.</value>
- public string Container { get; set; }
-
- /// <summary>
- /// Gets or sets the audio codec.
- /// </summary>
- /// <value>The audio codec.</value>
- public string AudioCodec { get; set; }
-
- /// <summary>
- /// Gets or sets the start time ticks.
- /// </summary>
- /// <value>The start time ticks.</value>
- public long? StartTimeTicks { get; set; }
-
- /// <summary>
- /// Gets or sets the maximum channels.
- /// </summary>
- /// <value>The maximum channels.</value>
- public int? MaxAudioChannels { get; set; }
-
- /// <summary>
- /// Gets or sets the channels.
- /// </summary>
- /// <value>The channels.</value>
- public int? AudioChannels { get; set; }
-
- /// <summary>
- /// Gets or sets the sample rate.
- /// </summary>
- /// <value>The sample rate.</value>
- public int? AudioSampleRate { get; set; }
-
- /// <summary>
- /// Gets or sets the bit rate.
- /// </summary>
- /// <value>The bit rate.</value>
- public int? AudioBitRate { get; set; }
-
- /// <summary>
- /// Gets or sets the maximum audio bit rate.
- /// </summary>
- /// <value>The maximum audio bit rate.</value>
- public int? MaxAudioBitRate { get; set; }
- }
-}
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingResult.cs b/MediaBrowser.Controller/MediaEncoding/EncodingResult.cs
deleted file mode 100644
index 75ee90e42..000000000
--- a/MediaBrowser.Controller/MediaEncoding/EncodingResult.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.MediaEncoding
-{
- public class EncodingResult
- {
- public string OutputPath { get; set; }
- }
-}
diff --git a/MediaBrowser.Controller/MediaEncoding/MediaStreamSelector.cs b/MediaBrowser.Controller/MediaEncoding/MediaStreamSelector.cs
index 58a68c257..4a807df7a 100644
--- a/MediaBrowser.Controller/MediaEncoding/MediaStreamSelector.cs
+++ b/MediaBrowser.Controller/MediaEncoding/MediaStreamSelector.cs
@@ -34,15 +34,13 @@ namespace MediaBrowser.Controller.MediaEncoding
}
public static int? GetDefaultSubtitleStreamIndex(List<MediaStream> streams,
- IEnumerable<string> preferredLanguages,
+ List<string> preferredLanguages,
SubtitlePlaybackMode mode,
string audioTrackLanguage)
{
- var languages = preferredLanguages.ToList();
- streams = GetSortedStreams(streams, MediaStreamType.Subtitle, languages).ToList();
+ streams = GetSortedStreams(streams, MediaStreamType.Subtitle, preferredLanguages).ToList();
var full = streams.Where(s => !s.IsForced);
- var forced = streams.Where(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase));
MediaStream stream = null;
@@ -54,9 +52,9 @@ namespace MediaBrowser.Controller.MediaEncoding
if (mode == SubtitlePlaybackMode.Default)
{
// if the audio language is not understood by the user, load their preferred subs, if there are any
- if (!ContainsOrdinal(languages, audioTrackLanguage))
+ if (!ContainsOrdinal(preferredLanguages, audioTrackLanguage))
{
- stream = full.FirstOrDefault(s => ContainsOrdinal(languages, s.Language));
+ stream = full.FirstOrDefault(s => ContainsOrdinal(preferredLanguages, s.Language));
}
}
else if (mode == SubtitlePlaybackMode.Always)
@@ -66,7 +64,7 @@ namespace MediaBrowser.Controller.MediaEncoding
}
// load forced subs if we have found no suitable full subtitles
- stream = stream ?? forced.FirstOrDefault();
+ stream = stream ?? streams.FirstOrDefault(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase));
if (stream != null)
{
diff --git a/MediaBrowser.Controller/MediaEncoding/VideoEncodingOptions.cs b/MediaBrowser.Controller/MediaEncoding/VideoEncodingOptions.cs
deleted file mode 100644
index 773f0ea46..000000000
--- a/MediaBrowser.Controller/MediaEncoding/VideoEncodingOptions.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-
-namespace MediaBrowser.Controller.MediaEncoding
-{
- public class VideoEncodingOptions : EncodingOptions
- {
- public string VideoCodec { get; set; }
-
- public string VideoProfile { get; set; }
-
- public double? VideoLevel { get; set; }
-
- public int? VideoStreamIndex { get; set; }
-
- public int? AudioStreamIndex { get; set; }
-
- public int? SubtitleStreamIndex { get; set; }
-
- public int? MaxWidth { get; set; }
-
- public int? MaxHeight { get; set; }
-
- public int? Height { get; set; }
-
- public int? Width { get; set; }
- }
-}
diff --git a/MediaBrowser.Common/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs
index a2af3707b..f1e371c1a 100644
--- a/MediaBrowser.Common/Net/BasePeriodicWebSocketListener.cs
+++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Model.Logging;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net;
using System;
using System.Collections.Generic;
@@ -7,7 +8,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-namespace MediaBrowser.Common.Net
+namespace MediaBrowser.Controller.Net
{
/// <summary>
/// Starts sending data over a web socket periodically when a message is received, and then stops when a corresponding stop message is received
diff --git a/MediaBrowser.Common/Net/IWebSocket.cs b/MediaBrowser.Controller/Net/IWebSocket.cs
index b31a95319..b88f2c389 100644
--- a/MediaBrowser.Common/Net/IWebSocket.cs
+++ b/MediaBrowser.Controller/Net/IWebSocket.cs
@@ -3,7 +3,7 @@ using System;
using System.Threading;
using System.Threading.Tasks;
-namespace MediaBrowser.Common.Net
+namespace MediaBrowser.Controller.Net
{
/// <summary>
/// Interface IWebSocket
diff --git a/MediaBrowser.Common/Net/IWebSocketConnection.cs b/MediaBrowser.Controller/Net/IWebSocketConnection.cs
index b7715e20b..37fd6708d 100644
--- a/MediaBrowser.Common/Net/IWebSocketConnection.cs
+++ b/MediaBrowser.Controller/Net/IWebSocketConnection.cs
@@ -3,7 +3,7 @@ using System;
using System.Threading;
using System.Threading.Tasks;
-namespace MediaBrowser.Common.Net
+namespace MediaBrowser.Controller.Net
{
public interface IWebSocketConnection : IDisposable
{
diff --git a/MediaBrowser.Common/Net/IWebSocketListener.cs b/MediaBrowser.Controller/Net/IWebSocketListener.cs
index 4b6c4111d..2b4fc7676 100644
--- a/MediaBrowser.Common/Net/IWebSocketListener.cs
+++ b/MediaBrowser.Controller/Net/IWebSocketListener.cs
@@ -1,6 +1,7 @@
-using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
+using System.Threading.Tasks;
-namespace MediaBrowser.Common.Net
+namespace MediaBrowser.Controller.Net
{
/// <summary>
///This is an interface for listening to messages coming through a web socket connection
diff --git a/MediaBrowser.Common/Net/WebSocketConnectEventArgs.cs b/MediaBrowser.Controller/Net/WebSocketConnectEventArgs.cs
index ce22c9520..394fcd92f 100644
--- a/MediaBrowser.Common/Net/WebSocketConnectEventArgs.cs
+++ b/MediaBrowser.Controller/Net/WebSocketConnectEventArgs.cs
@@ -1,6 +1,6 @@
using System;
-namespace MediaBrowser.Common.Net
+namespace MediaBrowser.Controller.Net
{
/// <summary>
/// Class WebSocketConnectEventArgs
diff --git a/MediaBrowser.Common/Net/WebSocketMessageInfo.cs b/MediaBrowser.Controller/Net/WebSocketMessageInfo.cs
index c1f935a7b..332f16420 100644
--- a/MediaBrowser.Common/Net/WebSocketMessageInfo.cs
+++ b/MediaBrowser.Controller/Net/WebSocketMessageInfo.cs
@@ -1,6 +1,6 @@
using MediaBrowser.Model.Net;
-namespace MediaBrowser.Common.Net
+namespace MediaBrowser.Controller.Net
{
/// <summary>
/// Class WebSocketMessageInfo
diff --git a/MediaBrowser.Controller/Providers/DirectoryService.cs b/MediaBrowser.Controller/Providers/DirectoryService.cs
index 74a9c6606..06ea7be02 100644
--- a/MediaBrowser.Controller/Providers/DirectoryService.cs
+++ b/MediaBrowser.Controller/Providers/DirectoryService.cs
@@ -46,6 +46,11 @@ namespace MediaBrowser.Controller.Providers
private Dictionary<string, FileSystemInfo> GetFileSystemDictionary(string path, bool clearCache)
{
+ if (string.IsNullOrWhiteSpace(path))
+ {
+ throw new ArgumentNullException("path");
+ }
+
Dictionary<string, FileSystemInfo> entries;
if (clearCache)
diff --git a/MediaBrowser.Controller/Sync/ISyncManager.cs b/MediaBrowser.Controller/Sync/ISyncManager.cs
index 47339f677..6cad19736 100644
--- a/MediaBrowser.Controller/Sync/ISyncManager.cs
+++ b/MediaBrowser.Controller/Sync/ISyncManager.cs
@@ -4,6 +4,7 @@ using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Sync;
using System.Collections.Generic;
using System.Threading.Tasks;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Sync
{
@@ -80,5 +81,26 @@ namespace MediaBrowser.Controller.Sync
/// <param name="id">The identifier.</param>
/// <returns>SyncJobItem.</returns>
SyncJobItem GetJobItem(string id);
+
+ /// <summary>
+ /// Reports the offline action.
+ /// </summary>
+ /// <param name="action">The action.</param>
+ /// <returns>Task.</returns>
+ Task ReportOfflineAction(UserAction action);
+
+ /// <summary>
+ /// Gets the ready synchronize items.
+ /// </summary>
+ /// <param name="targetId">The target identifier.</param>
+ /// <returns>List&lt;SyncedItem&gt;.</returns>
+ List<SyncedItem> GetReadySyncItems(string targetId);
+
+ /// <summary>
+ /// Synchronizes the data.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <returns>Task&lt;SyncDataResponse&gt;.</returns>
+ Task<SyncDataResponse> SyncData(SyncDataRequest request);
}
}
diff --git a/MediaBrowser.Controller/Sync/ISyncProvider.cs b/MediaBrowser.Controller/Sync/ISyncProvider.cs
index 89f61b80e..5ebdee207 100644
--- a/MediaBrowser.Controller/Sync/ISyncProvider.cs
+++ b/MediaBrowser.Controller/Sync/ISyncProvider.cs
@@ -25,4 +25,9 @@ namespace MediaBrowser.Controller.Sync
/// <returns>DeviceProfile.</returns>
DeviceProfile GetDeviceProfile(SyncTarget target);
}
+
+ public interface IHasUniqueTargetIds
+ {
+
+ }
}
diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs
index bdb1c4cbf..d1941c856 100644
--- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs
+++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs
@@ -18,6 +18,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Xml;
+using MediaBrowser.Model.Net;
namespace MediaBrowser.Dlna.Didl
{
diff --git a/MediaBrowser.LocalMetadata/BaseXmlProvider.cs b/MediaBrowser.LocalMetadata/BaseXmlProvider.cs
index 6f8047e4c..74e3b61ca 100644
--- a/MediaBrowser.LocalMetadata/BaseXmlProvider.cs
+++ b/MediaBrowser.LocalMetadata/BaseXmlProvider.cs
@@ -28,8 +28,6 @@ namespace MediaBrowser.LocalMetadata
var path = file.FullName;
- //await XmlProviderUtils.XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
-
try
{
result.Item = new T();
@@ -45,10 +43,6 @@ namespace MediaBrowser.LocalMetadata
{
result.HasMetadata = false;
}
- finally
- {
- //XmlProviderUtils.XmlParsingResourcePool.Release();
- }
return result;
}
@@ -90,7 +84,7 @@ namespace MediaBrowser.LocalMetadata
{
get
{
- return "Media Browser Legacy Xml";
+ return "Media Browser Xml";
}
}
diff --git a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
index 044d29a1b..7f83aa61d 100644
--- a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
+++ b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
@@ -1,7 +1,6 @@
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
@@ -76,11 +75,14 @@ namespace MediaBrowser.LocalMetadata.Images
{
return directoryService.GetFileSystemEntries(path)
.Where(i => BaseItem.SupportedImageExtensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase) ||
- (i.Attributes & FileAttributes.Directory) == FileAttributes.Directory);
+ (i.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
+
+ .OrderBy(i => BaseItem.SupportedImageExtensionsList.IndexOf(i.Extension ?? string.Empty));
}
return directoryService.GetFiles(path)
- .Where(i => BaseItem.SupportedImageExtensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase));
+ .Where(i => BaseItem.SupportedImageExtensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase))
+ .OrderBy(i => BaseItem.SupportedImageExtensionsList.IndexOf(i.Extension ?? string.Empty));
}
public List<LocalImageInfo> GetImages(IHasImages item, IDirectoryService directoryService)
@@ -109,6 +111,7 @@ namespace MediaBrowser.LocalMetadata.Images
return !string.IsNullOrEmpty(ext) &&
BaseItem.SupportedImageExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase);
})
+ .OrderBy(i => BaseItem.SupportedImageExtensionsList.IndexOf(i.Extension ?? string.Empty))
.ToList();
var list = new List<LocalImageInfo>();
@@ -166,8 +169,8 @@ namespace MediaBrowser.LocalMetadata.Images
var names = new List<string>
{
"folder",
- "cover",
"poster",
+ "cover",
"default"
};
@@ -402,13 +405,7 @@ namespace MediaBrowser.LocalMetadata.Images
private FileSystemInfo GetImage(IEnumerable<FileSystemInfo> files, string name)
{
- var candidates = files
- .Where(i => string.Equals(name, _fileSystem.GetFileNameWithoutExtension(i), StringComparison.OrdinalIgnoreCase))
- .ToList();
-
- return BaseItem.SupportedImageExtensions
- .Select(i => candidates.FirstOrDefault(c => string.Equals(c.Extension, i, StringComparison.OrdinalIgnoreCase)))
- .FirstOrDefault(i => i != null);
+ return files.FirstOrDefault(i => ((i.Attributes & FileAttributes.Directory) != FileAttributes.Directory) && string.Equals(name, _fileSystem.GetFileNameWithoutExtension(i), StringComparison.OrdinalIgnoreCase));
}
}
}
diff --git a/MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs
index fa3d7d87d..67fa12b55 100644
--- a/MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs
@@ -49,7 +49,7 @@ namespace MediaBrowser.LocalMetadata.Savers
!(item is GameSystem) &&
!(item is Playlist))
{
- return updateType >= ItemUpdateType.MetadataDownload;
+ return updateType >= ItemUpdateType.MetadataEdit;
}
}
diff --git a/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs b/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs
index 3e11c994b..4388ec964 100644
--- a/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs
+++ b/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs
@@ -649,7 +649,7 @@ namespace MediaBrowser.LocalMetadata.Savers
var hasShares = item as IHasShares;
if (hasShares != null)
{
-
+ AddShares(hasShares, builder);
}
}
diff --git a/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs b/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs
new file mode 100644
index 000000000..17470d206
--- /dev/null
+++ b/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs
@@ -0,0 +1,45 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Model.Configuration;
+using System.Collections.Generic;
+using System.IO;
+
+namespace MediaBrowser.MediaEncoding.Configuration
+{
+ public class EncodingConfigurationFactory : IConfigurationFactory
+ {
+ public IEnumerable<ConfigurationStore> GetConfigurations()
+ {
+ return new[]
+ {
+ new EncodingConfigurationStore()
+ };
+ }
+ }
+
+ public class EncodingConfigurationStore : ConfigurationStore, IValidatingConfiguration
+ {
+ public EncodingConfigurationStore()
+ {
+ ConfigurationType = typeof(EncodingOptions);
+ Key = "encoding";
+ }
+
+ public void Validate(object oldConfig, object newConfig)
+ {
+ var oldEncodingConfig = (EncodingOptions)oldConfig;
+ var newEncodingConfig = (EncodingOptions)newConfig;
+
+ var newPath = newEncodingConfig.TranscodingTempPath;
+
+ if (!string.IsNullOrWhiteSpace(newPath)
+ && !string.Equals(oldEncodingConfig.TranscodingTempPath ?? string.Empty, newPath))
+ {
+ // Validate
+ if (!Directory.Exists(newPath))
+ {
+ throw new DirectoryNotFoundException(string.Format("{0} does not exist.", newPath));
+ }
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
index 6f59b7bec..5c472ebc8 100644
--- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
+++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
@@ -56,6 +56,7 @@
<Link>Properties\SharedVersion.cs</Link>
</Compile>
<Compile Include="BdInfo\BdInfoExaminer.cs" />
+ <Compile Include="Configuration\EncodingConfigurationFactory.cs" />
<Compile Include="Encoder\EncodingUtils.cs" />
<Compile Include="Encoder\MediaEncoder.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
index 7c512840b..67c9123f5 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
@@ -613,6 +613,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles
{
}
+ catch (DirectoryNotFoundException)
+ {
+
+ }
catch (IOException ex)
{
_logger.ErrorException("Error deleting extracted subtitle {0}", ex, outputPath);
diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
index 2629dac8b..e4cfab571 100644
--- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
+++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
@@ -10,8 +10,8 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MediaBrowser.Model</RootNamespace>
<AssemblyName>MediaBrowser.Model</AssemblyName>
- <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
- <TargetFrameworkProfile>Profile344</TargetFrameworkProfile>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <TargetFrameworkProfile>Profile259</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
@@ -188,6 +188,9 @@
<Compile Include="..\MediaBrowser.Model\Configuration\DynamicDayOfWeek.cs">
<Link>Configuration\DynamicDayOfWeek.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Configuration\EncodingOptions.cs">
+ <Link>Configuration\EncodingOptions.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Configuration\EncodingQuality.cs">
<Link>Configuration\EncodingQuality.cs</Link>
</Compile>
@@ -461,6 +464,12 @@
<Compile Include="..\MediaBrowser.Model\Dto\MediaSourceType.cs">
<Link>Dto\MediaSourceType.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Dto\MetadataEditorInfo.cs">
+ <Link>Dto\MetadataEditorInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Dto\NameValuePair.cs">
+ <Link>Dto\NameValuePair.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Dto\RatingType.cs">
<Link>Dto\RatingType.cs</Link>
</Compile>
@@ -470,9 +479,6 @@
<Compile Include="..\MediaBrowser.Model\Dto\RecommendationType.cs">
<Link>Dto\RecommendationType.cs</Link>
</Compile>
- <Compile Include="..\MediaBrowser.Model\Dto\StreamOptions.cs">
- <Link>Dto\StreamOptions.cs</Link>
- </Compile>
<Compile Include="..\MediaBrowser.Model\Dto\StudioDto.cs">
<Link>Dto\StudioDto.cs</Link>
</Compile>
@@ -788,6 +794,12 @@
<Compile Include="..\MediaBrowser.Model\Net\HttpException.cs">
<Link>Net\HttpException.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Net\HttpResponse.cs">
+ <Link>Net\HttpResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Net\MimeTypes.cs">
+ <Link>Net\MimeTypes.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Net\NetworkShare.cs">
<Link>Net\NetworkShare.cs</Link>
</Compile>
@@ -1028,12 +1040,36 @@
<Compile Include="..\MediaBrowser.Model\Session\UserDataChangeInfo.cs">
<Link>Session\UserDataChangeInfo.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Sync\DeviceFileInfo.cs">
+ <Link>Sync\DeviceFileInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Sync\ItemFIleInfo.cs">
+ <Link>Sync\ItemFIleInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Sync\ItemFileType.cs">
+ <Link>Sync\ItemFileType.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Sync\LocalItem.cs">
+ <Link>Sync\LocalItem.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Sync\SyncCategory.cs">
<Link>Sync\SyncCategory.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Sync\SyncDataRequest.cs">
+ <Link>Sync\SyncDataRequest.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Sync\SyncDataResponse.cs">
+ <Link>Sync\SyncDataResponse.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Sync\SyncDialogOptions.cs">
<Link>Sync\SyncDialogOptions.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Sync\SyncedItem.cs">
+ <Link>Sync\SyncedItem.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Sync\SyncHelper.cs">
+ <Link>Sync\SyncHelper.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Sync\SyncJob.cs">
<Link>Sync\SyncJob.cs</Link>
</Compile>
@@ -1136,6 +1172,12 @@
<Compile Include="..\MediaBrowser.Model\Users\PinRedeemResult.cs">
<Link>Users\PinRedeemResult.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Users\UserAction.cs">
+ <Link>Users\UserAction.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Users\UserActionType.cs">
+ <Link>Users\UserActionType.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Users\UserPolicy.cs">
<Link>Users\UserPolicy.cs</Link>
</Compile>
diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
index 4840777a5..3fc5201a7 100644
--- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
+++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
@@ -153,6 +153,9 @@
<Compile Include="..\MediaBrowser.Model\Configuration\DynamicDayOfWeek.cs">
<Link>Configuration\DynamicDayOfWeek.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Configuration\EncodingOptions.cs">
+ <Link>Configuration\EncodingOptions.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Configuration\EncodingQuality.cs">
<Link>Configuration\EncodingQuality.cs</Link>
</Compile>
@@ -426,6 +429,12 @@
<Compile Include="..\MediaBrowser.Model\Dto\MediaSourceType.cs">
<Link>Dto\MediaSourceType.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Dto\MetadataEditorInfo.cs">
+ <Link>Dto\MetadataEditorInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Dto\NameValuePair.cs">
+ <Link>Dto\NameValuePair.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Dto\RatingType.cs">
<Link>Dto\RatingType.cs</Link>
</Compile>
@@ -435,9 +444,6 @@
<Compile Include="..\MediaBrowser.Model\Dto\RecommendationType.cs">
<Link>Dto\RecommendationType.cs</Link>
</Compile>
- <Compile Include="..\MediaBrowser.Model\Dto\StreamOptions.cs">
- <Link>Dto\StreamOptions.cs</Link>
- </Compile>
<Compile Include="..\MediaBrowser.Model\Dto\StudioDto.cs">
<Link>Dto\StudioDto.cs</Link>
</Compile>
@@ -747,6 +753,12 @@
<Compile Include="..\MediaBrowser.Model\Net\HttpException.cs">
<Link>Net\HttpException.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Net\HttpResponse.cs">
+ <Link>Net\HttpResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Net\MimeTypes.cs">
+ <Link>Net\MimeTypes.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Net\NetworkShare.cs">
<Link>Net\NetworkShare.cs</Link>
</Compile>
@@ -987,12 +999,36 @@
<Compile Include="..\MediaBrowser.Model\Session\UserDataChangeInfo.cs">
<Link>Session\UserDataChangeInfo.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Sync\DeviceFileInfo.cs">
+ <Link>Sync\DeviceFileInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Sync\ItemFIleInfo.cs">
+ <Link>Sync\ItemFIleInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Sync\ItemFileType.cs">
+ <Link>Sync\ItemFileType.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Sync\LocalItem.cs">
+ <Link>Sync\LocalItem.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Sync\SyncCategory.cs">
<Link>Sync\SyncCategory.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Sync\SyncDataRequest.cs">
+ <Link>Sync\SyncDataRequest.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Sync\SyncDataResponse.cs">
+ <Link>Sync\SyncDataResponse.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Sync\SyncDialogOptions.cs">
<Link>Sync\SyncDialogOptions.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Sync\SyncedItem.cs">
+ <Link>Sync\SyncedItem.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Sync\SyncHelper.cs">
+ <Link>Sync\SyncHelper.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Sync\SyncJob.cs">
<Link>Sync\SyncJob.cs</Link>
</Compile>
@@ -1095,6 +1131,12 @@
<Compile Include="..\MediaBrowser.Model\Users\PinRedeemResult.cs">
<Link>Users\PinRedeemResult.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Users\UserAction.cs">
+ <Link>Users\UserAction.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Users\UserActionType.cs">
+ <Link>Users\UserActionType.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Users\UserPolicy.cs">
<Link>Users\UserPolicy.cs</Link>
</Compile>
diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs
index 9521f8538..9faa8fced 100644
--- a/MediaBrowser.Model/ApiClient/IApiClient.cs
+++ b/MediaBrowser.Model/ApiClient/IApiClient.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Events;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.MediaInfo;
+using MediaBrowser.Model.Net;
using MediaBrowser.Model.Notifications;
using MediaBrowser.Model.Playlists;
using MediaBrowser.Model.Plugins;
@@ -186,6 +187,30 @@ namespace MediaBrowser.Model.ApiClient
Task<Stream> GetImageStreamAsync(string url, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
+ /// Gets the stream.
+ /// </summary>
+ /// <param name="url">The URL.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task&lt;Stream&gt;.</returns>
+ Task<Stream> GetStream(string url, CancellationToken cancellationToken = default(CancellationToken));
+
+ /// <summary>
+ /// Gets the response.
+ /// </summary>
+ /// <param name="url">The URL.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task&lt;HttpResponse&gt;.</returns>
+ Task<HttpResponse> GetResponse(string url, CancellationToken cancellationToken = default(CancellationToken));
+
+ /// <summary>
+ /// Updates the user configuration.
+ /// </summary>
+ /// <param name="userId">The user identifier.</param>
+ /// <param name="configuration">The configuration.</param>
+ /// <returns>Task.</returns>
+ Task UpdateUserConfiguration(string userId, UserConfiguration configuration);
+
+ /// <summary>
/// Gets a BaseItem
/// </summary>
/// <param name="id">The id.</param>
@@ -497,15 +522,6 @@ namespace MediaBrowser.Model.ApiClient
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;PublicSystemInfo&gt;.</returns>
Task<PublicSystemInfo> GetPublicSystemInfoAsync(CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets a person
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="userId">The user id.</param>
- /// <returns>Task{BaseItemDto}.</returns>
- /// <exception cref="ArgumentNullException">userId</exception>
- Task<BaseItemDto> GetPersonAsync(string name, string userId);
/// <summary>
/// Gets a list of plugins installed on the server
@@ -962,15 +978,6 @@ namespace MediaBrowser.Model.ApiClient
/// <summary>
/// Gets an image url that can be used to download an image from the api
/// </summary>
- /// <param name="name">The name of the person</param>
- /// <param name="options">The options.</param>
- /// <returns>System.String.</returns>
- /// <exception cref="ArgumentNullException">name</exception>
- string GetPersonImageUrl(string name, ImageOptions options);
-
- /// <summary>
- /// Gets an image url that can be used to download an image from the api
- /// </summary>
/// <param name="year">The year.</param>
/// <param name="options">The options.</param>
/// <returns>System.String.</returns>
@@ -1310,15 +1317,6 @@ namespace MediaBrowser.Model.ApiClient
Task<QueryResult<BaseItemDto>> GetPlaylistItems(PlaylistItemQuery query);
/// <summary>
- /// Gets the url needed to stream an audio file
- /// </summary>
- /// <param name="options">The options.</param>
- /// <returns>System.String.</returns>
- /// <exception cref="ArgumentNullException">options</exception>
- [Obsolete]
- string GetAudioStreamUrl(StreamOptions options);
-
- /// <summary>
/// Gets the url needed to stream a video file
/// </summary>
/// <param name="options">The options.</param>
@@ -1421,5 +1419,26 @@ namespace MediaBrowser.Model.ApiClient
/// <param name="webSocketFactory">The web socket factory.</param>
/// <param name="keepAliveTimerMs">The keep alive timer ms.</param>
void OpenWebSocket(Func<IClientWebSocket> webSocketFactory, int keepAliveTimerMs = 60000);
+
+ /// <summary>
+ /// Reports the offline actions.
+ /// </summary>
+ /// <param name="actions">The actions.</param>
+ /// <returns>Task.</returns>
+ Task ReportOfflineActions(List<UserAction> actions);
+
+ /// <summary>
+ /// Gets the ready synchronize items.
+ /// </summary>
+ /// <param name="targetId">The target identifier.</param>
+ /// <returns>List&lt;SyncedItem&gt;.</returns>
+ Task<List<SyncedItem>> GetReadySyncItems(string targetId);
+
+ /// <summary>
+ /// Synchronizes the data.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <returns>Task&lt;SyncDataResponse&gt;.</returns>
+ Task<SyncDataResponse> SyncData(SyncDataRequest request);
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/Configuration/CinemaModeConfiguration.cs b/MediaBrowser.Model/Configuration/CinemaModeConfiguration.cs
index bd20713de..764a7222f 100644
--- a/MediaBrowser.Model/Configuration/CinemaModeConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/CinemaModeConfiguration.cs
@@ -19,6 +19,7 @@ namespace MediaBrowser.Model.Configuration
public CinemaModeConfiguration()
{
EnableIntrosParentalControl = true;
+ EnableIntrosFromSimilarMovies = true;
TrailerLimit = 2;
}
}
diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs
new file mode 100644
index 000000000..f24367298
--- /dev/null
+++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs
@@ -0,0 +1,19 @@
+
+namespace MediaBrowser.Model.Configuration
+{
+ public class EncodingOptions
+ {
+ public EncodingQuality EncodingQuality { get; set; }
+ public string TranscodingTempPath { get; set; }
+ public double DownMixAudioBoost { get; set; }
+ public string H264Encoder { get; set; }
+ public bool EnableDebugLogging { get; set; }
+
+ public EncodingOptions()
+ {
+ H264Encoder = "libx264";
+ DownMixAudioBoost = 2;
+ EncodingQuality = EncodingQuality.Auto;
+ }
+ }
+}
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index b9eaf7001..ba5b6a122 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Entities;
namespace MediaBrowser.Model.Configuration
{
@@ -144,21 +145,8 @@ namespace MediaBrowser.Model.Configuration
/// <value>The image saving convention.</value>
public ImageSavingConvention ImageSavingConvention { get; set; }
- /// <summary>
- /// Gets or sets a value indicating whether [enable people prefix sub folders].
- /// </summary>
- /// <value><c>true</c> if [enable people prefix sub folders]; otherwise, <c>false</c>.</value>
- public bool EnablePeoplePrefixSubFolders { get; set; }
-
- /// <summary>
- /// Gets or sets the encoding quality.
- /// </summary>
- /// <value>The encoding quality.</value>
- public EncodingQuality MediaEncodingQuality { get; set; }
-
public MetadataOptions[] MetadataOptions { get; set; }
- public bool EnableDebugEncodingLogging { get; set; }
public string TranscodingTempPath { get; set; }
public bool EnableAutomaticRestart { get; set; }
@@ -171,16 +159,15 @@ namespace MediaBrowser.Model.Configuration
public string UICulture { get; set; }
- public double DownMixAudioBoost { get; set; }
-
public PeopleMetadataOptions PeopleMetadataOptions { get; set; }
public bool FindInternetTrailers { get; set; }
public string[] InsecureApps7 { get; set; }
public bool SaveMetadataHidden { get; set; }
+ public bool EnableWin8HttpListener { get; set; }
- public bool PlaylistImagesDeleted { get; set; }
+ public NameValuePair[] ContentTypes { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
@@ -188,17 +175,15 @@ namespace MediaBrowser.Model.Configuration
public ServerConfiguration()
: base()
{
- MediaEncodingQuality = EncodingQuality.Auto;
ImageSavingConvention = ImageSavingConvention.Compatible;
PublicPort = 8096;
HttpServerPortNumber = 8096;
EnableDashboardResponseCaching = true;
EnableAutomaticRestart = true;
- EnablePeoplePrefixSubFolders = true;
+ EnableWin8HttpListener = true;
EnableUPnP = true;
- DownMixAudioBoost = 2;
MinResumePct = 5;
MaxResumePct = 90;
@@ -212,6 +197,7 @@ namespace MediaBrowser.Model.Configuration
FindInternetTrailers = true;
PathSubstitutions = new PathSubstitution[] { };
+ ContentTypes = new NameValuePair[] { };
PreferredMetadataLanguage = "en";
MetadataCountryCode = "US";
diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs
index f0a27a2b9..9e33c1c36 100644
--- a/MediaBrowser.Model/Configuration/UserConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs
@@ -42,6 +42,10 @@ namespace MediaBrowser.Model.Configuration
/// <value><c>true</c> if this instance is hidden; otherwise, <c>false</c>.</value>
public bool IsHidden { get; set; }
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is disabled.
+ /// </summary>
+ /// <value><c>true</c> if this instance is disabled; otherwise, <c>false</c>.</value>
public bool IsDisabled { get; set; }
public bool DisplayMissingEpisodes { get; set; }
@@ -74,9 +78,6 @@ namespace MediaBrowser.Model.Configuration
public string[] OrderedViews { get; set; }
- public bool SyncConnectName { get; set; }
- public bool SyncConnectImage { get; set; }
-
public bool IncludeTrailersInSuggestions { get; set; }
public bool EnableCinemaMode { get; set; }
@@ -87,7 +88,9 @@ namespace MediaBrowser.Model.Configuration
public string[] LatestItemsExcludes { get; set; }
public string[] BlockedTags { get; set; }
-
+
+ public bool HasMigratedToPolicy { get; set; }
+
/// <summary>
/// Initializes a new instance of the <see cref="UserConfiguration" /> class.
/// </summary>
@@ -110,8 +113,6 @@ namespace MediaBrowser.Model.Configuration
ExcludeFoldersFromGrouping = new string[] { };
DisplayCollectionsView = true;
- SyncConnectName = true;
- SyncConnectImage = true;
IncludeTrailersInSuggestions = true;
EnableCinemaMode = true;
EnableUserPreferenceAccess = true;
diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs
index 7ca8ab6b0..703c73566 100644
--- a/MediaBrowser.Model/Dlna/StreamInfo.cs
+++ b/MediaBrowser.Model/Dlna/StreamInfo.cs
@@ -374,9 +374,17 @@ namespace MediaBrowser.Model.Dlna
MediaStream stream = TargetAudioStream;
int? streamChannels = stream == null ? null : stream.Channels;
- return MaxAudioChannels.HasValue && !IsDirectStream
- ? (streamChannels.HasValue ? Math.Min(MaxAudioChannels.Value, streamChannels.Value) : MaxAudioChannels.Value)
- : streamChannels;
+ if (MaxAudioChannels.HasValue && !IsDirectStream)
+ {
+ if (streamChannels.HasValue)
+ {
+ return Math.Min(MaxAudioChannels.Value, streamChannels.Value);
+ }
+
+ return MaxAudioChannels.Value;
+ }
+
+ return streamChannels;
}
}
diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs
index 71cefa076..2383d4809 100644
--- a/MediaBrowser.Model/Dto/BaseItemDto.cs
+++ b/MediaBrowser.Model/Dto/BaseItemDto.cs
@@ -366,6 +366,11 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The user data.</value>
public UserItemDataDto UserData { get; set; }
+ /// <summary>
+ /// Gets or sets the season user data.
+ /// </summary>
+ /// <value>The season user data.</value>
+ public UserItemDataDto SeasonUserData { get; set; }
/// <summary>
/// Gets or sets the recursive item count.
@@ -549,7 +554,13 @@ namespace MediaBrowser.Model.Dto
/// Gets or sets a value indicating whether [supports playlists].
/// </summary>
/// <value><c>true</c> if [supports playlists]; otherwise, <c>false</c>.</value>
- public bool SupportsPlaylists { get; set; }
+ public bool SupportsPlaylists
+ {
+ get
+ {
+ return RunTimeTicks.HasValue || IsFolder || IsGenre || IsMusicGenre || IsArtist;
+ }
+ }
/// <summary>
/// Determines whether the specified type is type.
diff --git a/MediaBrowser.Model/Dto/DtoOptions.cs b/MediaBrowser.Model/Dto/DtoOptions.cs
index 069d71fce..60eb6b1fe 100644
--- a/MediaBrowser.Model/Dto/DtoOptions.cs
+++ b/MediaBrowser.Model/Dto/DtoOptions.cs
@@ -1,11 +1,18 @@
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
+using System;
using System.Collections.Generic;
+using System.Linq;
namespace MediaBrowser.Model.Dto
{
public class DtoOptions
{
+ private static readonly List<ItemFields> DefaultExcludedFields = new List<ItemFields>
+ {
+ ItemFields.SeasonUserData
+ };
+
public List<ItemFields> Fields { get; set; }
public List<ImageType> ImageTypes { get; set; }
public int ImageTypeLimit { get; set; }
@@ -14,9 +21,17 @@ namespace MediaBrowser.Model.Dto
public DtoOptions()
{
Fields = new List<ItemFields>();
- ImageTypes = new List<ImageType>();
ImageTypeLimit = int.MaxValue;
EnableImages = true;
+
+ Fields = Enum.GetNames(typeof (ItemFields))
+ .Select(i => (ItemFields) Enum.Parse(typeof (ItemFields), i, true))
+ .Except(DefaultExcludedFields)
+ .ToList();
+
+ ImageTypes = Enum.GetNames(typeof(ImageType))
+ .Select(i => (ImageType)Enum.Parse(typeof(ImageType), i, true))
+ .ToList();
}
public int GetImageLimit(ImageType type)
diff --git a/MediaBrowser.Model/Dto/MetadataEditorInfo.cs b/MediaBrowser.Model/Dto/MetadataEditorInfo.cs
new file mode 100644
index 000000000..9bd15fc8f
--- /dev/null
+++ b/MediaBrowser.Model/Dto/MetadataEditorInfo.cs
@@ -0,0 +1,27 @@
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Globalization;
+using MediaBrowser.Model.Providers;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Model.Dto
+{
+ public class MetadataEditorInfo
+ {
+ public List<ParentalRating> ParentalRatingOptions { get; set; }
+ public List<CountryInfo> Countries { get; set; }
+ public List<CultureDto> Cultures { get; set; }
+ public List<ExternalIdInfo> ExternalIdInfos { get; set; }
+
+ public string ContentType { get; set; }
+ public List<NameValuePair> ContentTypeOptions { get; set; }
+
+ public MetadataEditorInfo()
+ {
+ ParentalRatingOptions = new List<ParentalRating>();
+ Countries = new List<CountryInfo>();
+ Cultures = new List<CultureDto>();
+ ExternalIdInfos = new List<ExternalIdInfo>();
+ ContentTypeOptions = new List<NameValuePair>();
+ }
+ }
+}
diff --git a/MediaBrowser.Model/Dto/NameValuePair.cs b/MediaBrowser.Model/Dto/NameValuePair.cs
new file mode 100644
index 000000000..2d55e8f2a
--- /dev/null
+++ b/MediaBrowser.Model/Dto/NameValuePair.cs
@@ -0,0 +1,17 @@
+
+namespace MediaBrowser.Model.Dto
+{
+ public class NameValuePair
+ {
+ /// <summary>
+ /// Gets or sets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ public string Name { get; set; }
+ /// <summary>
+ /// Gets or sets the value.
+ /// </summary>
+ /// <value>The value.</value>
+ public string Value { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/Dto/StreamOptions.cs b/MediaBrowser.Model/Dto/StreamOptions.cs
deleted file mode 100644
index 5b7cdc6fb..000000000
--- a/MediaBrowser.Model/Dto/StreamOptions.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-using System;
-
-namespace MediaBrowser.Model.Dto
-{
- /// <summary>
- /// Class StreamOptions
- /// </summary>
- [Obsolete]
- public class StreamOptions
- {
- /// <summary>
- /// Gets or sets the audio bit rate.
- /// </summary>
- /// <value>The audio bit rate.</value>
- public int? AudioBitRate { get; set; }
-
- /// <summary>
- /// Gets or sets the audio codec.
- /// Omit to copy the original stream
- /// </summary>
- /// <value>The audio encoding format.</value>
- public string AudioCodec { get; set; }
-
- /// <summary>
- /// Gets or sets the item id.
- /// </summary>
- /// <value>The item id.</value>
- public string ItemId { get; set; }
-
- /// <summary>
- /// Gets or sets the max audio channels.
- /// </summary>
- /// <value>The max audio channels.</value>
- public int? MaxAudioChannels { get; set; }
-
- /// <summary>
- /// Gets or sets the max audio sample rate.
- /// </summary>
- /// <value>The max audio sample rate.</value>
- public int? MaxAudioSampleRate { get; set; }
-
- /// <summary>
- /// Gets or sets the start time ticks.
- /// </summary>
- /// <value>The start time ticks.</value>
- public long? StartTimeTicks { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether the original media should be served statically
- /// Only used with progressive streaming
- /// </summary>
- /// <value><c>true</c> if static; otherwise, <c>false</c>.</value>
- public bool? Static { get; set; }
-
- /// <summary>
- /// Gets or sets the output file extension.
- /// </summary>
- /// <value>The output file extension.</value>
- public string OutputFileExtension { get; set; }
-
- /// <summary>
- /// Gets or sets the device id.
- /// </summary>
- /// <value>The device id.</value>
- public string DeviceId { get; set; }
- }
-}
diff --git a/MediaBrowser.Model/Dto/VideoStreamOptions.cs b/MediaBrowser.Model/Dto/VideoStreamOptions.cs
index 606e928f2..e9a83bd12 100644
--- a/MediaBrowser.Model/Dto/VideoStreamOptions.cs
+++ b/MediaBrowser.Model/Dto/VideoStreamOptions.cs
@@ -6,9 +6,65 @@ namespace MediaBrowser.Model.Dto
/// Class VideoStreamOptions
/// </summary>
[Obsolete]
- public class VideoStreamOptions : StreamOptions
+ public class VideoStreamOptions
{
/// <summary>
+ /// Gets or sets the audio bit rate.
+ /// </summary>
+ /// <value>The audio bit rate.</value>
+ public int? AudioBitRate { get; set; }
+
+ /// <summary>
+ /// Gets or sets the audio codec.
+ /// Omit to copy the original stream
+ /// </summary>
+ /// <value>The audio encoding format.</value>
+ public string AudioCodec { get; set; }
+
+ /// <summary>
+ /// Gets or sets the item id.
+ /// </summary>
+ /// <value>The item id.</value>
+ public string ItemId { get; set; }
+
+ /// <summary>
+ /// Gets or sets the max audio channels.
+ /// </summary>
+ /// <value>The max audio channels.</value>
+ public int? MaxAudioChannels { get; set; }
+
+ /// <summary>
+ /// Gets or sets the max audio sample rate.
+ /// </summary>
+ /// <value>The max audio sample rate.</value>
+ public int? MaxAudioSampleRate { get; set; }
+
+ /// <summary>
+ /// Gets or sets the start time ticks.
+ /// </summary>
+ /// <value>The start time ticks.</value>
+ public long? StartTimeTicks { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether the original media should be served statically
+ /// Only used with progressive streaming
+ /// </summary>
+ /// <value><c>true</c> if static; otherwise, <c>false</c>.</value>
+ public bool? Static { get; set; }
+
+ /// <summary>
+ /// Gets or sets the output file extension.
+ /// </summary>
+ /// <value>The output file extension.</value>
+ public string OutputFileExtension { get; set; }
+
+ /// <summary>
+ /// Gets or sets the device id.
+ /// </summary>
+ /// <value>The device id.</value>
+ public string DeviceId { get; set; }
+
+ /// <summary>
/// Gets or sets the video codec.
/// Omit to copy
/// </summary>
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index b81b4c1fd..d5280f4b1 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -96,6 +96,7 @@
<Compile Include="Configuration\ChannelOptions.cs" />
<Compile Include="Configuration\ChapterOptions.cs" />
<Compile Include="Configuration\CinemaModeConfiguration.cs" />
+ <Compile Include="Configuration\EncodingOptions.cs" />
<Compile Include="Configuration\MetadataConfiguration.cs" />
<Compile Include="Configuration\PeopleMetadataOptions.cs" />
<Compile Include="Configuration\XbmcMetadataOptions.cs" />
@@ -128,9 +129,10 @@
<Compile Include="Drawing\ImageOrientation.cs" />
<Compile Include="Dto\DtoOptions.cs" />
<Compile Include="Dto\IHasServerId.cs" />
+ <Compile Include="Dto\MetadataEditorInfo.cs" />
+ <Compile Include="Dto\NameValuePair.cs" />
<Compile Include="MediaInfo\LiveMediaInfoResult.cs" />
<Compile Include="Dto\MediaSourceType.cs" />
- <Compile Include="Dto\StreamOptions.cs" />
<Compile Include="Dto\VideoStreamOptions.cs" />
<Compile Include="Configuration\DynamicDayOfWeek.cs" />
<Compile Include="Entities\ExtraType.cs" />
@@ -152,6 +154,8 @@
<Compile Include="Configuration\MetadataPluginType.cs" />
<Compile Include="Dlna\SubtitleProfile.cs" />
<Compile Include="MediaInfo\MediaProtocol.cs" />
+ <Compile Include="Net\HttpResponse.cs" />
+ <Compile Include="Net\MimeTypes.cs" />
<Compile Include="Notifications\NotificationOption.cs" />
<Compile Include="Notifications\NotificationOptions.cs" />
<Compile Include="Notifications\NotificationType.cs" />
@@ -363,8 +367,15 @@
<Compile Include="Session\TranscodingInfo.cs" />
<Compile Include="Session\UserDataChangeInfo.cs" />
<Compile Include="Devices\ContentUploadHistory.cs" />
+ <Compile Include="Sync\DeviceFileInfo.cs" />
+ <Compile Include="Sync\ItemFIleInfo.cs" />
+ <Compile Include="Sync\ItemFileType.cs" />
+ <Compile Include="Sync\LocalItem.cs" />
<Compile Include="Sync\SyncCategory.cs" />
+ <Compile Include="Sync\SyncDataRequest.cs" />
+ <Compile Include="Sync\SyncDataResponse.cs" />
<Compile Include="Sync\SyncDialogOptions.cs" />
+ <Compile Include="Sync\SyncedItem.cs" />
<Compile Include="Sync\SyncHelper.cs" />
<Compile Include="Sync\SyncJob.cs" />
<Compile Include="Sync\SyncJobCreationResult.cs" />
@@ -419,6 +430,8 @@
<Compile Include="Users\ForgotPasswordAction.cs" />
<Compile Include="Users\ForgotPasswordResult.cs" />
<Compile Include="Users\PinRedeemResult.cs" />
+ <Compile Include="Users\UserAction.cs" />
+ <Compile Include="Users\UserActionType.cs" />
<Compile Include="Users\UserPolicy.cs" />
<None Include="Fody.targets" />
<None Include="FodyWeavers.xml" />
diff --git a/MediaBrowser.Model/Net/HttpResponse.cs b/MediaBrowser.Model/Net/HttpResponse.cs
new file mode 100644
index 000000000..f4bd8e681
--- /dev/null
+++ b/MediaBrowser.Model/Net/HttpResponse.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+
+namespace MediaBrowser.Model.Net
+{
+ public class HttpResponse : IDisposable
+ {
+ /// <summary>
+ /// Gets or sets the type of the content.
+ /// </summary>
+ /// <value>The type of the content.</value>
+ public string ContentType { get; set; }
+
+ /// <summary>
+ /// Gets or sets the response URL.
+ /// </summary>
+ /// <value>The response URL.</value>
+ public string ResponseUrl { get; set; }
+
+ /// <summary>
+ /// Gets or sets the content.
+ /// </summary>
+ /// <value>The content.</value>
+ public Stream Content { get; set; }
+
+ /// <summary>
+ /// Gets or sets the status code.
+ /// </summary>
+ /// <value>The status code.</value>
+ public HttpStatusCode StatusCode { get; set; }
+
+ /// <summary>
+ /// Gets or sets the length of the content.
+ /// </summary>
+ /// <value>The length of the content.</value>
+ public long? ContentLength { get; set; }
+
+ /// <summary>
+ /// Gets or sets the headers.
+ /// </summary>
+ /// <value>The headers.</value>
+ public Dictionary<string, string> Headers { get; set; }
+
+ private readonly IDisposable _disposable;
+
+ public HttpResponse(IDisposable disposable)
+ {
+ _disposable = disposable;
+ }
+ public HttpResponse()
+ {
+ }
+
+ public void Dispose()
+ {
+ if (_disposable != null)
+ {
+ _disposable.Dispose();
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Common/Net/MimeTypes.cs b/MediaBrowser.Model/Net/MimeTypes.cs
index 14052e759..1f54e48d1 100644
--- a/MediaBrowser.Common/Net/MimeTypes.cs
+++ b/MediaBrowser.Model/Net/MimeTypes.cs
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
-namespace MediaBrowser.Common.Net
+namespace MediaBrowser.Model.Net
{
/// <summary>
/// Class MimeTypes
@@ -11,11 +11,6 @@ namespace MediaBrowser.Common.Net
public static class MimeTypes
{
/// <summary>
- /// The json MIME type
- /// </summary>
- public static string JsonMimeType = "application/json";
-
- /// <summary>
/// Any extension in this list is considered a video file - can be added to at runtime for extensibility
/// </summary>
private static readonly List<string> VideoFileExtensions = new List<string>
@@ -52,26 +47,43 @@ namespace MediaBrowser.Common.Net
private static readonly Dictionary<string, string> VideoFileExtensionsDictionary = VideoFileExtensions.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
- /// <summary>
- /// Determines whether [is video file] [the specified path].
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns><c>true</c> if [is video file] [the specified path]; otherwise, <c>false</c>.</returns>
- public static bool IsVideoFile(string path)
- {
- if (string.IsNullOrEmpty(path))
+ // http://en.wikipedia.org/wiki/Internet_media_type
+ // Add more as needed
+
+ private static readonly Dictionary<string, string> MimeTypeLookup =
+ new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
- throw new ArgumentNullException("path");
- }
+ {".jpg", "image/jpeg"},
+ {".jpeg", "image/jpeg"},
+ {".tbn", "image/jpeg"},
+ {".png", "image/png"},
+ {".gif", "image/gif"},
+ {".webp", "image/webp"},
+ {".ico", "image/vnd.microsoft.icon"},
+ {".mpg", "video/mpeg"},
+ {".mpeg", "video/mpeg"},
+ {".ogv", "video/ogg"},
+ {".mov", "video/quicktime"},
+ {".webm", "video/webm"},
+ {".mkv", "video/x-matroska"},
+ {".wmv", "video/x-ms-wmv"},
+ {".flv", "video/x-flv"},
+ {".avi", "video/x-msvideo"},
+ {".asf", "video/x-ms-asf"},
+ {".m4v", "video/x-m4v"}
+ };
- var extension = Path.GetExtension(path);
+ private static readonly Dictionary<string, string> ExtensionLookup = CreateExtensionLookup();
- if (string.IsNullOrEmpty(extension))
- {
- return false;
- }
+ private static Dictionary<string, string> CreateExtensionLookup()
+ {
+ var dict = MimeTypeLookup
+ .GroupBy(i => i.Value)
+ .ToDictionary(x => x.Key, x => x.First().Key, StringComparer.OrdinalIgnoreCase);
+
+ dict["image/jpg"] = ".jpg";
- return VideoFileExtensionsDictionary.ContainsKey(extension);
+ return dict;
}
/// <summary>
@@ -79,8 +91,8 @@ namespace MediaBrowser.Common.Net
/// </summary>
/// <param name="path">The path.</param>
/// <returns>System.String.</returns>
- /// <exception cref="System.ArgumentNullException">path</exception>
- /// <exception cref="System.InvalidOperationException">Argument not supported: + path</exception>
+ /// <exception cref="ArgumentNullException">path</exception>
+ /// <exception cref="InvalidOperationException">Argument not supported: + path</exception>
public static string GetMimeType(string path)
{
if (string.IsNullOrEmpty(path))
@@ -90,50 +102,13 @@ namespace MediaBrowser.Common.Net
var ext = Path.GetExtension(path) ?? string.Empty;
- // http://en.wikipedia.org/wiki/Internet_media_type
- // Add more as needed
-
- // Type video
- if (ext.Equals(".mpg", StringComparison.OrdinalIgnoreCase) || ext.EndsWith("mpeg", StringComparison.OrdinalIgnoreCase))
- {
- return "video/mpeg";
- }
- if (ext.Equals(".ogv", StringComparison.OrdinalIgnoreCase))
- {
- return "video/ogg";
- }
- if (ext.Equals(".mov", StringComparison.OrdinalIgnoreCase))
+ string result;
+ if (MimeTypeLookup.TryGetValue(ext, out result))
{
- return "video/quicktime";
- }
- if (ext.Equals(".webm", StringComparison.OrdinalIgnoreCase))
- {
- return "video/webm";
- }
- if (ext.Equals(".mkv", StringComparison.OrdinalIgnoreCase))
- {
- return "video/x-matroska";
- }
- if (ext.Equals(".wmv", StringComparison.OrdinalIgnoreCase))
- {
- return "video/x-ms-wmv";
- }
- if (ext.Equals(".flv", StringComparison.OrdinalIgnoreCase))
- {
- return "video/x-flv";
- }
- if (ext.Equals(".avi", StringComparison.OrdinalIgnoreCase))
- {
- return "video/x-msvideo";
- }
- if (ext.Equals(".m4v", StringComparison.OrdinalIgnoreCase))
- {
- return "video/x-m4v";
- }
- if (ext.EndsWith("asf", StringComparison.OrdinalIgnoreCase))
- {
- return "video/x-ms-asf";
+ return result;
}
+
+ // Type video
if (ext.Equals(".3gp", StringComparison.OrdinalIgnoreCase))
{
return "video/3gpp";
@@ -197,28 +172,6 @@ namespace MediaBrowser.Common.Net
return "application/x-cdisplay";
}
- // Type image
- if (ext.Equals(".gif", StringComparison.OrdinalIgnoreCase))
- {
- return "image/gif";
- }
- if (ext.Equals(".jpg", StringComparison.OrdinalIgnoreCase) || ext.Equals(".jpeg", StringComparison.OrdinalIgnoreCase) || ext.Equals(".tbn", StringComparison.OrdinalIgnoreCase))
- {
- return "image/jpeg";
- }
- if (ext.Equals(".png", StringComparison.OrdinalIgnoreCase))
- {
- return "image/png";
- }
- if (ext.Equals(".webp", StringComparison.OrdinalIgnoreCase))
- {
- return "image/webp";
- }
- if (ext.Equals(".ico", StringComparison.OrdinalIgnoreCase))
- {
- return "image/vnd.microsoft.icon";
- }
-
// Type audio
if (ext.Equals(".mp3", StringComparison.OrdinalIgnoreCase))
{
@@ -272,7 +225,7 @@ namespace MediaBrowser.Common.Net
}
if (ext.Equals(".json", StringComparison.OrdinalIgnoreCase))
{
- return JsonMimeType;
+ return "application/json";
}
if (ext.Equals(".map", StringComparison.OrdinalIgnoreCase))
{
@@ -320,19 +273,19 @@ namespace MediaBrowser.Common.Net
throw new ArgumentException("Argument not supported: " + path);
}
- private static readonly Dictionary<string, string> MimeExtensions =
- new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
- {
- {"image/jpeg", "jpg"},
- {"image/jpg", "jpg"},
- {"image/png", "png"},
- {"image/gif", "gif"},
- {"image/webp", "webp"}
- };
-
public static string ToExtension(string mimeType)
{
- return "." + MimeExtensions[mimeType];
+ if (string.IsNullOrEmpty(mimeType))
+ {
+ throw new ArgumentNullException("mimeType");
+ }
+
+ string result;
+ if (ExtensionLookup.TryGetValue(mimeType, out result))
+ {
+ return result;
+ }
+ throw new ArgumentNullException("Unable to determine extension for mimeType: " + mimeType);
}
}
}
diff --git a/MediaBrowser.Model/Querying/ItemFields.cs b/MediaBrowser.Model/Querying/ItemFields.cs
index 19e30cd8a..5018f8e51 100644
--- a/MediaBrowser.Model/Querying/ItemFields.cs
+++ b/MediaBrowser.Model/Querying/ItemFields.cs
@@ -7,6 +7,11 @@ namespace MediaBrowser.Model.Querying
public enum ItemFields
{
/// <summary>
+ /// The air time
+ /// </summary>
+ AirTime,
+
+ /// <summary>
/// The alternate episode numbers
/// </summary>
AlternateEpisodeNumbers,
@@ -102,11 +107,6 @@ namespace MediaBrowser.Model.Querying
Metascore,
/// <summary>
- /// The metadata settings
- /// </summary>
- Settings,
-
- /// <summary>
/// The item overview
/// </summary>
Overview,
@@ -152,6 +152,16 @@ namespace MediaBrowser.Model.Querying
Revenue,
/// <summary>
+ /// The season name
+ /// </summary>
+ SeasonName,
+
+ /// <summary>
+ /// The settings
+ /// </summary>
+ Settings,
+
+ /// <summary>
/// The short overview
/// </summary>
ShortOverview,
@@ -182,6 +192,11 @@ namespace MediaBrowser.Model.Querying
SortName,
/// <summary>
+ /// The special episode numbers
+ /// </summary>
+ SpecialEpisodeNumbers,
+
+ /// <summary>
/// The studios of the item
/// </summary>
Studios,
@@ -219,6 +234,11 @@ namespace MediaBrowser.Model.Querying
/// <summary>
/// The media streams
/// </summary>
- MediaStreams
+ MediaStreams,
+
+ /// <summary>
+ /// The season user data
+ /// </summary>
+ SeasonUserData
}
}
diff --git a/MediaBrowser.Model/Session/TranscodingInfo.cs b/MediaBrowser.Model/Session/TranscodingInfo.cs
index b3ab32a44..e646d80d3 100644
--- a/MediaBrowser.Model/Session/TranscodingInfo.cs
+++ b/MediaBrowser.Model/Session/TranscodingInfo.cs
@@ -5,6 +5,8 @@ namespace MediaBrowser.Model.Session
public string AudioCodec { get; set; }
public string VideoCodec { get; set; }
public string Container { get; set; }
+ public bool IsVideoDirect { get; set; }
+ public bool IsAudioDirect { get; set; }
public int? Bitrate { get; set; }
public float? Framerate { get; set; }
diff --git a/MediaBrowser.Model/Sync/DeviceFileInfo.cs b/MediaBrowser.Model/Sync/DeviceFileInfo.cs
new file mode 100644
index 000000000..bc93b69bc
--- /dev/null
+++ b/MediaBrowser.Model/Sync/DeviceFileInfo.cs
@@ -0,0 +1,9 @@
+
+namespace MediaBrowser.Model.Sync
+{
+ public class DeviceFileInfo
+ {
+ public string Path { get; set; }
+ public string Name { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/Sync/ItemFIleInfo.cs b/MediaBrowser.Model/Sync/ItemFIleInfo.cs
new file mode 100644
index 000000000..b110af6b5
--- /dev/null
+++ b/MediaBrowser.Model/Sync/ItemFIleInfo.cs
@@ -0,0 +1,28 @@
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Model.Sync
+{
+ public class ItemFileInfo
+ {
+ /// <summary>
+ /// Gets or sets the type.
+ /// </summary>
+ /// <value>The type.</value>
+ public ItemFileType Type { get; set; }
+ /// <summary>
+ /// Gets or sets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ public string Name { get; set; }
+ /// <summary>
+ /// Gets or sets the path.
+ /// </summary>
+ /// <value>The path.</value>
+ public string Path { get; set; }
+ /// <summary>
+ /// Gets or sets the type of the image.
+ /// </summary>
+ /// <value>The type of the image.</value>
+ public ImageType ImageType { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/Sync/ItemFileType.cs b/MediaBrowser.Model/Sync/ItemFileType.cs
new file mode 100644
index 000000000..305f4c502
--- /dev/null
+++ b/MediaBrowser.Model/Sync/ItemFileType.cs
@@ -0,0 +1,19 @@
+
+namespace MediaBrowser.Model.Sync
+{
+ public enum ItemFileType
+ {
+ /// <summary>
+ /// The media
+ /// </summary>
+ Media = 0,
+ /// <summary>
+ /// The image
+ /// </summary>
+ Image = 1,
+ /// <summary>
+ /// The subtitles
+ /// </summary>
+ Subtitles = 2
+ }
+}
diff --git a/MediaBrowser.Model/Sync/LocalItem.cs b/MediaBrowser.Model/Sync/LocalItem.cs
new file mode 100644
index 000000000..51faaff90
--- /dev/null
+++ b/MediaBrowser.Model/Sync/LocalItem.cs
@@ -0,0 +1,33 @@
+using MediaBrowser.Model.Dto;
+
+namespace MediaBrowser.Model.Sync
+{
+ public class LocalItem
+ {
+ /// <summary>
+ /// Gets or sets the item.
+ /// </summary>
+ /// <value>The item.</value>
+ public BaseItemDto Item { get; set; }
+ /// <summary>
+ /// Gets or sets the local path.
+ /// </summary>
+ /// <value>The local path.</value>
+ public string LocalPath { get; set; }
+ /// <summary>
+ /// Gets or sets the server identifier.
+ /// </summary>
+ /// <value>The server identifier.</value>
+ public string ServerId { get; set; }
+ /// <summary>
+ /// Gets or sets the unique identifier.
+ /// </summary>
+ /// <value>The unique identifier.</value>
+ public string UniqueId { get; set; }
+ /// <summary>
+ /// Gets or sets the item identifier.
+ /// </summary>
+ /// <value>The item identifier.</value>
+ public string ItemId { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/Sync/SyncDataRequest.cs b/MediaBrowser.Model/Sync/SyncDataRequest.cs
new file mode 100644
index 000000000..3eb447b3f
--- /dev/null
+++ b/MediaBrowser.Model/Sync/SyncDataRequest.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+namespace MediaBrowser.Model.Sync
+{
+ public class SyncDataRequest
+ {
+ public List<string> LocalItemIds { get; set; }
+
+ public string TargetId { get; set; }
+
+ public SyncDataRequest()
+ {
+ LocalItemIds = new List<string>();
+ }
+ }
+}
diff --git a/MediaBrowser.Model/Sync/SyncDataResponse.cs b/MediaBrowser.Model/Sync/SyncDataResponse.cs
new file mode 100644
index 000000000..ac7ff5c84
--- /dev/null
+++ b/MediaBrowser.Model/Sync/SyncDataResponse.cs
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+
+namespace MediaBrowser.Model.Sync
+{
+ public class SyncDataResponse
+ {
+ public List<string> ItemIdsToRemove { get; set; }
+
+ public SyncDataResponse()
+ {
+ ItemIdsToRemove = new List<string>();
+ }
+ }
+}
diff --git a/MediaBrowser.Model/Sync/SyncHelper.cs b/MediaBrowser.Model/Sync/SyncHelper.cs
index 28a36ed21..c2a446fbe 100644
--- a/MediaBrowser.Model/Sync/SyncHelper.cs
+++ b/MediaBrowser.Model/Sync/SyncHelper.cs
@@ -62,6 +62,7 @@ namespace MediaBrowser.Model.Sync
{
List<SyncOptions> options = new List<SyncOptions>();
+ options.Add(SyncOptions.Name);
options.Add(SyncOptions.Quality);
options.Add(SyncOptions.UnwatchedOnly);
options.Add(SyncOptions.SyncNewContent);
diff --git a/MediaBrowser.Model/Sync/SyncJobItem.cs b/MediaBrowser.Model/Sync/SyncJobItem.cs
index 063f7feb2..d9fb1ed09 100644
--- a/MediaBrowser.Model/Sync/SyncJobItem.cs
+++ b/MediaBrowser.Model/Sync/SyncJobItem.cs
@@ -23,6 +23,12 @@ namespace MediaBrowser.Model.Sync
public string ItemId { get; set; }
/// <summary>
+ /// Gets or sets the media source identifier.
+ /// </summary>
+ /// <value>The media source identifier.</value>
+ public string MediaSourceId { get; set; }
+
+ /// <summary>
/// Gets or sets the target identifier.
/// </summary>
/// <value>The target identifier.</value>
diff --git a/MediaBrowser.Model/Sync/SyncJobItemQuery.cs b/MediaBrowser.Model/Sync/SyncJobItemQuery.cs
index b85c21691..d8fa34851 100644
--- a/MediaBrowser.Model/Sync/SyncJobItemQuery.cs
+++ b/MediaBrowser.Model/Sync/SyncJobItemQuery.cs
@@ -28,10 +28,5 @@ namespace MediaBrowser.Model.Sync
/// </summary>
/// <value>The status.</value>
public SyncJobItemStatus? Status { get; set; }
- /// <summary>
- /// Gets or sets a value indicating whether this instance is completed.
- /// </summary>
- /// <value><c>null</c> if [is completed] contains no value, <c>true</c> if [is completed]; otherwise, <c>false</c>.</value>
- public bool? IsCompleted { get; set; }
}
}
diff --git a/MediaBrowser.Model/Sync/SyncJobItemStatus.cs b/MediaBrowser.Model/Sync/SyncJobItemStatus.cs
index 3d0579a3c..606f8cde4 100644
--- a/MediaBrowser.Model/Sync/SyncJobItemStatus.cs
+++ b/MediaBrowser.Model/Sync/SyncJobItemStatus.cs
@@ -6,7 +6,8 @@ namespace MediaBrowser.Model.Sync
Queued = 0,
Converting = 1,
Transferring = 2,
- Completed = 3,
- Failed = 4
+ Synced = 3,
+ Failed = 4,
+ RemovedFromDevice = 5
}
}
diff --git a/MediaBrowser.Model/Sync/SyncedItem.cs b/MediaBrowser.Model/Sync/SyncedItem.cs
new file mode 100644
index 000000000..784a12bc9
--- /dev/null
+++ b/MediaBrowser.Model/Sync/SyncedItem.cs
@@ -0,0 +1,38 @@
+using MediaBrowser.Model.Dto;
+
+namespace MediaBrowser.Model.Sync
+{
+ public class SyncedItem
+ {
+ /// <summary>
+ /// Gets or sets the server identifier.
+ /// </summary>
+ /// <value>The server identifier.</value>
+ public string ServerId { get; set; }
+ /// <summary>
+ /// Gets or sets the synchronize job identifier.
+ /// </summary>
+ /// <value>The synchronize job identifier.</value>
+ public string SyncJobId { get; set; }
+ /// <summary>
+ /// Gets or sets the synchronize job item identifier.
+ /// </summary>
+ /// <value>The synchronize job item identifier.</value>
+ public string SyncJobItemId { get; set; }
+ /// <summary>
+ /// Gets or sets the name of the original file.
+ /// </summary>
+ /// <value>The name of the original file.</value>
+ public string OriginalFileName { get; set; }
+ /// <summary>
+ /// Gets or sets the item.
+ /// </summary>
+ /// <value>The item.</value>
+ public BaseItemDto Item { get; set; }
+ /// <summary>
+ /// Gets or sets the user identifier.
+ /// </summary>
+ /// <value>The user identifier.</value>
+ public string UserId { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/Users/UserAction.cs b/MediaBrowser.Model/Users/UserAction.cs
new file mode 100644
index 000000000..680835364
--- /dev/null
+++ b/MediaBrowser.Model/Users/UserAction.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace MediaBrowser.Model.Users
+{
+ public class UserAction
+ {
+ public string Id { get; set; }
+ public string ServerId { get; set; }
+ public string UserId { get; set; }
+ public string ItemId { get; set; }
+ public UserActionType Type { get; set; }
+ public DateTime Date { get; set; }
+ public long? PositionTicks { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/Users/UserActionType.cs b/MediaBrowser.Model/Users/UserActionType.cs
new file mode 100644
index 000000000..493de6272
--- /dev/null
+++ b/MediaBrowser.Model/Users/UserActionType.cs
@@ -0,0 +1,8 @@
+
+namespace MediaBrowser.Model.Users
+{
+ public enum UserActionType
+ {
+ PlayedItem = 0
+ }
+}
diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs
index b458e2854..0a6a37696 100644
--- a/MediaBrowser.Model/Users/UserPolicy.cs
+++ b/MediaBrowser.Model/Users/UserPolicy.cs
@@ -1,8 +1,75 @@
-
+using MediaBrowser.Model.Configuration;
+
namespace MediaBrowser.Model.Users
{
public class UserPolicy
{
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is administrator.
+ /// </summary>
+ /// <value><c>true</c> if this instance is administrator; otherwise, <c>false</c>.</value>
+ public bool IsAdministrator { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is hidden.
+ /// </summary>
+ /// <value><c>true</c> if this instance is hidden; otherwise, <c>false</c>.</value>
+ public bool IsHidden { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is disabled.
+ /// </summary>
+ /// <value><c>true</c> if this instance is disabled; otherwise, <c>false</c>.</value>
+ public bool IsDisabled { get; set; }
+
+ /// <summary>
+ /// Gets or sets the max parental rating.
+ /// </summary>
+ /// <value>The max parental rating.</value>
+ public int? MaxParentalRating { get; set; }
+
+ public string[] BlockedTags { get; set; }
+ public bool EnableUserPreferenceAccess { get; set; }
+ public AccessSchedule[] AccessSchedules { get; set; }
+ public UnratedItem[] BlockUnratedItems { get; set; }
+ public string[] BlockedMediaFolders { get; set; }
+ public string[] BlockedChannels { get; set; }
+ public bool EnableRemoteControlOfOtherUsers { get; set; }
+ public bool EnableSharedDeviceControl { get; set; }
+
+ public bool EnableLiveTvManagement { get; set; }
+ public bool EnableLiveTvAccess { get; set; }
+
+ public bool EnableMediaPlayback { get; set; }
+ public bool EnableContentDeletion { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether [enable synchronize].
+ /// </summary>
+ /// <value><c>true</c> if [enable synchronize]; otherwise, <c>false</c>.</value>
public bool EnableSync { get; set; }
+
+ public string[] EnabledDevices { get; set; }
+ public bool EnableAllDevices { get; set; }
+
+ public UserPolicy()
+ {
+ EnableLiveTvManagement = true;
+ EnableMediaPlayback = true;
+ EnableLiveTvAccess = true;
+ EnableSharedDeviceControl = true;
+
+ BlockedMediaFolders = new string[] { };
+ BlockedTags = new string[] { };
+ BlockedChannels = new string[] { };
+ BlockUnratedItems = new UnratedItem[] { };
+
+ EnableUserPreferenceAccess = true;
+
+ AccessSchedules = new AccessSchedule[] { };
+
+ EnabledDevices = new string[] { };
+ EnableAllDevices = true;
+ }
}
}
diff --git a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs
index 062519f9d..5afaaa875 100644
--- a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs
+++ b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs
@@ -75,7 +75,7 @@ namespace MediaBrowser.Providers.BoxSets
if (!string.Equals(currentOfficialRating ?? string.Empty, item.OfficialRating ?? string.Empty,
StringComparison.OrdinalIgnoreCase))
{
- updateType = updateType | ItemUpdateType.MetadataDownload;
+ updateType = updateType | ItemUpdateType.MetadataEdit;
}
}
diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs
index 2c97f2c16..700bca0fa 100644
--- a/MediaBrowser.Providers/Manager/ImageSaver.cs
+++ b/MediaBrowser.Providers/Manager/ImageSaver.cs
@@ -16,6 +16,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Model.Net;
namespace MediaBrowser.Providers.Manager
{
diff --git a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
index b0c1b10e4..65d8e287f 100644
--- a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
@@ -6,7 +6,6 @@ using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
-using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
@@ -132,7 +131,9 @@ namespace MediaBrowser.Providers.MediaInfo
public bool Supports(IHasImages item)
{
- return item is Audio;
+ var audio = item as Audio;
+
+ return item.LocationType == LocationType.FileSystem && audio != null && !audio.IsArchive;
}
public bool HasChanged(IHasMetadata item, MetadataStatus status, IDirectoryService directoryService)
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
index a856d5dba..2634bd9bc 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
@@ -38,6 +38,13 @@ namespace MediaBrowser.Providers.MediaInfo
public async Task<ItemUpdateType> Probe<T>(T item, CancellationToken cancellationToken)
where T : Audio
{
+ if (item.IsArchive)
+ {
+ var ext = Path.GetExtension(item.Path) ?? string.Empty;
+ item.Container = ext.TrimStart('.');
+ return ItemUpdateType.MetadataImport;
+ }
+
var result = await GetMediaInfo(item, cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
@@ -58,8 +65,8 @@ namespace MediaBrowser.Providers.MediaInfo
cancellationToken.ThrowIfCancellationRequested();
var idString = item.Id.ToString("N");
- var cachePath = Path.Combine(_appPaths.CachePath,
- "ffprobe-audio",
+ var cachePath = Path.Combine(_appPaths.CachePath,
+ "ffprobe-audio",
idString.Substring(0, 2), idString, "v" + SchemaVersion + _mediaEncoder.Version + item.DateModified.Ticks.ToString(_usCulture) + ".json");
try
@@ -132,7 +139,7 @@ namespace MediaBrowser.Providers.MediaInfo
if (!string.IsNullOrEmpty(data.format.size))
{
- audio.Size = long.Parse(data.format.size , _usCulture);
+ audio.Size = long.Parse(data.format.size, _usCulture);
}
else
{
@@ -217,9 +224,9 @@ namespace MediaBrowser.Providers.MediaInfo
audio.ProductionYear = FFProbeHelpers.GetDictionaryNumericValue(tags, "date");
// Several different forms of retaildate
- audio.PremiereDate = FFProbeHelpers.GetDictionaryDateTime(tags, "retaildate") ??
- FFProbeHelpers.GetDictionaryDateTime(tags, "retail date") ??
- FFProbeHelpers.GetDictionaryDateTime(tags, "retail_date") ??
+ audio.PremiereDate = FFProbeHelpers.GetDictionaryDateTime(tags, "retaildate") ??
+ FFProbeHelpers.GetDictionaryDateTime(tags, "retail date") ??
+ FFProbeHelpers.GetDictionaryDateTime(tags, "retail_date") ??
FFProbeHelpers.GetDictionaryDateTime(tags, "date");
// If we don't have a ProductionYear try and get it from PremiereDate
@@ -261,8 +268,8 @@ namespace MediaBrowser.Providers.MediaInfo
{
// Only use the comma as a delimeter if there are no slashes or pipes.
// We want to be careful not to split names that have commas in them
- var delimeter = !allowCommaDelimiter || _nameDelimiters.Any(i => val.IndexOf(i) != -1) ?
- _nameDelimiters :
+ var delimeter = !allowCommaDelimiter || _nameDelimiters.Any(i => val.IndexOf(i) != -1) ?
+ _nameDelimiters :
new[] { ',' };
return val.Split(delimeter, StringSplitOptions.RemoveEmptyEntries)
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
index 7c078866a..7f025dea1 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
@@ -71,6 +71,13 @@ namespace MediaBrowser.Providers.MediaInfo
CancellationToken cancellationToken)
where T : Video
{
+ if (item.IsArchive)
+ {
+ var ext = Path.GetExtension(item.Path) ?? string.Empty;
+ item.Container = ext.TrimStart('.');
+ return ItemUpdateType.MetadataImport;
+ }
+
var isoMount = await MountIsoIfNeeded(item, cancellationToken).ConfigureAwait(false);
BlurayDiscInfo blurayDiscInfo = null;
diff --git a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
index a91a01edc..7f55ce1ac 100644
--- a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
@@ -123,7 +123,7 @@ namespace MediaBrowser.Providers.MediaInfo
{
var video = item as Video;
- return item.LocationType == LocationType.FileSystem && video != null && !video.IsPlaceHolder && !video.IsShortcut;
+ return item.LocationType == LocationType.FileSystem && video != null && !video.IsPlaceHolder && !video.IsShortcut && !video.IsArchive;
}
public int Order
diff --git a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs
index a7ccf3f6e..6813f2ff5 100644
--- a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs
+++ b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs
@@ -106,6 +106,10 @@ namespace MediaBrowser.Providers.Movies
{
// No biggie. Don't blow up
}
+ catch (DirectoryNotFoundException)
+ {
+ // No biggie. Don't blow up
+ }
}
var language = item.GetPreferredMetadataLanguage();
diff --git a/MediaBrowser.Providers/Music/AlbumMetadataService.cs b/MediaBrowser.Providers/Music/AlbumMetadataService.cs
index 79fab2f70..6e3a5bf06 100644
--- a/MediaBrowser.Providers/Music/AlbumMetadataService.cs
+++ b/MediaBrowser.Providers/Music/AlbumMetadataService.cs
@@ -54,7 +54,7 @@ namespace MediaBrowser.Providers.Music
if (currentList.Count != item.Genres.Count || !currentList.OrderBy(i => i).SequenceEqual(item.Genres.OrderBy(i => i), StringComparer.OrdinalIgnoreCase))
{
- updateType = updateType | ItemUpdateType.MetadataDownload;
+ updateType = updateType | ItemUpdateType.MetadataEdit;
}
}
@@ -68,7 +68,7 @@ namespace MediaBrowser.Providers.Music
if (currentList.Count != item.Studios.Count || !currentList.OrderBy(i => i).SequenceEqual(item.Studios.OrderBy(i => i), StringComparer.OrdinalIgnoreCase))
{
- updateType = updateType | ItemUpdateType.MetadataDownload;
+ updateType = updateType | ItemUpdateType.MetadataEdit;
}
}
@@ -81,15 +81,15 @@ namespace MediaBrowser.Providers.Music
if (!string.Equals(item.Name, name, StringComparison.Ordinal))
{
item.Name = name;
- updateType = updateType | ItemUpdateType.MetadataDownload;
+ updateType = updateType | ItemUpdateType.MetadataEdit;
}
}
}
- }
- updateType = updateType | SetAlbumArtistFromSongs(item, songs);
- updateType = updateType | SetArtistsFromSongs(item, songs);
- updateType = updateType | SetDateFromSongs(item, songs);
+ updateType = updateType | SetAlbumArtistFromSongs(item, songs);
+ updateType = updateType | SetArtistsFromSongs(item, songs);
+ updateType = updateType | SetDateFromSongs(item, songs);
+ }
return updateType;
}
@@ -106,7 +106,7 @@ namespace MediaBrowser.Providers.Music
if (!item.AlbumArtists.SequenceEqual(albumArtists, StringComparer.OrdinalIgnoreCase))
{
item.AlbumArtists = albumArtists;
- updateType = updateType | ItemUpdateType.MetadataDownload;
+ updateType = updateType | ItemUpdateType.MetadataEdit;
}
return updateType;
@@ -124,7 +124,7 @@ namespace MediaBrowser.Providers.Music
if (currentList.Count != item.Artists.Count || !currentList.OrderBy(i => i).SequenceEqual(item.Artists.OrderBy(i => i), StringComparer.OrdinalIgnoreCase))
{
- updateType = updateType | ItemUpdateType.MetadataDownload;
+ updateType = updateType | ItemUpdateType.MetadataEdit;
}
return updateType;
@@ -158,7 +158,7 @@ namespace MediaBrowser.Providers.Music
if ((originalPremiereDate ?? DateTime.MinValue) != (item.PremiereDate ?? DateTime.MinValue) ||
(originalProductionYear ?? -1) != (item.ProductionYear ?? -1))
{
- updateType = updateType | ItemUpdateType.MetadataDownload;
+ updateType = updateType | ItemUpdateType.MetadataEdit;
}
return updateType;
diff --git a/MediaBrowser.Providers/Music/ArtistMetadataService.cs b/MediaBrowser.Providers/Music/ArtistMetadataService.cs
index 939bd2b3b..a73d82992 100644
--- a/MediaBrowser.Providers/Music/ArtistMetadataService.cs
+++ b/MediaBrowser.Providers/Music/ArtistMetadataService.cs
@@ -35,19 +35,22 @@ namespace MediaBrowser.Providers.Music
{
var updateType = base.BeforeSave(item);
- if (!item.IsAccessedByName && !item.LockedFields.Contains(MetadataFields.Genres))
+ if (!item.IsAccessedByName && !item.IsLocked)
{
- var songs = item.RecursiveChildren.OfType<Audio>().ToList();
+ if (!item.LockedFields.Contains(MetadataFields.Genres))
+ {
+ var songs = item.RecursiveChildren.OfType<Audio>().ToList();
- var currentList = item.Genres.ToList();
+ var currentList = item.Genres.ToList();
- item.Genres = songs.SelectMany(i => i.Genres)
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .ToList();
+ item.Genres = songs.SelectMany(i => i.Genres)
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .ToList();
- if (currentList.Count != item.Genres.Count || !currentList.OrderBy(i => i).SequenceEqual(item.Genres.OrderBy(i => i), StringComparer.OrdinalIgnoreCase))
- {
- updateType = updateType | ItemUpdateType.MetadataDownload;
+ if (currentList.Count != item.Genres.Count || !currentList.OrderBy(i => i).SequenceEqual(item.Genres.OrderBy(i => i), StringComparer.OrdinalIgnoreCase))
+ {
+ updateType = updateType | ItemUpdateType.MetadataEdit;
+ }
}
}
diff --git a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs
index 94d682f44..123ff9e29 100644
--- a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs
+++ b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs
@@ -83,6 +83,10 @@ namespace MediaBrowser.Providers.Music
{
}
+ catch (DirectoryNotFoundException)
+ {
+
+ }
}
var language = item.GetPreferredMetadataLanguage();
diff --git a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
index a8df95fd1..6f633cfc8 100644
--- a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
+++ b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
@@ -91,6 +91,10 @@ namespace MediaBrowser.Providers.Music
{
}
+ catch (DirectoryNotFoundException)
+ {
+
+ }
}
var language = item.GetPreferredMetadataLanguage();
diff --git a/MediaBrowser.Providers/People/TvdbPersonImageProvider.cs b/MediaBrowser.Providers/People/TvdbPersonImageProvider.cs
index 63d054664..253acc13f 100644
--- a/MediaBrowser.Providers/People/TvdbPersonImageProvider.cs
+++ b/MediaBrowser.Providers/People/TvdbPersonImageProvider.cs
@@ -83,6 +83,10 @@ namespace MediaBrowser.Providers.People
{
return null;
}
+ catch (DirectoryNotFoundException)
+ {
+ return null;
+ }
}
private RemoteImageInfo GetImageInfo(string xmlFile, string personName, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs
index 05244af74..9f0cd4ff1 100644
--- a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs
+++ b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs
@@ -98,6 +98,10 @@ namespace MediaBrowser.Providers.TV
{
// No biggie. Don't blow up
}
+ catch (DirectoryNotFoundException)
+ {
+ // No biggie. Don't blow up
+ }
}
}
diff --git a/MediaBrowser.Providers/TV/FanartSeriesProvider.cs b/MediaBrowser.Providers/TV/FanartSeriesProvider.cs
index afc71698b..8ba25e9f1 100644
--- a/MediaBrowser.Providers/TV/FanartSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/FanartSeriesProvider.cs
@@ -106,6 +106,10 @@ namespace MediaBrowser.Providers.TV
{
// No biggie. Don't blow up
}
+ catch (DirectoryNotFoundException)
+ {
+ // No biggie. Don't blow up
+ }
}
var language = item.GetPreferredMetadataLanguage();
diff --git a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
index 21d41ca00..0b52956de 100644
--- a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
@@ -2,6 +2,7 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
@@ -22,14 +23,16 @@ namespace MediaBrowser.Providers.TV
private readonly IServerConfigurationManager _config;
private readonly ILogger _logger;
private readonly ILibraryManager _libraryManager;
+ private readonly ILocalizationManager _localization;
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
- public MissingEpisodeProvider(ILogger logger, IServerConfigurationManager config, ILibraryManager libraryManager)
+ public MissingEpisodeProvider(ILogger logger, IServerConfigurationManager config, ILibraryManager libraryManager, ILocalizationManager localization)
{
_logger = logger;
_config = config;
_libraryManager = libraryManager;
+ _localization = localization;
}
public async Task Run(IEnumerable<IGrouping<string, Series>> series, CancellationToken cancellationToken)
@@ -93,16 +96,16 @@ namespace MediaBrowser.Providers.TV
var hasBadData = HasInvalidContent(group);
- var anySeasonsRemoved = await RemoveObsoleteOrMissingSeasons(group, episodeLookup, false)
+ var anySeasonsRemoved = await RemoveObsoleteOrMissingSeasons(group, episodeLookup)
.ConfigureAwait(false);
- var anyEpisodesRemoved = await RemoveObsoleteOrMissingEpisodes(group, episodeLookup, false)
+ var anyEpisodesRemoved = await RemoveObsoleteOrMissingEpisodes(group, episodeLookup)
.ConfigureAwait(false);
var hasNewEpisodes = false;
var hasNewSeasons = false;
- foreach (var series in group.Where(s => s.ContainsEpisodesWithoutSeasonFolders))
+ foreach (var series in group)
{
hasNewSeasons = await AddDummySeasonFolders(series, cancellationToken).ConfigureAwait(false);
}
@@ -165,14 +168,15 @@ namespace MediaBrowser.Providers.TV
/// <returns></returns>
private async Task<bool> AddDummySeasonFolders(Series series, CancellationToken cancellationToken)
{
- var existingEpisodes = series.RecursiveChildren
+ var episodesInSeriesFolder = series.RecursiveChildren
.OfType<Episode>()
+ .Where(i => !i.IsInSeasonFolder)
.ToList();
var hasChanges = false;
// Loop through the unique season numbers
- foreach (var seasonNumber in existingEpisodes.Select(i => i.ParentIndexNumber ?? -1)
+ foreach (var seasonNumber in episodesInSeriesFolder.Select(i => i.ParentIndexNumber ?? -1)
.Where(i => i >= 0)
.Distinct()
.ToList())
@@ -188,6 +192,20 @@ namespace MediaBrowser.Providers.TV
}
}
+ // Unknown season - create a dummy season to put these under
+ if (episodesInSeriesFolder.Any(i => !i.ParentIndexNumber.HasValue))
+ {
+ var hasSeason = series.Children.OfType<Season>()
+ .Any(i => !i.IndexNumber.HasValue);
+
+ if (!hasSeason)
+ {
+ await AddSeason(series, null, cancellationToken).ConfigureAwait(false);
+
+ hasChanges = true;
+ }
+ }
+
return hasChanges;
}
@@ -292,8 +310,7 @@ namespace MediaBrowser.Providers.TV
/// Removes the virtual entry after a corresponding physical version has been added
/// </summary>
private async Task<bool> RemoveObsoleteOrMissingEpisodes(IEnumerable<Series> series,
- IEnumerable<Tuple<int, int>> episodeLookup,
- bool forceRemoveAll)
+ IEnumerable<Tuple<int, int>> episodeLookup)
{
var existingEpisodes = (from s in series
let seasonOffset = TvdbSeriesProvider.GetSeriesOffset(s.ProviderIds) ?? ((s.AnimeSeriesIndex ?? 1) - 1)
@@ -312,11 +329,6 @@ namespace MediaBrowser.Providers.TV
var episodesToRemove = virtualEpisodes
.Where(i =>
{
- if (forceRemoveAll)
- {
- return true;
- }
-
if (i.Episode.IndexNumber.HasValue && i.Episode.ParentIndexNumber.HasValue)
{
var seasonNumber = i.Episode.ParentIndexNumber.Value + i.SeasonOffset;
@@ -362,11 +374,9 @@ namespace MediaBrowser.Providers.TV
/// </summary>
/// <param name="series">The series.</param>
/// <param name="episodeLookup">The episode lookup.</param>
- /// <param name="forceRemoveAll">if set to <c>true</c> [force remove all].</param>
/// <returns>Task{System.Boolean}.</returns>
private async Task<bool> RemoveObsoleteOrMissingSeasons(IEnumerable<Series> series,
- IEnumerable<Tuple<int, int>> episodeLookup,
- bool forceRemoveAll)
+ IEnumerable<Tuple<int, int>> episodeLookup)
{
var existingSeasons = (from s in series
let seasonOffset = TvdbSeriesProvider.GetSeriesOffset(s.ProviderIds) ?? ((s.AnimeSeriesIndex ?? 1) - 1)
@@ -385,11 +395,6 @@ namespace MediaBrowser.Providers.TV
var seasonsToRemove = virtualSeasons
.Where(i =>
{
- if (forceRemoveAll)
- {
- return true;
- }
-
if (i.Season.IndexNumber.HasValue)
{
var seasonNumber = i.Season.IndexNumber.Value + i.SeasonOffset;
@@ -409,7 +414,9 @@ namespace MediaBrowser.Providers.TV
return false;
}
- return true;
+ // Season does not have a number
+ // Remove if there are no episodes directly in series without a season number
+ return i.Season.Series.RecursiveChildren.OfType<Episode>().All(s => s.ParentIndexNumber.HasValue || s.IsInSeasonFolder);
})
.ToList();
@@ -472,20 +479,22 @@ namespace MediaBrowser.Providers.TV
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{Season}.</returns>
private async Task<Season> AddSeason(Series series,
- int seasonNumber,
+ int? seasonNumber,
CancellationToken cancellationToken)
{
- _logger.Info("Creating Season {0} entry for {1}", seasonNumber, series.Name);
+ var seasonName = seasonNumber == 0 ?
+ _config.Configuration.SeasonZeroDisplayName :
+ (seasonNumber.HasValue ? string.Format(_localization.GetLocalizedString("NameSeasonNumber"), seasonNumber.Value.ToString(UsCulture)) : _localization.GetLocalizedString("NameSeasonUnknown"));
- var name = seasonNumber == 0 ? _config.Configuration.SeasonZeroDisplayName : string.Format("Season {0}", seasonNumber.ToString(UsCulture));
+ _logger.Info("Creating Season {0} entry for {1}", seasonName, series.Name);
var season = new Season
{
- Name = name,
+ Name = seasonName,
IndexNumber = seasonNumber,
Parent = series,
DisplayMediaType = typeof(Season).Name,
- Id = (series.Id + seasonNumber.ToString(UsCulture) + name).GetMBId(typeof(Season))
+ Id = (series.Id + (seasonNumber ?? -1).ToString(UsCulture) + seasonName).GetMBId(typeof(Season))
};
await series.AddChild(season, cancellationToken).ConfigureAwait(false);
diff --git a/MediaBrowser.Providers/TV/MovieDbSeasonProvider.cs b/MediaBrowser.Providers/TV/MovieDbSeasonProvider.cs
index 26b2711de..80f4c9485 100644
--- a/MediaBrowser.Providers/TV/MovieDbSeasonProvider.cs
+++ b/MediaBrowser.Providers/TV/MovieDbSeasonProvider.cs
@@ -52,18 +52,18 @@ namespace MediaBrowser.Providers.TV
if (!string.IsNullOrWhiteSpace(seriesTmdbId) && seasonNumber.HasValue)
{
- result.HasMetadata = true;
- result.Item = new Season();
-
try
{
var seasonInfo = await GetSeasonInfo(seriesTmdbId, seasonNumber.Value, info.MetadataLanguage, cancellationToken)
.ConfigureAwait(false);
+ result.HasMetadata = true;
+ result.Item = new Season();
result.Item.Name = info.Name;
- result.Item.Overview = seasonInfo.overview;
result.Item.IndexNumber = seasonNumber;
+ result.Item.Overview = seasonInfo.overview;
+
if (seasonInfo.external_ids.tvdb_id > 0)
{
result.Item.SetProviderId(MetadataProviders.Tvdb, seasonInfo.external_ids.tvdb_id.ToString(CultureInfo.InvariantCulture));
diff --git a/MediaBrowser.Providers/TV/SeriesMetadataService.cs b/MediaBrowser.Providers/TV/SeriesMetadataService.cs
index a7571f7ad..713d46347 100644
--- a/MediaBrowser.Providers/TV/SeriesMetadataService.cs
+++ b/MediaBrowser.Providers/TV/SeriesMetadataService.cs
@@ -7,7 +7,6 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
-using System.Linq;
namespace MediaBrowser.Providers.TV
{
@@ -54,29 +53,5 @@ namespace MediaBrowser.Providers.TV
target.DisplaySpecialsWithSeasons = source.DisplaySpecialsWithSeasons;
}
}
-
- protected override ItemUpdateType BeforeSave(Series item)
- {
- var updateType = base.BeforeSave(item);
-
- var episodes = item.RecursiveChildren
- .OfType<Episode>()
- .ToList();
-
- var dateLastEpisodeAdded = item.DateLastEpisodeAdded;
-
- item.DateLastEpisodeAdded = episodes
- .Where(i => i.LocationType != LocationType.Virtual)
- .Select(i => i.DateCreated)
- .OrderByDescending(i => i)
- .FirstOrDefault();
-
- if (dateLastEpisodeAdded != item.DateLastEpisodeAdded)
- {
- updateType = updateType | ItemUpdateType.MetadataImport;
- }
-
- return updateType;
- }
}
}
diff --git a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs
index d350d2fe4..17a219f52 100644
--- a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs
+++ b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs
@@ -1,11 +1,12 @@
-using System.Collections.Generic;
-using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -25,12 +26,14 @@ namespace MediaBrowser.Providers.TV
private readonly ILibraryManager _libraryManager;
private readonly IServerConfigurationManager _config;
private readonly ILogger _logger;
+ private readonly ILocalizationManager _localization;
- public SeriesPostScanTask(ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config)
+ public SeriesPostScanTask(ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config, ILocalizationManager localization)
{
_libraryManager = libraryManager;
_logger = logger;
_config = config;
+ _localization = localization;
}
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
@@ -47,7 +50,7 @@ namespace MediaBrowser.Providers.TV
var seriesGroups = FindSeriesGroups(seriesList).Where(g => !string.IsNullOrEmpty(g.Key)).ToList();
- await new MissingEpisodeProvider(_logger, _config, _libraryManager).Run(seriesGroups, cancellationToken).ConfigureAwait(false);
+ await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization).Run(seriesGroups, cancellationToken).ConfigureAwait(false);
var numComplete = 0;
@@ -73,10 +76,6 @@ namespace MediaBrowser.Providers.TV
.Select(i => i.Id)
.ToList();
- series.DateLastEpisodeAdded = physicalEpisodes.Select(i => i.DateCreated)
- .OrderByDescending(i => i)
- .FirstOrDefault();
-
numComplete++;
double percent = numComplete;
percent /= seriesList.Count;
diff --git a/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs
index ef9f5427c..52c1ab7dd 100644
--- a/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs
@@ -72,6 +72,10 @@ namespace MediaBrowser.Providers.TV
{
// Don't fail the provider because this will just keep on going and going.
}
+ catch (DirectoryNotFoundException)
+ {
+ // Don't fail the provider because this will just keep on going and going.
+ }
}
return list;
@@ -101,6 +105,10 @@ namespace MediaBrowser.Providers.TV
{
// Don't fail the provider because this will just keep on going and going.
}
+ catch (DirectoryNotFoundException)
+ {
+ // Don't fail the provider because this will just keep on going and going.
+ }
}
return result;
@@ -208,8 +216,9 @@ namespace MediaBrowser.Providers.TV
/// Fetches the episode data.
/// </summary>
/// <param name="id">The identifier.</param>
+ /// <param name="identity">The identity.</param>
/// <param name="seriesDataPath">The series data path.</param>
- /// <param name="seriesProviderIds"></param>
+ /// <param name="seriesProviderIds">The series provider ids.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{System.Boolean}.</returns>
private Episode FetchEpisodeData(EpisodeInfo id, EpisodeIdentity identity, string seriesDataPath, Dictionary<string, string> seriesProviderIds, CancellationToken cancellationToken)
@@ -279,6 +288,10 @@ namespace MediaBrowser.Providers.TV
{
break;
}
+ catch (DirectoryNotFoundException)
+ {
+ break;
+ }
episodeNumber++;
}
diff --git a/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs b/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs
index efafeae96..1ebd7bed5 100644
--- a/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs
@@ -94,6 +94,10 @@ namespace MediaBrowser.Providers.TV
{
// No tvdb data yet. Don't blow up
}
+ catch (DirectoryNotFoundException)
+ {
+ // No tvdb data yet. Don't blow up
+ }
}
return new RemoteImageInfo[] { };
diff --git a/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs
index 9cc09c40c..08913d3b4 100644
--- a/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs
@@ -87,6 +87,10 @@ namespace MediaBrowser.Providers.TV
{
// No tvdb data yet. Don't blow up
}
+ catch (DirectoryNotFoundException)
+ {
+ // No tvdb data yet. Don't blow up
+ }
}
return new RemoteImageInfo[] { };
diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs b/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs
index bfdbb8ccf..ce939aeb4 100644
--- a/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs
+++ b/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs
@@ -95,7 +95,7 @@ namespace MediaBrowser.Server.Implementations.Channels
public static string GetUserDistinctValue(User user)
{
- var channels = user.Configuration.BlockedChannels
+ var channels = user.Policy.BlockedChannels
.OrderBy(i => i)
.ToList();
diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
index 9e7679f93..d88625396 100644
--- a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
+++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
@@ -179,12 +179,9 @@ namespace MediaBrowser.Server.Implementations.Channels
var internalResult = await GetChannelsInternal(query, cancellationToken).ConfigureAwait(false);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields))
- .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
- .ToList();
+ var dtoOptions = new DtoOptions();
- var returnItems = internalResult.Items.Select(i => _dtoService.GetBaseItemDto(i, fields, user))
+ var returnItems = internalResult.Items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
.ToArray();
var result = new QueryResult<BaseItemDto>
@@ -544,11 +541,6 @@ namespace MediaBrowser.Server.Implementations.Channels
var internalResult = await GetLatestChannelItemsInternal(query, cancellationToken).ConfigureAwait(false);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields))
- .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
- .ToList();
-
var items = internalResult.Items;
var totalRecordCount = internalResult.TotalRecordCount;
@@ -563,7 +555,9 @@ namespace MediaBrowser.Server.Implementations.Channels
totalRecordCount = items.Length;
}
- var returnItems = items.Select(i => _dtoService.GetBaseItemDto(i, fields, user))
+ var dtoOptions = new DtoOptions();
+
+ var returnItems = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
.ToArray();
var result = new QueryResult<BaseItemDto>
@@ -828,12 +822,9 @@ namespace MediaBrowser.Server.Implementations.Channels
await RefreshIfNeeded(internalResult.Items, new Progress<double>(), cancellationToken).ConfigureAwait(false);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields))
- .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
- .ToList();
+ var dtoOptions = new DtoOptions();
- var returnItems = internalResult.Items.Select(i => _dtoService.GetBaseItemDto(i, fields, user))
+ var returnItems = internalResult.Items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
.ToArray();
var result = new QueryResult<BaseItemDto>
@@ -980,12 +971,9 @@ namespace MediaBrowser.Server.Implementations.Channels
var internalResult = await GetChannelItemsInternal(query, new Progress<double>(), cancellationToken).ConfigureAwait(false);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields))
- .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
- .ToList();
+ var dtoOptions = new DtoOptions();
- var returnItems = internalResult.Items.Select(i => _dtoService.GetBaseItemDto(i, fields, user))
+ var returnItems = internalResult.Items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
.ToArray();
var result = new QueryResult<BaseItemDto>
@@ -1407,12 +1395,9 @@ namespace MediaBrowser.Server.Implementations.Channels
{
var user = string.IsNullOrEmpty(userId) ? null : _userManager.GetUserById(userId);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
-
var folder = await GetInternalChannelFolder(userId, cancellationToken).ConfigureAwait(false);
- return _dtoService.GetBaseItemDto(folder, fields, user);
+ return _dtoService.GetBaseItemDto(folder, new DtoOptions(), user);
}
public async Task<Folder> GetInternalChannelFolder(string userId, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelPostScanTask.cs b/MediaBrowser.Server.Implementations/Channels/ChannelPostScanTask.cs
index 72c524ec5..d266cca6c 100644
--- a/MediaBrowser.Server.Implementations/Channels/ChannelPostScanTask.cs
+++ b/MediaBrowser.Server.Implementations/Channels/ChannelPostScanTask.cs
@@ -72,26 +72,29 @@ namespace MediaBrowser.Server.Implementations.Channels
var features = _channelManager.GetChannelFeatures(channelId);
const int currentRefreshLevel = 1;
- var maxRefreshLevel = features.AutoRefreshLevels ?? 1;
+ var maxRefreshLevel = features.AutoRefreshLevels ?? 0;
- var innerProgress = new ActionableProgress<double>();
-
- var startingNumberComplete = numComplete;
- innerProgress.RegisterAction(p =>
+ if (maxRefreshLevel > 0)
{
- double innerPercent = startingNumberComplete;
- innerPercent += (p / 100);
- innerPercent /= numItems;
- progress.Report(innerPercent * 100);
- });
+ var innerProgress = new ActionableProgress<double>();
- try
- {
- await GetAllItems(user, channelId, null, currentRefreshLevel, maxRefreshLevel, innerProgress, cancellationToken).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting channel content", ex);
+ var startingNumberComplete = numComplete;
+ innerProgress.RegisterAction(p =>
+ {
+ double innerPercent = startingNumberComplete;
+ innerPercent += (p / 100);
+ innerPercent /= numItems;
+ progress.Report(innerPercent * 100);
+ });
+
+ try
+ {
+ await GetAllItems(user, channelId, null, currentRefreshLevel, maxRefreshLevel, innerProgress, cancellationToken).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error getting channel content", ex);
+ }
}
numComplete++;
diff --git a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
index b9896e9ce..b3b8ccbd8 100644
--- a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
+++ b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Configuration;
+using System.Collections.Generic;
+using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Events;
using MediaBrowser.Common.Implementations.Configuration;
using MediaBrowser.Controller;
@@ -32,7 +33,6 @@ namespace MediaBrowser.Server.Implementations.Configuration
: base(applicationPaths, logManager, xmlSerializer)
{
UpdateItemsByNamePath();
- UpdateTranscodingTempPath();
UpdateMetadataPath();
}
@@ -71,12 +71,18 @@ namespace MediaBrowser.Server.Implementations.Configuration
protected override void OnConfigurationUpdated()
{
UpdateItemsByNamePath();
- UpdateTranscodingTempPath();
UpdateMetadataPath();
base.OnConfigurationUpdated();
}
+ public override void AddParts(IEnumerable<IConfigurationFactory> factories)
+ {
+ base.AddParts(factories);
+
+ UpdateTranscodingTempPath();
+ }
+
/// <summary>
/// Updates the items by name path.
/// </summary>
@@ -102,9 +108,21 @@ namespace MediaBrowser.Server.Implementations.Configuration
/// </summary>
private void UpdateTranscodingTempPath()
{
- ((ServerApplicationPaths)ApplicationPaths).TranscodingTempPath = string.IsNullOrEmpty(Configuration.TranscodingTempPath) ?
+ var encodingConfig = this.GetConfiguration<EncodingOptions>("encoding");
+
+ ((ServerApplicationPaths)ApplicationPaths).TranscodingTempPath = string.IsNullOrEmpty(encodingConfig.TranscodingTempPath) ?
null :
- Configuration.TranscodingTempPath;
+ encodingConfig.TranscodingTempPath;
+ }
+
+ protected override void OnNamedConfigurationUpdated(string key, object configuration)
+ {
+ base.OnNamedConfigurationUpdated(key, configuration);
+
+ if (string.Equals(key, "encoding", StringComparison.OrdinalIgnoreCase))
+ {
+ UpdateTranscodingTempPath();
+ }
}
/// <summary>
@@ -117,7 +135,6 @@ namespace MediaBrowser.Server.Implementations.Configuration
var newConfig = (ServerConfiguration)newConfiguration;
ValidateItemByNamePath(newConfig);
- ValidateTranscodingTempPath(newConfig);
ValidatePathSubstitutions(newConfig);
ValidateMetadataPath(newConfig);
@@ -158,26 +175,6 @@ namespace MediaBrowser.Server.Implementations.Configuration
}
/// <summary>
- /// Validates the transcoding temporary path.
- /// </summary>
- /// <param name="newConfig">The new configuration.</param>
- /// <exception cref="DirectoryNotFoundException"></exception>
- private void ValidateTranscodingTempPath(ServerConfiguration newConfig)
- {
- var newPath = newConfig.TranscodingTempPath;
-
- if (!string.IsNullOrWhiteSpace(newPath)
- && !string.Equals(Configuration.TranscodingTempPath ?? string.Empty, newPath))
- {
- // Validate
- if (!Directory.Exists(newPath))
- {
- throw new DirectoryNotFoundException(string.Format("{0} does not exist.", newPath));
- }
- }
- }
-
- /// <summary>
/// Validates the metadata path.
/// </summary>
/// <param name="newConfig">The new configuration.</param>
diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs b/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs
index 52c252d24..52ec5c9b1 100644
--- a/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs
+++ b/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs
@@ -34,7 +34,7 @@ namespace MediaBrowser.Server.Implementations.Connect
{
LoadCachedAddress();
- _timer = new Timer(TimerCallback, null, TimeSpan.FromSeconds(10), TimeSpan.FromHours(6));
+ _timer = new Timer(TimerCallback, null, TimeSpan.FromSeconds(5), TimeSpan.FromHours(3));
}
private async void TimerCallback(object state)
diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
index cbd75cdeb..67d844543 100644
--- a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
+++ b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
@@ -1,4 +1,5 @@
using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
@@ -432,9 +433,7 @@ namespace MediaBrowser.Server.Implementations.Connect
await user.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
- user.Configuration.SyncConnectImage = false;
- user.Configuration.SyncConnectName = false;
- _userManager.UpdateConfiguration(user, user.Configuration);
+ await _userManager.UpdateConfiguration(user.Id.ToString("N"), user.Configuration);
await RefreshAuthorizationsInternal(false, CancellationToken.None).ConfigureAwait(false);
@@ -791,7 +790,7 @@ namespace MediaBrowser.Server.Implementations.Connect
if (user == null)
{
// Add user
- user = await _userManager.CreateUser(connectEntry.UserName).ConfigureAwait(false);
+ user = await _userManager.CreateUser(_userManager.MakeValidUsername(connectEntry.UserName)).ConfigureAwait(false);
user.ConnectUserName = connectEntry.UserName;
user.ConnectUserId = connectEntry.UserId;
@@ -800,23 +799,21 @@ namespace MediaBrowser.Server.Implementations.Connect
await _userManager.UpdateUser(user).ConfigureAwait(false);
- user.Configuration.SyncConnectImage = true;
- user.Configuration.SyncConnectName = true;
- user.Configuration.IsHidden = true;
- user.Configuration.EnableLiveTvManagement = false;
- user.Configuration.EnableContentDeletion = false;
- user.Configuration.EnableRemoteControlOfOtherUsers = false;
- user.Configuration.EnableSharedDeviceControl = false;
- user.Configuration.IsAdministrator = false;
+ user.Policy.IsHidden = true;
+ user.Policy.EnableLiveTvManagement = false;
+ user.Policy.EnableContentDeletion = false;
+ user.Policy.EnableRemoteControlOfOtherUsers = false;
+ user.Policy.EnableSharedDeviceControl = false;
+ user.Policy.IsAdministrator = false;
if (currentPendingEntry != null)
{
- user.Configuration.EnableLiveTvAccess = currentPendingEntry.EnableLiveTv;
- user.Configuration.BlockedMediaFolders = currentPendingEntry.ExcludedLibraries;
- user.Configuration.BlockedChannels = currentPendingEntry.ExcludedChannels;
+ user.Policy.EnableLiveTvAccess = currentPendingEntry.EnableLiveTv;
+ user.Policy.BlockedMediaFolders = currentPendingEntry.ExcludedLibraries;
+ user.Policy.BlockedChannels = currentPendingEntry.ExcludedChannels;
}
- _userManager.UpdateConfiguration(user, user.Configuration);
+ await _userManager.UpdateConfiguration(user.Id.ToString("N"), user.Configuration);
}
}
else if (string.Equals(connectEntry.AcceptStatus, "waiting", StringComparison.OrdinalIgnoreCase))
@@ -844,7 +841,7 @@ namespace MediaBrowser.Server.Implementations.Connect
{
var users = _userManager.Users
.Where(i => !string.IsNullOrEmpty(i.ConnectUserId) &&
- (i.Configuration.SyncConnectImage || i.Configuration.SyncConnectName))
+ (i.ConnectLinkType.HasValue && i.ConnectLinkType.Value == UserLinkType.Guest))
.ToList();
foreach (var user in users)
@@ -857,7 +854,10 @@ namespace MediaBrowser.Server.Implementations.Connect
continue;
}
- if (user.Configuration.SyncConnectName)
+ var syncConnectName = true;
+ var syncConnectImage = true;
+
+ if (syncConnectName)
{
var changed = !string.Equals(authorization.UserName, user.Name, StringComparison.OrdinalIgnoreCase);
@@ -867,7 +867,7 @@ namespace MediaBrowser.Server.Implementations.Connect
}
}
- if (user.Configuration.SyncConnectImage)
+ if (syncConnectImage)
{
var imageUrl = authorization.UserImageUrl;
diff --git a/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs b/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs
index 6cdc58118..3810fec66 100644
--- a/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs
+++ b/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs
@@ -5,6 +5,7 @@ using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Devices;
using MediaBrowser.Model.Events;
+using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Session;
@@ -13,6 +14,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
+using MediaBrowser.Model.Users;
namespace MediaBrowser.Server.Implementations.Devices
{
@@ -188,6 +190,41 @@ namespace MediaBrowser.Server.Implementations.Devices
EventHelper.FireEventIfNotNull(DeviceOptionsUpdated, this, new GenericEventArgs<DeviceInfo>(device), _logger);
}
+
+ public bool CanAccessDevice(string userId, string deviceId)
+ {
+ if (string.IsNullOrWhiteSpace(userId))
+ {
+ throw new ArgumentNullException("userId");
+ }
+ if (string.IsNullOrWhiteSpace(deviceId))
+ {
+ throw new ArgumentNullException("deviceId");
+ }
+
+ var user = _userManager.GetUserById(userId);
+ if (!CanAccessDevice(user.Policy, deviceId))
+ {
+ var capabilities = GetCapabilities(deviceId);
+
+ if (capabilities.SupportsUniqueIdentifier)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private bool CanAccessDevice(UserPolicy policy, string id)
+ {
+ if (policy.EnableAllDevices)
+ {
+ return true;
+ }
+
+ return ListHelper.ContainsIgnoreCase(policy.EnabledDevices, id);
+ }
}
public class DevicesConfigStore : IConfigurationFactory
diff --git a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
index b141fea1e..967c78c50 100644
--- a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
+++ b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
@@ -78,6 +78,11 @@ namespace MediaBrowser.Server.Implementations.Drawing
// No biggie
sizeDictionary = new Dictionary<Guid, ImageSize>();
}
+ catch (DirectoryNotFoundException)
+ {
+ // No biggie
+ sizeDictionary = new Dictionary<Guid, ImageSize>();
+ }
catch (Exception ex)
{
logger.ErrorException("Error parsing image size cache file", ex);
diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
index 1020a4373..362ee80b0 100644
--- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs
+++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
@@ -73,11 +73,6 @@ namespace MediaBrowser.Server.Implementations.Dto
{
Fields = fields
};
-
- // Get everything
- options.ImageTypes = Enum.GetNames(typeof(ImageType))
- .Select(i => (ImageType)Enum.Parse(typeof(ImageType), i, true))
- .ToList();
return GetBaseItemDto(item, options, user, owner);
}
@@ -121,8 +116,6 @@ namespace MediaBrowser.Server.Implementations.Dto
ServerId = _appHost.SystemId
};
- dto.SupportsPlaylists = item.SupportsAddingToPlaylist;
-
if (fields.Contains(ItemFields.People))
{
AttachPeople(dto, item);
@@ -275,6 +268,21 @@ namespace MediaBrowser.Server.Implementations.Dto
}
dto.PlayAccess = item.GetPlayAccess(user);
+
+ if (fields.Contains(ItemFields.SeasonUserData))
+ {
+ var episode = item as Episode;
+
+ if (episode != null)
+ {
+ var season = episode.Season;
+
+ if (season != null)
+ {
+ dto.SeasonUserData = _userDataRepository.GetUserDataDto(season, user);
+ }
+ }
+ }
}
private int GetChildCount(Folder folder, User user)
@@ -750,7 +758,7 @@ namespace MediaBrowser.Server.Implementations.Dto
dto.AspectRatio = hasAspectRatio.AspectRatio;
}
- if (fields.Contains(ItemFields.ProductionLocations))
+ if (fields.Contains(ItemFields.Metascore))
{
var hasMetascore = item as IHasMetascore;
if (hasMetascore != null)
@@ -1132,15 +1140,22 @@ namespace MediaBrowser.Server.Implementations.Dto
dto.AbsoluteEpisodeNumber = episode.AbsoluteEpisodeNumber;
}
- dto.AirsAfterSeasonNumber = episode.AirsAfterSeasonNumber;
- dto.AirsBeforeEpisodeNumber = episode.AirsBeforeEpisodeNumber;
- dto.AirsBeforeSeasonNumber = episode.AirsBeforeSeasonNumber;
+ //if (fields.Contains(ItemFields.SpecialEpisodeNumbers))
+ {
+ dto.AirsAfterSeasonNumber = episode.AirsAfterSeasonNumber;
+ dto.AirsBeforeEpisodeNumber = episode.AirsBeforeEpisodeNumber;
+ dto.AirsBeforeSeasonNumber = episode.AirsBeforeSeasonNumber;
+ }
var episodeSeason = episode.Season;
if (episodeSeason != null)
{
dto.SeasonId = episodeSeason.Id.ToString("N");
- dto.SeasonName = episodeSeason.Name;
+
+ if (fields.Contains(ItemFields.SeasonName))
+ {
+ dto.SeasonName = episodeSeason.Name;
+ }
}
if (fields.Contains(ItemFields.SeriesGenres))
@@ -1180,7 +1195,11 @@ namespace MediaBrowser.Server.Implementations.Dto
{
dto.SeriesId = GetDtoId(series);
dto.SeriesName = series.Name;
- dto.AirTime = series.AirTime;
+
+ if (fields.Contains(ItemFields.AirTime))
+ {
+ dto.AirTime = series.AirTime;
+ }
if (options.GetImageLimit(ImageType.Thumb) > 0)
{
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/UsageEntryPoint.cs b/MediaBrowser.Server.Implementations/EntryPoints/UsageEntryPoint.cs
index de53201c9..fcc664011 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/UsageEntryPoint.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/UsageEntryPoint.cs
@@ -1,6 +1,5 @@
using MediaBrowser.Common;
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Implementations.Security;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Session;
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
index d4625d402..432ea1f69 100644
--- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
+++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
@@ -4,11 +4,11 @@ using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.FileOrganization;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
-using MediaBrowser.Controller.Resolvers;
-using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.FileOrganization;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Naming.Common;
+using MediaBrowser.Naming.IO;
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -16,8 +16,6 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Server.Implementations.Library;
-using MediaBrowser.Server.Implementations.Library.Resolvers.TV;
namespace MediaBrowser.Server.Implementations.FileOrganization
{
@@ -57,18 +55,23 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
FileSize = new FileInfo(path).Length
};
- var seriesName = SeriesResolver.GetSeriesNameFromEpisodeFile(path);
+ var resolver = new Naming.TV.EpisodeResolver(new ExtendedNamingOptions(), new Naming.Logging.NullLogger());
+
+ var episodeInfo = resolver.Resolve(path, FileInfoType.File) ??
+ new Naming.TV.EpisodeInfo();
+
+ var seriesName = episodeInfo.SeriesName;
if (!string.IsNullOrEmpty(seriesName))
{
- var season = SeriesResolver.GetSeasonNumberFromEpisodeFile(path);
+ var season = episodeInfo.SeasonNumber;
result.ExtractedSeasonNumber = season;
if (season.HasValue)
{
// Passing in true will include a few extra regex's
- var episode = SeriesResolver.GetEpisodeNumberFromFile(path, true);
+ var episode = episodeInfo.EpisodeNumber;
result.ExtractedEpisodeNumber = episode;
@@ -76,7 +79,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
{
_logger.Debug("Extracted information from {0}. Series name {1}, Season {2}, Episode {3}", path, seriesName, season, episode);
- var endingEpisodeNumber = SeriesResolver.GetEndingEpisodeNumberFromFile(path);
+ var endingEpisodeNumber = episodeInfo.EndingEpsiodeNumber;
result.ExtractedEndingEpisodeNumber = endingEpisodeNumber;
@@ -251,7 +254,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
var folder = Path.GetDirectoryName(targetPath);
var targetFileNameWithoutExtension = _fileSystem.GetFileNameWithoutExtension(targetPath);
-
+
try
{
var filesOfOtherExtensions = Directory.EnumerateFiles(folder, "*", SearchOption.TopDirectoryOnly)
@@ -456,11 +459,11 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
private bool IsSameEpisode(string sourcePath, string newPath)
{
- var sourceFileInfo = new FileInfo(sourcePath);
- var destinationFileInfo = new FileInfo(newPath);
-
try
{
+ var sourceFileInfo = new FileInfo(sourcePath);
+ var destinationFileInfo = new FileInfo(newPath);
+
if (sourceFileInfo.Length == destinationFileInfo.Length)
{
return true;
@@ -470,6 +473,10 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
{
return false;
}
+ catch (DirectoryNotFoundException)
+ {
+ return false;
+ }
return false;
}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
index 56e2e5247..c3228db92 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -1,7 +1,6 @@
using Funq;
using MediaBrowser.Common;
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Logging;
using MediaBrowser.Server.Implementations.HttpServer.NetListener;
@@ -205,10 +204,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
{
HostContext.Config.HandlerFactoryPath = ListenerRequest.GetHandlerPathIfAny(UrlPrefixes.First());
- _listener = _supportsNativeWebSocket && NativeWebSocket.IsSupported
- ? _listener = new HttpListenerServer(_logger, OnRequestReceived)
- //? _listener = new WebSocketSharpListener(_logger, OnRequestReceived)
- : _listener = new WebSocketSharpListener(_logger, OnRequestReceived);
+ _listener = GetListener();
_listener.WebSocketHandler = WebSocketHandler;
_listener.ErrorHandler = ErrorHandler;
@@ -217,6 +213,16 @@ namespace MediaBrowser.Server.Implementations.HttpServer
_listener.Start(UrlPrefixes);
}
+ private IHttpListener GetListener()
+ {
+ if (_supportsNativeWebSocket && NativeWebSocket.IsSupported)
+ {
+ return new HttpListenerServer(_logger, OnRequestReceived);
+ }
+
+ return new WebSocketSharpListener(_logger, OnRequestReceived);
+ }
+
private void WebSocketHandler(WebSocketConnectEventArgs args)
{
if (WebSocketConnected != null)
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
index e13e27d5a..681d3ac5e 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
@@ -12,7 +12,7 @@ using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
-using MimeTypes = MediaBrowser.Common.Net.MimeTypes;
+using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
namespace MediaBrowser.Server.Implementations.HttpServer
{
diff --git a/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs b/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs
index 86e8856cf..e77600e93 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs
@@ -1,8 +1,8 @@
-using System.Threading.Tasks;
-using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Net;
using ServiceStack.Web;
using System;
using System.Collections.Generic;
+using System.Threading.Tasks;
namespace MediaBrowser.Server.Implementations.HttpServer
{
diff --git a/MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs b/MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs
index 8cc614fe5..cac2f8e09 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs
@@ -1,9 +1,9 @@
-using System.Text;
-using MediaBrowser.Common.Events;
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Events;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Logging;
using System;
using System.Net.WebSockets;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
using WebSocketMessageType = MediaBrowser.Model.Net.WebSocketMessageType;
diff --git a/MediaBrowser.Server.Implementations/HttpServer/NetListener/HttpListenerServer.cs b/MediaBrowser.Server.Implementations/HttpServer/NetListener/HttpListenerServer.cs
index 2d41cc26f..31c0e87b3 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/NetListener/HttpListenerServer.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/NetListener/HttpListenerServer.cs
@@ -1,4 +1,4 @@
-using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Logging;
using ServiceStack;
using ServiceStack.Host.HttpListener;
diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs
index 57d87749c..1d17c641d 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Connect;
+using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
@@ -15,10 +16,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
{
private readonly IServerConfigurationManager _config;
- public AuthService(IUserManager userManager, IAuthorizationContext authorizationContext, IServerConfigurationManager config, IConnectManager connectManager, ISessionManager sessionManager)
+ public AuthService(IUserManager userManager, IAuthorizationContext authorizationContext, IServerConfigurationManager config, IConnectManager connectManager, ISessionManager sessionManager, IDeviceManager deviceManager)
{
AuthorizationContext = authorizationContext;
_config = config;
+ DeviceManager = deviceManager;
SessionManager = sessionManager;
ConnectManager = connectManager;
UserManager = userManager;
@@ -28,6 +30,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
public IAuthorizationContext AuthorizationContext { get; private set; }
public IConnectManager ConnectManager { get; private set; }
public ISessionManager SessionManager { get; private set; }
+ public IDeviceManager DeviceManager { get; private set; }
/// <summary>
/// Redirect the client to a specific URL if authentication failed.
@@ -68,24 +71,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
if (user != null)
{
- if (user.Configuration.IsDisabled)
- {
- throw new SecurityException("User account has been disabled.")
- {
- SecurityExceptionType = SecurityExceptionType.Unauthenticated
- };
- }
-
- if (!user.Configuration.IsAdministrator &&
- !authAttribtues.EscapeParentalControl &&
- !user.IsParentalScheduleAllowed())
- {
- request.AddResponseHeader("X-Application-Error-Code", "ParentalControl");
- throw new SecurityException("This user account is not allowed access at this time.")
- {
- SecurityExceptionType = SecurityExceptionType.ParentalControl
- };
- }
+ ValidateUserAccess(user, request, authAttribtues, auth);
}
if (!IsExemptFromRoles(auth, authAttribtues))
@@ -108,6 +94,42 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
}
}
+ private void ValidateUserAccess(User user, IServiceRequest request,
+ IAuthenticationAttributes authAttribtues,
+ AuthorizationInfo auth)
+ {
+ if (user.Policy.IsDisabled)
+ {
+ throw new SecurityException("User account has been disabled.")
+ {
+ SecurityExceptionType = SecurityExceptionType.Unauthenticated
+ };
+ }
+
+ if (!user.Policy.IsAdministrator &&
+ !authAttribtues.EscapeParentalControl &&
+ !user.IsParentalScheduleAllowed())
+ {
+ request.AddResponseHeader("X-Application-Error-Code", "ParentalControl");
+
+ throw new SecurityException("This user account is not allowed access at this time.")
+ {
+ SecurityExceptionType = SecurityExceptionType.ParentalControl
+ };
+ }
+
+ if (!string.IsNullOrWhiteSpace(auth.DeviceId))
+ {
+ if (!DeviceManager.CanAccessDevice(user.Id.ToString("N"), auth.DeviceId))
+ {
+ throw new SecurityException("User is not allowed access from this device.")
+ {
+ SecurityExceptionType = SecurityExceptionType.ParentalControl
+ };
+ }
+ }
+ }
+
private bool IsExemptFromAuthenticationToken(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues)
{
if (!_config.Configuration.IsStartupWizardCompleted &&
@@ -135,7 +157,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
{
if (roles.Contains("admin", StringComparer.OrdinalIgnoreCase))
{
- if (user == null || !user.Configuration.IsAdministrator)
+ if (user == null || !user.Policy.IsAdministrator)
{
throw new SecurityException("User does not have admin access.")
{
@@ -145,7 +167,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
}
if (roles.Contains("delete", StringComparer.OrdinalIgnoreCase))
{
- if (user == null || !user.Configuration.EnableContentDeletion)
+ if (user == null || !user.Policy.EnableContentDeletion)
{
throw new SecurityException("User does not have delete access.")
{
diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/SharpWebSocket.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/SharpWebSocket.cs
index 7ff3a1247..401d49325 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/SharpWebSocket.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/SharpWebSocket.cs
@@ -1,11 +1,9 @@
-using System.Text;
-using MediaBrowser.Common.Events;
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Events;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Logging;
using System;
using System.Threading;
using System.Threading.Tasks;
-using WebSocketMessageType = MediaBrowser.Model.Net.WebSocketMessageType;
using WebSocketState = MediaBrowser.Model.Net.WebSocketState;
namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
index 9deb34e91..77d968409 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
@@ -1,4 +1,4 @@
-using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Logging;
using ServiceStack;
using ServiceStack.Web;
@@ -6,7 +6,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
-using System.Threading;
using System.Threading.Tasks;
using WebSocketSharp.Net;
@@ -15,7 +14,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
public class WebSocketSharpListener : IHttpListener
{
private HttpListener _listener;
- private readonly ManualResetEventSlim _listenForNextRequest = new ManualResetEventSlim(false);
private readonly ILogger _logger;
private readonly Action<string> _endpointListener;
@@ -43,70 +41,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
_listener.Prefixes.Add(prefix);
}
- _listener.Start();
-
- Task.Factory.StartNew(Listen, TaskCreationOptions.LongRunning);
- }
-
- private bool IsListening
- {
- get { return _listener != null && _listener.IsListening; }
- }
+ _listener.OnContext = ProcessContext;
- // Loop here to begin processing of new requests.
- private void Listen()
- {
- while (IsListening)
- {
- if (_listener == null) return;
- _listenForNextRequest.Reset();
-
- try
- {
- _listener.BeginGetContext(ListenerCallback, _listener);
- _listenForNextRequest.Wait();
- }
- catch (Exception ex)
- {
- _logger.Error("Listen()", ex);
- return;
- }
- if (_listener == null) return;
- }
+ _listener.Start();
}
- // Handle the processing of a request in here.
- private void ListenerCallback(IAsyncResult asyncResult)
+ private void ProcessContext(HttpListenerContext context)
{
- _listenForNextRequest.Set();
-
- var listener = asyncResult.AsyncState as HttpListener;
- HttpListenerContext context;
-
- if (listener == null) return;
- var isListening = listener.IsListening;
-
- try
- {
- if (!isListening)
- {
- _logger.Debug("Ignoring ListenerCallback() as HttpListener is no longer listening"); return;
- }
- // The EndGetContext() method, as with all Begin/End asynchronous methods in the .NET Framework,
- // blocks until there is a request to be processed or some type of data is available.
- context = listener.EndGetContext(asyncResult);
- }
- catch (Exception ex)
- {
- // You will get an exception when httpListener.Stop() is called
- // because there will be a thread stopped waiting on the .EndGetContext()
- // method, and again, that is just the way most Begin/End asynchronous
- // methods of the .NET Framework work.
- var errMsg = ex + ": " + IsListening;
- _logger.Warn(errMsg);
- return;
- }
-
Task.Factory.StartNew(() => InitTask(context));
}
@@ -117,10 +58,10 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
var task = this.ProcessRequestAsync(context);
task.ContinueWith(x => HandleError(x.Exception, context), TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.AttachedToParent);
- if (task.Status == TaskStatus.Created)
- {
- task.RunSynchronously();
- }
+ //if (task.Status == TaskStatus.Created)
+ //{
+ // task.RunSynchronously();
+ //}
}
catch (Exception ex)
{
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index 4cb39778c..b4a4c7e9a 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -18,8 +18,8 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.Naming.Audio;
using MediaBrowser.Naming.Common;
using MediaBrowser.Naming.IO;
+using MediaBrowser.Naming.TV;
using MediaBrowser.Naming.Video;
-using MediaBrowser.Server.Implementations.Library.Resolvers.TV;
using MediaBrowser.Server.Implementations.Library.Validators;
using MediaBrowser.Server.Implementations.ScheduledTasks;
using System;
@@ -68,6 +68,7 @@ namespace MediaBrowser.Server.Implementations.Library
/// </summary>
/// <value>The entity resolvers enumerable.</value>
private IItemResolver[] EntityResolvers { get; set; }
+ private IMultiItemResolver[] MultiItemResolvers { get; set; }
/// <summary>
/// Gets or sets the comparers.
@@ -196,9 +197,10 @@ namespace MediaBrowser.Server.Implementations.Library
EntityResolutionIgnoreRules = rules.ToArray();
PluginFolderCreators = pluginFolders.ToArray();
EntityResolvers = resolvers.OrderBy(i => i.Priority).ToArray();
+ MultiItemResolvers = EntityResolvers.OfType<IMultiItemResolver>().ToArray();
IntroProviders = introProviders.ToArray();
Comparers = itemComparers.ToArray();
-
+
PostscanTasks = postscanTasks.OrderBy(i =>
{
var hasOrder = i as IHasOrder;
@@ -344,7 +346,7 @@ namespace MediaBrowser.Server.Implementations.Library
try
{
- await UpdateItem(season, ItemUpdateType.MetadataDownload, cancellationToken).ConfigureAwait(false);
+ await UpdateItem(season, ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -560,10 +562,9 @@ namespace MediaBrowser.Server.Implementations.Library
}
public BaseItem ResolvePath(FileSystemInfo fileInfo,
- Folder parent = null,
- string collectionType = null)
+ Folder parent = null)
{
- return ResolvePath(fileInfo, new DirectoryService(_logger), parent, collectionType);
+ return ResolvePath(fileInfo, new DirectoryService(_logger), parent);
}
private BaseItem ResolvePath(FileSystemInfo fileInfo, IDirectoryService directoryService, Folder parent = null, string collectionType = null)
@@ -573,10 +574,17 @@ namespace MediaBrowser.Server.Implementations.Library
throw new ArgumentNullException("fileInfo");
}
+ var fullPath = fileInfo.FullName;
+
+ if (string.IsNullOrWhiteSpace(collectionType))
+ {
+ collectionType = GetConfiguredContentType(fullPath);
+ }
+
var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, this, directoryService)
{
Parent = parent,
- Path = fileInfo.FullName,
+ Path = fullPath,
FileInfo = fileInfo,
CollectionType = collectionType
};
@@ -652,9 +660,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (parent != null)
{
- var multiItemResolvers = EntityResolvers.OfType<IMultiItemResolver>();
-
- foreach (var resolver in multiItemResolvers)
+ foreach (var resolver in MultiItemResolvers)
{
var result = resolver.ResolveMultiple(parent, fileList, collectionType, directoryService);
@@ -862,7 +868,7 @@ namespace MediaBrowser.Server.Implementations.Library
var type = typeof(T);
- if (type == typeof(Person) && ConfigurationManager.Configuration.EnablePeoplePrefixSubFolders)
+ if (type == typeof(Person))
{
subFolderPrefix = validFilename.Substring(0, 1);
}
@@ -1546,12 +1552,48 @@ namespace MediaBrowser.Server.Implementations.Library
return ItemRepository.RetrieveItem(id);
}
- /// <summary>
- /// Finds the type of the collection.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns>System.String.</returns>
- public string FindCollectionType(BaseItem item)
+ public string GetContentType(BaseItem item)
+ {
+ // Types cannot be overridden, so go from the top down until we find a configured content type
+
+ var type = GetTopFolderContentType(item);
+
+ if (!string.IsNullOrWhiteSpace(type))
+ {
+ return type;
+ }
+
+ type = GetInheritedContentType(item);
+
+ if (!string.IsNullOrWhiteSpace(type))
+ {
+ return type;
+ }
+
+ return GetConfiguredContentType(item);
+ }
+
+ public string GetInheritedContentType(BaseItem item)
+ {
+ return item.Parents
+ .Select(GetConfiguredContentType)
+ .LastOrDefault(i => !string.IsNullOrWhiteSpace(i));
+ }
+
+ private string GetConfiguredContentType(BaseItem item)
+ {
+ return GetConfiguredContentType(item.ContainingFolderPath);
+ }
+
+ private string GetConfiguredContentType(string path)
+ {
+ var type = ConfigurationManager.Configuration.ContentTypes
+ .FirstOrDefault(i => string.Equals(i.Name, path, StringComparison.OrdinalIgnoreCase) || _fileSystem.ContainsSubPath(i.Name, path));
+
+ return type == null ? null : type.Value;
+ }
+
+ private string GetTopFolderContentType(BaseItem item)
{
while (!(item.Parent is AggregateFolder) && item.Parent != null)
{
@@ -1563,14 +1605,11 @@ namespace MediaBrowser.Server.Implementations.Library
return null;
}
- var collectionTypes = GetUserRootFolder().Children
+ return GetUserRootFolder().Children
.OfType<ICollectionFolder>()
- .Where(i => !string.IsNullOrEmpty(i.CollectionType) && (string.Equals(i.Path, item.Path, StringComparison.OrdinalIgnoreCase) || i.PhysicalLocations.Contains(item.Path)))
+ .Where(i => string.Equals(i.Path, item.Path, StringComparison.OrdinalIgnoreCase) || i.PhysicalLocations.Contains(item.Path))
.Select(i => i.CollectionType)
- .Distinct()
- .ToList();
-
- return collectionTypes.Count == 1 ? collectionTypes[0] : null;
+ .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i));
}
public async Task<UserView> GetNamedView(string name,
@@ -1708,22 +1747,127 @@ namespace MediaBrowser.Server.Implementations.Library
public int? GetSeasonNumberFromPath(string path)
{
- return SeriesResolver.GetSeasonNumberFromPath(path, CollectionType.TvShows);
+ return new SeasonPathParser(new ExtendedNamingOptions(), new RegexProvider()).Parse(path, true).SeasonNumber;
}
- public int? GetSeasonNumberFromEpisodeFile(string path)
+ public bool FillMissingEpisodeNumbersFromPath(Episode episode)
{
- return SeriesResolver.GetSeasonNumberFromEpisodeFile(path);
- }
+ var resolver = new EpisodeResolver(new ExtendedNamingOptions(),
+ new Naming.Logging.NullLogger());
- public int? GetEndingEpisodeNumberFromFile(string path)
- {
- return SeriesResolver.GetEndingEpisodeNumberFromFile(path);
- }
+ var fileType = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd || episode.VideoType == VideoType.HdDvd ?
+ FileInfoType.Directory :
+ FileInfoType.File;
- public int? GetEpisodeNumberFromFile(string path, bool considerSeasonless)
- {
- return SeriesResolver.GetEpisodeNumberFromFile(path, considerSeasonless);
+ var locationType = episode.LocationType;
+
+ var episodeInfo = locationType == LocationType.FileSystem || locationType == LocationType.Offline ?
+ resolver.Resolve(episode.Path, fileType) :
+ new Naming.TV.EpisodeInfo();
+
+ if (episodeInfo == null)
+ {
+ episodeInfo = new Naming.TV.EpisodeInfo();
+ }
+
+ var changed = false;
+
+ if (episodeInfo.IsByDate)
+ {
+ if (episode.IndexNumber.HasValue)
+ {
+ episode.IndexNumber = null;
+ changed = true;
+ }
+
+ if (episode.IndexNumberEnd.HasValue)
+ {
+ episode.IndexNumberEnd = null;
+ changed = true;
+ }
+
+ if (!episode.PremiereDate.HasValue)
+ {
+ if (episodeInfo.Year.HasValue && episodeInfo.Month.HasValue && episodeInfo.Day.HasValue)
+ {
+ episode.PremiereDate = new DateTime(episodeInfo.Year.Value, episodeInfo.Month.Value, episodeInfo.Day.Value).ToUniversalTime();
+ }
+
+ if (episode.PremiereDate.HasValue)
+ {
+ changed = true;
+ }
+ }
+
+ if (!episode.ProductionYear.HasValue)
+ {
+ episode.ProductionYear = episodeInfo.Year;
+
+ if (episode.ProductionYear.HasValue)
+ {
+ changed = true;
+ }
+ }
+
+ if (!episode.ParentIndexNumber.HasValue)
+ {
+ var season = episode.Season;
+
+ if (season != null)
+ {
+ episode.ParentIndexNumber = season.IndexNumber;
+ }
+
+ if (episode.ParentIndexNumber.HasValue)
+ {
+ changed = true;
+ }
+ }
+ }
+ else
+ {
+ if (!episode.IndexNumber.HasValue)
+ {
+ episode.IndexNumber = episodeInfo.EpisodeNumber;
+
+ if (episode.IndexNumber.HasValue)
+ {
+ changed = true;
+ }
+ }
+
+ if (!episode.IndexNumberEnd.HasValue)
+ {
+ episode.IndexNumberEnd = episodeInfo.EndingEpsiodeNumber;
+
+ if (episode.IndexNumberEnd.HasValue)
+ {
+ changed = true;
+ }
+ }
+
+ if (!episode.ParentIndexNumber.HasValue)
+ {
+ episode.ParentIndexNumber = episodeInfo.SeasonNumber;
+
+ if (!episode.ParentIndexNumber.HasValue)
+ {
+ var season = episode.Season;
+
+ if (season != null)
+ {
+ episode.ParentIndexNumber = season.IndexNumber;
+ }
+ }
+
+ if (episode.ParentIndexNumber.HasValue)
+ {
+ changed = true;
+ }
+ }
+ }
+
+ return changed;
}
public ItemLookupInfo ParseName(string name)
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
index f32ed2b20..0f703cb22 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
@@ -37,7 +37,11 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
/// <value>The priority.</value>
public override ResolverPriority Priority
{
- get { return ResolverPriority.Third; } // we need to be ahead of the generic folder resolver but behind the movie one
+ get
+ {
+ // Behind special folder resolver
+ return ResolverPriority.Second;
+ }
}
/// <summary>
@@ -49,21 +53,13 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
{
if (!args.IsDirectory) return null;
- //Avoid mis-identifying top folders
- if (args.Parent == null) return null;
+ // Avoid mis-identifying top folders
if (args.Parent.IsRoot) return null;
if (args.HasParent<MusicAlbum>()) return null;
- // Optimization
- if (args.HasParent<BoxSet>() || args.HasParent<Series>() || args.HasParent<Season>())
- {
- return null;
- }
-
var collectionType = args.GetCollectionType();
- var isMusicMediaFolder = string.Equals(collectionType, CollectionType.Music,
- StringComparison.OrdinalIgnoreCase);
+ var isMusicMediaFolder = string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase);
// If there's a collection type and it's not music, don't allow it.
if (!isMusicMediaFolder)
@@ -125,14 +121,28 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
ILibraryManager libraryManager)
{
var discSubfolderCount = 0;
+ var notMultiDisc = false;
foreach (var fileSystemInfo in list)
{
if ((fileSystemInfo.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
{
- if (allowSubfolders && IsAlbumSubfolder(fileSystemInfo, directoryService, logger, fileSystem, libraryManager))
+ if (allowSubfolders)
{
- discSubfolderCount++;
+ var path = fileSystemInfo.FullName;
+ var isMultiDisc = IsMultiDiscFolder(path);
+ var hasMusic = ContainsMusic(directoryService.GetFileSystemEntries(path), false, directoryService, logger, fileSystem, libraryManager);
+
+ if (isMultiDisc && hasMusic)
+ {
+ logger.Debug("Found multi-disc folder: " + path);
+ discSubfolderCount++;
+ }
+ else if (hasMusic)
+ {
+ // If there are folders underneath with music that are not multidisc, then this can't be a multi-disc album
+ notMultiDisc = true;
+ }
}
}
@@ -144,34 +154,15 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
}
}
- return discSubfolderCount > 0;
- }
-
- private static bool IsAlbumSubfolder(FileSystemInfo directory, IDirectoryService directoryService, ILogger logger, IFileSystem fileSystem, ILibraryManager libraryManager)
- {
- var path = directory.FullName;
-
- if (IsMultiDiscFolder(path))
+ if (notMultiDisc)
{
- logger.Debug("Found multi-disc folder: " + path);
-
- return ContainsMusic(directoryService.GetFileSystemEntries(path), false, directoryService, logger, fileSystem, libraryManager);
+ return false;
}
- return false;
- }
-
- public static bool IsMultiDiscFolder(string path)
- {
- return IsMultiDiscAlbumFolder(path);
+ return discSubfolderCount > 0 && discSubfolderCount > 10;
}
- /// <summary>
- /// Determines whether [is multi disc album folder] [the specified path].
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns><c>true</c> if [is multi disc album folder] [the specified path]; otherwise, <c>false</c>.</returns>
- private static bool IsMultiDiscAlbumFolder(string path)
+ private static bool IsMultiDiscFolder(string path)
{
var parser = new AlbumParser(new ExtendedNamingOptions(), new Naming.Logging.NullLogger());
var result = parser.ParseMultiPart(path);
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
index 71b6c0843..edbc87415 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
@@ -34,7 +34,11 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
/// <value>The priority.</value>
public override ResolverPriority Priority
{
- get { return ResolverPriority.Third; } // we need to be ahead of the generic folder resolver but behind the movie one
+ get
+ {
+ // Behind special folder resolver
+ return ResolverPriority.Second;
+ }
}
/// <summary>
@@ -46,8 +50,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
{
if (!args.IsDirectory) return null;
- //Avoid mis-identifying top folders
- if (args.Parent == null) return null;
+ // Avoid mis-identifying top folders
if (args.Parent.IsRoot) return null;
// Don't allow nested artists
@@ -56,16 +59,9 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
return null;
}
- // Optimization
- if (args.HasParent<BoxSet>() || args.HasParent<Series>() || args.HasParent<Season>())
- {
- return null;
- }
-
var collectionType = args.GetCollectionType();
- var isMusicMediaFolder = string.Equals(collectionType, CollectionType.Music,
- StringComparison.OrdinalIgnoreCase);
+ var isMusicMediaFolder = string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase);
// If there's a collection type and it's not music, it can't be a series
if (!isMusicMediaFolder)
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs
index 166465f72..34237622d 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs
@@ -1,10 +1,6 @@
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Resolvers;
-using System;
-using System.IO;
-using System.Linq;
namespace MediaBrowser.Server.Implementations.Library.Resolvers
{
@@ -13,13 +9,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
/// </summary>
public class FolderResolver : FolderResolver<Folder>
{
- private readonly IFileSystem _fileSystem;
-
- public FolderResolver(IFileSystem fileSystem)
- {
- _fileSystem = fileSystem;
- }
-
/// <summary>
/// Gets the priority.
/// </summary>
@@ -38,48 +27,11 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
{
if (args.IsDirectory)
{
- if (args.IsPhysicalRoot)
- {
- return new AggregateFolder();
- }
- if (args.IsRoot)
- {
- return new UserRootFolder(); //if we got here and still a root - must be user root
- }
- if (args.IsVf)
- {
- return new CollectionFolder
- {
- CollectionType = GetCollectionType(args)
- };
- }
-
return new Folder();
}
return null;
}
-
- private string GetCollectionType(ItemResolveArgs args)
- {
- return args.FileSystemChildren
- .Where(i =>
- {
-
- try
- {
- return (i.Attributes & FileAttributes.Directory) != FileAttributes.Directory &&
- string.Equals(".collection", i.Extension, StringComparison.OrdinalIgnoreCase);
- }
- catch (IOException)
- {
- return false;
- }
-
- })
- .Select(i => _fileSystem.GetFileNameWithoutExtension(i))
- .FirstOrDefault();
- }
}
/// <summary>
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs
index cc261c3e7..67b9d546f 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs
@@ -4,6 +4,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities;
using System;
using System.IO;
+using System.Linq;
namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
{
@@ -30,12 +31,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
{
return null;
}
-
- // This is a bit of a one-off but it's here to combat MCM's over-aggressive placement of collection.xml files where they don't belong, including in series folders.
- if (args.ContainsMetaFileByName("series.xml"))
- {
- return null;
- }
if (filename.IndexOf("[boxset]", StringComparison.OrdinalIgnoreCase) != -1 ||
args.ContainsFileSystemEntryByName("collection.xml"))
@@ -51,6 +46,17 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
return null;
}
+ private bool IsInvalid(string collectionType)
+ {
+ var validCollectionTypes = new[]
+ {
+ CollectionType.Movies,
+ CollectionType.BoxSets
+ };
+
+ return !validCollectionTypes.Contains(collectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
+ }
+
/// <summary>
/// Sets the initial item values.
/// </summary>
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
index 276b99d3a..587c6668c 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
@@ -1,13 +1,9 @@
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
using MediaBrowser.Naming.Common;
using MediaBrowser.Naming.IO;
using MediaBrowser.Naming.Video;
@@ -23,16 +19,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
/// </summary>
public class MovieResolver : BaseVideoResolver<Video>, IMultiItemResolver
{
- private readonly IServerApplicationPaths _applicationPaths;
- private readonly ILogger _logger;
- private readonly IFileSystem _fileSystem;
-
- public MovieResolver(ILibraryManager libraryManager, IServerApplicationPaths applicationPaths, ILogger logger, IFileSystem fileSystem)
- : base(libraryManager)
+ public MovieResolver(ILibraryManager libraryManager) : base(libraryManager)
{
- _applicationPaths = applicationPaths;
- _logger = logger;
- _fileSystem = fileSystem;
}
/// <summary>
@@ -63,12 +51,12 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
{
- return ResolveVideos<MusicVideo>(parent, files, directoryService, collectionType);
+ return ResolveVideos<MusicVideo>(parent, files, directoryService, collectionType, false);
}
if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase))
{
- return ResolveVideos<Video>(parent, files, directoryService, collectionType);
+ return ResolveVideos<Video>(parent, files, directoryService, collectionType, false);
}
if (string.IsNullOrEmpty(collectionType))
@@ -76,22 +64,21 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
// Owned items should just use the plain video type
if (parent == null)
{
- return ResolveVideos<Video>(parent, files, directoryService, collectionType);
+ return ResolveVideos<Video>(parent, files, directoryService, collectionType, false);
}
- return ResolveVideos<Movie>(parent, files, directoryService, collectionType);
+ return ResolveVideos<Video>(parent, files, directoryService, collectionType, false);
}
- if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase) ||
- string.Equals(collectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
{
- return ResolveVideos<Movie>(parent, files, directoryService, collectionType);
+ return ResolveVideos<Movie>(parent, files, directoryService, collectionType, false);
}
return null;
}
- private MultiItemResolverResult ResolveVideos<T>(Folder parent, IEnumerable<FileSystemInfo> fileSystemEntries, IDirectoryService directoryService, string collectionType)
+ private MultiItemResolverResult ResolveVideos<T>(Folder parent, IEnumerable<FileSystemInfo> fileSystemEntries, IDirectoryService directoryService, string collectionType, bool suppportMultiEditions)
where T : Video, new()
{
var files = new List<FileSystemInfo>();
@@ -117,7 +104,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
FullName = i.FullName,
Type = FileInfoType.File
- }).ToList()).ToList();
+ }).ToList(), suppportMultiEditions).ToList();
var result = new MultiItemResolverResult
{
@@ -137,7 +124,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
IsInMixedFolder = isInMixedFolder,
ProductionYear = video.Year,
Name = video.Name,
- AdditionalParts = video.Files.Skip(1).Select(i => i.Path).ToList()
+ AdditionalParts = video.Files.Skip(1).Select(i => i.Path).ToList(),
+ LocalAlternateVersions = video.AlternateVersions.Select(i => i.Path).ToList()
};
SetVideoType(videoItem, firstVideo);
@@ -168,12 +156,12 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
{
if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
{
- return FindMovie<MusicVideo>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, collectionType, false);
+ return FindMovie<MusicVideo>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, collectionType);
}
if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase))
{
- return FindMovie<Video>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, collectionType, false);
+ return FindMovie<Video>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, collectionType);
}
if (string.IsNullOrEmpty(collectionType))
@@ -184,17 +172,10 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
return FindMovie<Video>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, collectionType);
}
- // Since the looping is expensive, this is an optimization to help us avoid it
- if (args.ContainsMetaFileByName("series.xml"))
- {
- return null;
- }
-
- return FindMovie<Movie>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, collectionType);
+ return FindMovie<Video>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, collectionType);
}
- if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase) ||
- string.Equals(collectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
{
return FindMovie<Movie>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, collectionType);
}
@@ -216,8 +197,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
}
// To find a movie file, the collection type must be movies or boxsets
- else if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase) ||
- string.Equals(collectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase))
+ else if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
{
item = ResolveVideo<Movie>(args, true);
}
@@ -228,7 +208,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
}
else if (string.IsNullOrEmpty(collectionType))
{
- item = ResolveVideo<Movie>(args, false);
+ item = ResolveVideo<Video>(args, false);
}
if (item != null)
@@ -277,9 +257,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
/// <param name="fileSystemEntries">The file system entries.</param>
/// <param name="directoryService">The directory service.</param>
/// <param name="collectionType">Type of the collection.</param>
- /// <param name="supportMultiVersion">if set to <c>true</c> [support multi version].</param>
/// <returns>Movie.</returns>
- private T FindMovie<T>(string path, Folder parent, List<FileSystemInfo> fileSystemEntries, IDirectoryService directoryService, string collectionType, bool supportMultiVersion = true)
+ private T FindMovie<T>(string path, Folder parent, List<FileSystemInfo> fileSystemEntries, IDirectoryService directoryService, string collectionType)
where T : Video, new()
{
var multiDiscFolders = new List<FileSystemInfo>();
@@ -325,34 +304,17 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
return movie;
}
}
-
- var result = ResolveVideos<T>(parent, fileSystemEntries, directoryService, collectionType);
- // Test for multi-editions
- if (result.Items.Count > 1 && supportMultiVersion)
- {
- var filenamePrefix = Path.GetFileName(path);
+ var supportsMultiVersion = !string.Equals(collectionType, CollectionType.HomeVideos) &&
+ !string.Equals(collectionType, CollectionType.MusicVideos);
- if (!string.IsNullOrWhiteSpace(filenamePrefix))
- {
- if (result.Items.All(i => _fileSystem.GetFileNameWithoutExtension(i.Path).StartsWith(filenamePrefix + " - ", StringComparison.OrdinalIgnoreCase)))
- {
- var movie = (T)result.Items[0];
- movie.Name = filenamePrefix;
- movie.LocalAlternateVersions = result.Items.Skip(1).Select(i => i.Path).ToList();
- movie.IsInMixedFolder = false;
-
- _logger.Debug("Multi-version video found: " + movie.Path);
-
- return movie;
- }
- }
- }
+ var result = ResolveVideos<T>(parent, fileSystemEntries, directoryService, collectionType, supportsMultiVersion);
if (result.Items.Count == 1)
{
var movie = (T)result.Items[0];
movie.IsInMixedFolder = false;
+ movie.Name = Path.GetFileName(movie.ContainingFolderPath);
return movie;
}
@@ -453,52 +415,16 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
}
}
- // Don't do any resolving within a series structure
- if (string.IsNullOrEmpty(collectionType))
- {
- if (HasParent<Series>(parent) || HasParent<Season>(parent))
- {
- return true;
- }
-
- // Since the looping is expensive, this is an optimization to help us avoid it
- if (files.Select(i => i.Name).Contains("series.xml", StringComparer.OrdinalIgnoreCase))
- {
- return true;
- }
- }
-
var validCollectionTypes = new[]
{
string.Empty,
CollectionType.Movies,
CollectionType.HomeVideos,
CollectionType.MusicVideos,
- CollectionType.BoxSets,
CollectionType.Movies
};
return !validCollectionTypes.Contains(collectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
}
-
- private bool HasParent<T>(Folder parent)
- where T : Folder
- {
- if (parent != null)
- {
- var item = parent as T;
-
- // Just in case the user decided to nest episodes.
- // Not officially supported but in some cases we can handle it.
- if (item == null)
- {
- item = parent.Parents.OfType<T>().FirstOrDefault();
- }
-
- return item != null;
-
- }
- return false;
- }
}
}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs
index 2fcfd7086..acae5b801 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Model.Entities;
using System;
using System.IO;
@@ -17,7 +18,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
protected override PhotoAlbum Resolve(ItemResolveArgs args)
{
// Must be an image file within a photo collection
- if (!args.IsRoot && args.IsDirectory && string.Equals(args.GetCollectionType(), CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
+ if (args.IsDirectory && string.Equals(args.GetCollectionType(), CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
{
if (HasPhotos(args))
{
@@ -35,5 +36,14 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
{
return args.FileSystemChildren.Any(i => ((i.Attributes & FileAttributes.Directory) != FileAttributes.Directory) && PhotoResolver.IsImageFile(i.FullName));
}
+
+ public override ResolverPriority Priority
+ {
+ get
+ {
+ // Behind special folder resolver
+ return ResolverPriority.Second;
+ }
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs
index 5580b442c..02960ea7e 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs
@@ -17,8 +17,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
protected override Photo Resolve(ItemResolveArgs args)
{
// Must be an image file within a photo collection
- if (!args.IsDirectory &&
- string.Equals(args.GetCollectionType(), CollectionType.Photos, StringComparison.OrdinalIgnoreCase) &&
+ if (string.Equals(args.GetCollectionType(), CollectionType.Photos, StringComparison.OrdinalIgnoreCase) &&
+ !args.IsDirectory &&
IsImageFile(args.Path))
{
return new Photo
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs
new file mode 100644
index 000000000..0a41a6c04
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs
@@ -0,0 +1,79 @@
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Resolvers;
+using System;
+using System.IO;
+using System.Linq;
+
+namespace MediaBrowser.Server.Implementations.Library.Resolvers
+{
+ class SpecialFolderResolver : FolderResolver<Folder>
+ {
+ private readonly IFileSystem _fileSystem;
+
+ public SpecialFolderResolver(IFileSystem fileSystem)
+ {
+ _fileSystem = fileSystem;
+ }
+
+ /// <summary>
+ /// Gets the priority.
+ /// </summary>
+ /// <value>The priority.</value>
+ public override ResolverPriority Priority
+ {
+ get { return ResolverPriority.First; }
+ }
+
+ /// <summary>
+ /// Resolves the specified args.
+ /// </summary>
+ /// <param name="args">The args.</param>
+ /// <returns>Folder.</returns>
+ protected override Folder Resolve(ItemResolveArgs args)
+ {
+ if (args.IsDirectory)
+ {
+ if (args.IsPhysicalRoot)
+ {
+ return new AggregateFolder();
+ }
+ if (args.IsRoot)
+ {
+ return new UserRootFolder(); //if we got here and still a root - must be user root
+ }
+ if (args.IsVf)
+ {
+ return new CollectionFolder
+ {
+ CollectionType = GetCollectionType(args)
+ };
+ }
+ }
+
+ return null;
+ }
+
+ private string GetCollectionType(ItemResolveArgs args)
+ {
+ return args.FileSystemChildren
+ .Where(i =>
+ {
+
+ try
+ {
+ return (i.Attributes & FileAttributes.Directory) != FileAttributes.Directory &&
+ string.Equals(".collection", i.Extension, StringComparison.OrdinalIgnoreCase);
+ }
+ catch (IOException)
+ {
+ return false;
+ }
+
+ })
+ .Select(i => _fileSystem.GetFileNameWithoutExtension(i))
+ .FirstOrDefault();
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
index 057425ca9..1a873f01e 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
@@ -37,23 +37,10 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
}
// If the parent is a Season or Series, then this is an Episode if the VideoResolver returns something
- if (season != null || parent is Series || parent.Parents.OfType<Series>().Any())
+ if (season != null || args.HasParent<Series>())
{
var episode = ResolveVideo<Episode>(args, false);
- if (episode != null)
- {
- if (season != null)
- {
- episode.ParentIndexNumber = season.IndexNumber;
- }
-
- if (episode.ParentIndexNumber == null)
- {
- episode.ParentIndexNumber = SeriesResolver.GetSeasonNumberFromEpisodeFile(args.Path);
- }
- }
-
return episode;
}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
index 058fb1489..80477e567 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
@@ -1,7 +1,8 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Entities;
+using MediaBrowser.Naming.Common;
+using MediaBrowser.Naming.TV;
namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
{
@@ -35,7 +36,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
{
var season = new Season
{
- IndexNumber = SeriesResolver.GetSeasonNumberFromPath(args.Path, CollectionType.TvShows)
+ IndexNumber = new SeasonPathParser(new ExtendedNamingOptions(), new RegexProvider()).Parse(args.Path, true).SeasonNumber
};
if (season.IndexNumber.HasValue && season.IndexNumber.Value == 0)
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
index 72c0bae53..7f1416ad6 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
@@ -1,18 +1,9 @@
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
using System;
-using System.Collections.Generic;
-using System.Globalization;
using System.IO;
-using System.Linq;
-using System.Text.RegularExpressions;
namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
{
@@ -21,17 +12,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
/// </summary>
public class SeriesResolver : FolderResolver<Series>
{
- private readonly IFileSystem _fileSystem;
- private readonly ILogger _logger;
- private readonly ILibraryManager _libraryManager;
-
- public SeriesResolver(IFileSystem fileSystem, ILogger logger, ILibraryManager libraryManager)
- {
- _fileSystem = fileSystem;
- _logger = logger;
- _libraryManager = libraryManager;
- }
-
/// <summary>
/// Gets the priority.
/// </summary>
@@ -53,33 +33,16 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
{
if (args.IsDirectory)
{
- // Avoid expensive tests against VF's and all their children by not allowing this
- if (args.Parent == null || args.Parent.IsRoot)
- {
- return null;
- }
-
- // Optimization to avoid running these tests against Seasons
- if (args.HasParent<Series>() || args.HasParent<Season>() || args.HasParent<MusicArtist>() || args.HasParent<MusicAlbum>())
- {
- return null;
- }
-
var collectionType = args.GetCollectionType();
- var isTvShowsFolder = string.Equals(collectionType, CollectionType.TvShows,
- StringComparison.OrdinalIgnoreCase);
-
// If there's a collection type and it's not tv, it can't be a series
- if (!string.IsNullOrEmpty(collectionType) &&
- !isTvShowsFolder &&
- !string.Equals(collectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase))
- {
- return null;
- }
-
- if (IsSeriesFolder(args.Path, collectionType, args.FileSystemChildren, args.DirectoryService, _fileSystem, _logger, _libraryManager))
+ if (string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
{
+ if (args.HasParent<Series>())
+ {
+ return null;
+ }
+
return new Series
{
Path = args.Path,
@@ -92,434 +55,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
}
/// <summary>
- /// Determines whether [is series folder] [the specified path].
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="collectionType">Type of the collection.</param>
- /// <param name="fileSystemChildren">The file system children.</param>
- /// <param name="directoryService">The directory service.</param>
- /// <param name="fileSystem">The file system.</param>
- /// <param name="logger">The logger.</param>
- /// <param name="libraryManager">The library manager.</param>
- /// <returns><c>true</c> if [is series folder] [the specified path]; otherwise, <c>false</c>.</returns>
- public static bool IsSeriesFolder(string path, string collectionType, IEnumerable<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService, IFileSystem fileSystem, ILogger logger, ILibraryManager libraryManager)
- {
- foreach (var child in fileSystemChildren)
- {
- var attributes = child.Attributes;
-
- if ((attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
- {
- //logger.Debug("Igoring series file or folder marked hidden: {0}", child.FullName);
- continue;
- }
-
- // Can't enforce this because files saved by Bitcasa are always marked System
- //if ((attributes & FileAttributes.System) == FileAttributes.System)
- //{
- // logger.Debug("Igoring series subfolder marked system: {0}", child.FullName);
- // continue;
- //}
-
- if ((attributes & FileAttributes.Directory) == FileAttributes.Directory)
- {
- if (IsSeasonFolder(child.FullName, collectionType, directoryService, fileSystem))
- {
- //logger.Debug("{0} is a series because of season folder {1}.", path, child.FullName);
- return true;
- }
- }
- else
- {
- var fullName = child.FullName;
-
- if (libraryManager.IsVideoFile(fullName) || IsVideoPlaceHolder(fullName))
- {
- var isTvShowsFolder = string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase);
-
- if (GetEpisodeNumberFromFile(fullName, isTvShowsFolder).HasValue)
- {
- return true;
- }
- }
- }
- }
-
- logger.Debug("{0} is not a series folder.", path);
- return false;
- }
-
- /// <summary>
- /// Determines whether [is place holder] [the specified path].
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns><c>true</c> if [is place holder] [the specified path]; otherwise, <c>false</c>.</returns>
- /// <exception cref="System.ArgumentNullException">path</exception>
- private static bool IsVideoPlaceHolder(string path)
- {
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentNullException("path");
- }
-
- var extension = Path.GetExtension(path);
-
- return string.Equals(extension, ".disc", StringComparison.OrdinalIgnoreCase);
- }
-
- /// <summary>
- /// Determines whether [is season folder] [the specified path].
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="collectionType">Type of the collection.</param>
- /// <param name="directoryService">The directory service.</param>
- /// <param name="fileSystem">The file system.</param>
- /// <returns><c>true</c> if [is season folder] [the specified path]; otherwise, <c>false</c>.</returns>
- private static bool IsSeasonFolder(string path, string collectionType, IDirectoryService directoryService, IFileSystem fileSystem)
- {
- var seasonNumber = GetSeasonNumberFromPath(path, collectionType);
- var hasSeasonNumber = seasonNumber != null;
-
- if (!hasSeasonNumber)
- {
- return false;
- }
-
- //// It's a season folder if it's named as such and does not contain any audio files, apart from theme.mp3
- //foreach (var fileSystemInfo in directoryService.GetFileSystemEntries(path))
- //{
- // var attributes = fileSystemInfo.Attributes;
-
- // if ((attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
- // {
- // continue;
- // }
-
- // // Can't enforce this because files saved by Bitcasa are always marked System
- // //if ((attributes & FileAttributes.System) == FileAttributes.System)
- // //{
- // // continue;
- // //}
-
- // if ((attributes & FileAttributes.Directory) == FileAttributes.Directory)
- // {
- // //if (IsBadFolder(fileSystemInfo.Name))
- // //{
- // // return false;
- // //}
- // }
- // else
- // {
- // if (EntityResolutionHelper.IsAudioFile(fileSystemInfo.FullName) &&
- // !string.Equals(fileSystem.GetFileNameWithoutExtension(fileSystemInfo), BaseItem.ThemeSongFilename))
- // {
- // return false;
- // }
- // }
- //}
-
- return true;
- }
-
- /// <summary>
- /// A season folder must contain one of these somewhere in the name
- /// </summary>
- private static readonly string[] SeasonFolderNames =
- {
- "season",
- "sæson",
- "temporada",
- "saison",
- "staffel",
- "series",
- "сезон"
- };
-
- /// <summary>
- /// Used to detect paths that represent episodes, need to make sure they don't also
- /// match movie titles like "2001 A Space..."
- /// Currently we limit the numbers here to 2 digits to try and avoid this
- /// </summary>
- private static readonly Regex[] EpisodeExpressions =
- {
- new Regex(
- @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)[sS](?<seasonnumber>\d{1,4})[x,X]?[eE](?<epnumber>\d{1,3})[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>\d{1,4})[xX\.]?[eE](?<epnumber>\d{1,3})[^\\\/]*$",
- RegexOptions.Compiled)
- };
- private static readonly Regex[] MultipleEpisodeExpressions =
- {
- new Regex(
- @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})((-| - )\d{1,4}[eExX](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})((-| - )\d{1,4}[xX][eE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})((-| - )?[xXeE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})(-[xE]?[eE]?(?<endingepnumber>\d{1,3}))+[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))((-| - )\d{1,4}[xXeE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))((-| - )\d{1,4}[xX][eE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))((-| - )?[xXeE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))(-[xX]?[eE]?(?<endingepnumber>\d{1,3}))+[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>\d{1,4})[xX\.]?[eE](?<epnumber>\d{1,3})((-| - )?[xXeE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>\d{1,4})[xX\.]?[eE](?<epnumber>\d{1,3})(-[xX]?[eE]?(?<endingepnumber>\d{1,3}))+[^\\\/]*$",
- RegexOptions.Compiled)
- };
-
- /// <summary>
- /// To avoid the following matching movies they are only valid when contained in a folder which has been matched as a being season, or the media type is TV series
- /// </summary>
- private static readonly Regex[] EpisodeExpressionsWithoutSeason =
- {
- new Regex(
- @".*[\\\/](?<epnumber>\d{1,3})(-(?<endingepnumber>\d{2,3}))*\.\w+$",
- RegexOptions.Compiled),
- // "01.avi"
- new Regex(
- @".*(\\|\/)(?<epnumber>\d{1,3})(-(?<endingepnumber>\d{2,3}))*\s?-\s?[^\\\/]*$",
- RegexOptions.Compiled),
- // "01 - blah.avi", "01-blah.avi"
- new Regex(
- @".*(\\|\/)(?<epnumber>\d{1,3})(-(?<endingepnumber>\d{2,3}))*\.[^\\\/]+$",
- RegexOptions.Compiled),
- // "01.blah.avi"
- new Regex(
- @".*[\\\/][^\\\/]* - (?<epnumber>\d{1,3})(-(?<endingepnumber>\d{2,3}))*[^\\\/]*$",
- RegexOptions.Compiled),
- // "blah - 01.avi", "blah 2 - 01.avi", "blah - 01 blah.avi", "blah 2 - 01 blah", "blah - 01 - blah.avi", "blah 2 - 01 - blah"
- };
-
- public static int? GetSeasonNumberFromPath(string path)
- {
- return GetSeasonNumberFromPath(path, CollectionType.TvShows);
- }
-
- /// <summary>
- /// Gets the season number from path.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="collectionType">Type of the collection.</param>
- /// <returns>System.Nullable{System.Int32}.</returns>
- public static int? GetSeasonNumberFromPath(string path, string collectionType)
- {
- var filename = Path.GetFileName(path);
-
- if (string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
- {
- if (string.Equals(filename, "specials", StringComparison.OrdinalIgnoreCase))
- {
- return 0;
- }
- }
-
- int val;
- if (int.TryParse(filename, NumberStyles.Integer, CultureInfo.InvariantCulture, out val))
- {
- return val;
- }
-
- if (filename.StartsWith("s", StringComparison.OrdinalIgnoreCase))
- {
- var testFilename = filename.Substring(1);
-
- if (int.TryParse(testFilename, NumberStyles.Integer, CultureInfo.InvariantCulture, out val))
- {
- return val;
- }
- }
-
- // Look for one of the season folder names
- foreach (var name in SeasonFolderNames)
- {
- var index = filename.IndexOf(name, StringComparison.OrdinalIgnoreCase);
-
- if (index != -1)
- {
- return GetSeasonNumberFromPathSubstring(filename.Substring(index + name.Length));
- }
- }
-
- return null;
- }
-
- /// <summary>
- /// Extracts the season number from the second half of the Season folder name (everything after "Season", or "Staffel")
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>System.Nullable{System.Int32}.</returns>
- private static int? GetSeasonNumberFromPathSubstring(string path)
- {
- var numericStart = -1;
- var length = 0;
-
- // Find out where the numbers start, and then keep going until they end
- for (var i = 0; i < path.Length; i++)
- {
- if (char.IsNumber(path, i))
- {
- if (numericStart == -1)
- {
- numericStart = i;
- }
- length++;
- }
- else if (numericStart != -1)
- {
- break;
- }
- }
-
- if (numericStart == -1)
- {
- return null;
- }
-
- return int.Parse(path.Substring(numericStart, length), CultureInfo.InvariantCulture);
- }
-
- /// <summary>
- /// Episodes the number from file.
- /// </summary>
- /// <param name="fullPath">The full path.</param>
- /// <param name="considerSeasonlessNames">if set to <c>true</c> [is in season].</param>
- /// <returns>System.String.</returns>
- public static int? GetEpisodeNumberFromFile(string fullPath, bool considerSeasonlessNames)
- {
- string fl = fullPath.ToLower();
- foreach (var r in EpisodeExpressions)
- {
- Match m = r.Match(fl);
- if (m.Success)
- return ParseEpisodeNumber(m.Groups["epnumber"].Value);
- }
- if (considerSeasonlessNames)
- {
- var match = EpisodeExpressionsWithoutSeason.Select(r => r.Match(fl))
- .FirstOrDefault(m => m.Success);
-
- if (match != null)
- {
- return ParseEpisodeNumber(match.Groups["epnumber"].Value);
- }
- }
-
- return null;
- }
-
- public static int? GetEndingEpisodeNumberFromFile(string fullPath)
- {
- var fl = fullPath.ToLower();
- foreach (var r in MultipleEpisodeExpressions)
- {
- var m = r.Match(fl);
- if (m.Success && !string.IsNullOrEmpty(m.Groups["endingepnumber"].Value))
- return ParseEpisodeNumber(m.Groups["endingepnumber"].Value);
- }
- foreach (var r in EpisodeExpressionsWithoutSeason)
- {
- var m = r.Match(fl);
- if (m.Success && !string.IsNullOrEmpty(m.Groups["endingepnumber"].Value))
- return ParseEpisodeNumber(m.Groups["endingepnumber"].Value);
- }
- return null;
- }
-
- /// <summary>
- /// Seasons the number from episode file.
- /// </summary>
- /// <param name="fullPath">The full path.</param>
- /// <returns>System.String.</returns>
- public static int? GetSeasonNumberFromEpisodeFile(string fullPath)
- {
- string fl = fullPath.ToLower();
- foreach (var r in EpisodeExpressions)
- {
- Match m = r.Match(fl);
- if (m.Success)
- {
- Group g = m.Groups["seasonnumber"];
- if (g != null)
- {
- var val = g.Value;
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- int num;
-
- if (int.TryParse(val, NumberStyles.Integer, UsCulture, out num))
- {
- return num;
- }
- }
- }
- return null;
- }
- }
- return null;
- }
-
- public static string GetSeriesNameFromEpisodeFile(string fullPath)
- {
- var fl = fullPath.ToLower();
- foreach (var r in EpisodeExpressions)
- {
- var m = r.Match(fl);
- if (m.Success)
- {
- var g = m.Groups["seriesname"];
- if (g != null)
- {
- var val = g.Value;
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- return val;
- }
- }
- return null;
- }
- }
- return null;
- }
-
- private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- private static int? ParseEpisodeNumber(string val)
- {
- int num;
-
- if (!string.IsNullOrEmpty(val) && int.TryParse(val, NumberStyles.Integer, UsCulture, out num))
- {
- return num;
- }
-
- return null;
- }
-
- /// <summary>
/// Sets the initial item values.
/// </summary>
/// <param name="item">The item.</param>
diff --git a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs
index bd845ef4a..071031b25 100644
--- a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs
+++ b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Querying;
@@ -105,7 +106,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (query.IncludeMedia)
{
// Add search hints based on item name
- hints.AddRange(items.Where(i => !string.IsNullOrWhiteSpace(i.Name)).Select(item =>
+ hints.AddRange(items.Where(i => !string.IsNullOrWhiteSpace(i.Name) && IncludeInSearch(i)).Select(item =>
{
var index = GetIndex(item.Name, searchTerm, terms);
@@ -289,6 +290,20 @@ namespace MediaBrowser.Server.Implementations.Library
return Task.FromResult(returnValue);
}
+ private bool IncludeInSearch(BaseItem item)
+ {
+ var episode = item as Episode;
+
+ if (episode != null)
+ {
+ if (episode.IsVirtualUnaired || episode.IsMissingEpisode)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
/// <summary>
/// Gets the index.
/// </summary>
diff --git a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs
index 3f132ab7f..ed3503c1b 100644
--- a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs
@@ -1,6 +1,8 @@
using System.Collections.Generic;
using MediaBrowser.Common.Events;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Dto;
@@ -23,9 +25,11 @@ namespace MediaBrowser.Server.Implementations.Library
private readonly ConcurrentDictionary<string, UserItemData> _userData = new ConcurrentDictionary<string, UserItemData>();
private readonly ILogger _logger;
+ private readonly IServerConfigurationManager _config;
- public UserDataManager(ILogManager logManager)
+ public UserDataManager(ILogManager logManager, IServerConfigurationManager config)
{
+ _config = config;
_logger = logManager.GetLogger(GetType().Name);
}
@@ -35,22 +39,6 @@ namespace MediaBrowser.Server.Implementations.Library
/// <value>The repository.</value>
public IUserDataRepository Repository { get; set; }
- /// <summary>
- /// Saves the user data.
- /// </summary>
- /// <param name="userId">The user id.</param>
- /// <param name="item">The item.</param>
- /// <param name="userData">The user data.</param>
- /// <param name="reason">The reason.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- /// <exception cref="System.ArgumentNullException">userData
- /// or
- /// cancellationToken
- /// or
- /// userId
- /// or
- /// key</exception>
public async Task SaveUserData(Guid userId, IHasUserData item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken)
{
if (userData == null)
@@ -219,5 +207,59 @@ namespace MediaBrowser.Server.Implementations.Library
Key = data.Key
};
}
+
+ public bool UpdatePlayState(BaseItem item, UserItemData data, long positionTicks)
+ {
+ var playedToCompletion = false;
+
+ var hasRuntime = item.RunTimeTicks.HasValue && item.RunTimeTicks > 0;
+
+ // If a position has been reported, and if we know the duration
+ if (positionTicks > 0 && hasRuntime)
+ {
+ var pctIn = Decimal.Divide(positionTicks, item.RunTimeTicks.Value) * 100;
+
+ // Don't track in very beginning
+ if (pctIn < _config.Configuration.MinResumePct)
+ {
+ positionTicks = 0;
+ }
+
+ // If we're at the end, assume completed
+ else if (pctIn > _config.Configuration.MaxResumePct || positionTicks >= item.RunTimeTicks.Value)
+ {
+ positionTicks = 0;
+ data.Played = playedToCompletion = true;
+ }
+
+ else
+ {
+ // Enforce MinResumeDuration
+ var durationSeconds = TimeSpan.FromTicks(item.RunTimeTicks.Value).TotalSeconds;
+
+ if (durationSeconds < _config.Configuration.MinResumeDurationSeconds)
+ {
+ positionTicks = 0;
+ data.Played = playedToCompletion = true;
+ }
+ }
+ }
+ else if (!hasRuntime)
+ {
+ // If we don't know the runtime we'll just have to assume it was fully played
+ data.Played = playedToCompletion = true;
+ positionTicks = 0;
+ }
+
+ if (item is Audio)
+ {
+ positionTicks = 0;
+ }
+
+ data.PlaybackPositionTicks = positionTicks;
+
+ return playedToCompletion;
+ }
+
}
}
diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs
index 791cae553..503af4970 100644
--- a/MediaBrowser.Server.Implementations/Library/UserManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs
@@ -1,5 +1,4 @@
-using System.Collections.Concurrent;
-using MediaBrowser.Common.Events;
+using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
@@ -63,6 +62,7 @@ namespace MediaBrowser.Server.Implementations.Library
public event EventHandler<GenericEventArgs<User>> UserPasswordChanged;
private readonly IXmlSerializer _xmlSerializer;
+ private readonly IJsonSerializer _jsonSerializer;
private readonly INetworkManager _networkManager;
@@ -71,13 +71,7 @@ namespace MediaBrowser.Server.Implementations.Library
private readonly Func<IConnectManager> _connectFactory;
private readonly IServerApplicationHost _appHost;
- /// <summary>
- /// Initializes a new instance of the <see cref="UserManager" /> class.
- /// </summary>
- /// <param name="logger">The logger.</param>
- /// <param name="configurationManager">The configuration manager.</param>
- /// <param name="userRepository">The user repository.</param>
- public UserManager(ILogger logger, IServerConfigurationManager configurationManager, IUserRepository userRepository, IXmlSerializer xmlSerializer, INetworkManager networkManager, Func<IImageProcessor> imageProcessorFactory, Func<IDtoService> dtoServiceFactory, Func<IConnectManager> connectFactory, IServerApplicationHost appHost)
+ public UserManager(ILogger logger, IServerConfigurationManager configurationManager, IUserRepository userRepository, IXmlSerializer xmlSerializer, INetworkManager networkManager, Func<IImageProcessor> imageProcessorFactory, Func<IDtoService> dtoServiceFactory, Func<IConnectManager> connectFactory, IServerApplicationHost appHost, IJsonSerializer jsonSerializer)
{
_logger = logger;
UserRepository = userRepository;
@@ -87,6 +81,7 @@ namespace MediaBrowser.Server.Implementations.Library
_dtoServiceFactory = dtoServiceFactory;
_connectFactory = connectFactory;
_appHost = appHost;
+ _jsonSerializer = jsonSerializer;
ConfigurationManager = configurationManager;
Users = new List<User>();
@@ -164,6 +159,11 @@ namespace MediaBrowser.Server.Implementations.Library
public async Task Initialize()
{
Users = await LoadUsers().ConfigureAwait(false);
+
+ foreach (var user in Users.ToList())
+ {
+ await DoPolicyMigration(user).ConfigureAwait(false);
+ }
}
public Task<bool> AuthenticateUser(string username, string passwordSha1, string remoteEndPoint)
@@ -171,6 +171,38 @@ namespace MediaBrowser.Server.Implementations.Library
return AuthenticateUser(username, passwordSha1, null, remoteEndPoint);
}
+ public bool IsValidUsername(string username)
+ {
+ // Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)
+ return username.All(IsValidCharacter);
+ }
+
+ private bool IsValidCharacter(char i)
+ {
+ return char.IsLetterOrDigit(i) || char.Equals(i, '-') || char.Equals(i, '_') || char.Equals(i, '\'') ||
+ char.Equals(i, '.');
+ }
+
+ public string MakeValidUsername(string username)
+ {
+ if (IsValidUsername(username))
+ {
+ return username;
+ }
+
+ // Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)
+ var builder = new StringBuilder();
+
+ foreach (var c in username)
+ {
+ if (IsValidCharacter(c))
+ {
+ builder.Append(c);
+ }
+ }
+ return builder.ToString();
+ }
+
public async Task<bool> AuthenticateUser(string username, string passwordSha1, string passwordMd5, string remoteEndPoint)
{
if (string.IsNullOrWhiteSpace(username))
@@ -178,14 +210,15 @@ namespace MediaBrowser.Server.Implementations.Library
throw new ArgumentNullException("username");
}
- var user = Users.FirstOrDefault(i => string.Equals(username, i.Name, StringComparison.OrdinalIgnoreCase));
+ var user = Users
+ .FirstOrDefault(i => string.Equals(username, i.Name, StringComparison.OrdinalIgnoreCase));
if (user == null)
{
throw new SecurityException("Invalid username or password entered.");
}
- if (user.Configuration.IsDisabled)
+ if (user.Policy.IsDisabled)
{
throw new SecurityException(string.Format("The {0} account is currently disabled. Please consult with your administrator.", user.Name));
}
@@ -203,20 +236,6 @@ namespace MediaBrowser.Server.Implementations.Library
}
}
- // Maybe user accidently entered connect credentials. let's be flexible
- if (!success && user.ConnectLinkType.HasValue && !string.IsNullOrWhiteSpace(passwordMd5))
- {
- try
- {
- await _connectFactory().Authenticate(user.ConnectUserName, passwordMd5).ConfigureAwait(false);
- success = true;
- }
- catch
- {
-
- }
- }
-
// Update LastActivityDate and LastLoginDate, then save
if (success)
{
@@ -273,7 +292,7 @@ namespace MediaBrowser.Server.Implementations.Library
// There always has to be at least one user.
if (users.Count == 0)
{
- var name = Environment.UserName;
+ var name = MakeValidUsername(Environment.UserName);
var user = InstantiateNewUser(name, false);
@@ -283,14 +302,42 @@ namespace MediaBrowser.Server.Implementations.Library
users.Add(user);
- user.Configuration.IsAdministrator = true;
- user.Configuration.EnableRemoteControlOfOtherUsers = true;
- UpdateConfiguration(user, user.Configuration);
+ user.Policy.IsAdministrator = true;
+ user.Policy.EnableRemoteControlOfOtherUsers = true;
+ await UpdateUserPolicy(user, user.Policy, false).ConfigureAwait(false);
}
return users;
}
+ private async Task DoPolicyMigration(User user)
+ {
+ if (!user.Configuration.HasMigratedToPolicy)
+ {
+ user.Policy.AccessSchedules = user.Configuration.AccessSchedules;
+ user.Policy.BlockedChannels = user.Configuration.BlockedChannels;
+ user.Policy.BlockedMediaFolders = user.Configuration.BlockedMediaFolders;
+ user.Policy.BlockedTags = user.Configuration.BlockedTags;
+ user.Policy.BlockUnratedItems = user.Configuration.BlockUnratedItems;
+ user.Policy.EnableContentDeletion = user.Configuration.EnableContentDeletion;
+ user.Policy.EnableLiveTvAccess = user.Configuration.EnableLiveTvAccess;
+ user.Policy.EnableLiveTvManagement = user.Configuration.EnableLiveTvManagement;
+ user.Policy.EnableMediaPlayback = user.Configuration.EnableMediaPlayback;
+ user.Policy.EnableRemoteControlOfOtherUsers = user.Configuration.EnableRemoteControlOfOtherUsers;
+ user.Policy.EnableSharedDeviceControl = user.Configuration.EnableSharedDeviceControl;
+ user.Policy.EnableUserPreferenceAccess = user.Configuration.EnableUserPreferenceAccess;
+ user.Policy.IsAdministrator = user.Configuration.IsAdministrator;
+ user.Policy.IsDisabled = user.Configuration.IsDisabled;
+ user.Policy.IsHidden = user.Configuration.IsHidden;
+ user.Policy.MaxParentalRating = user.Configuration.MaxParentalRating;
+
+ await UpdateUserPolicy(user.Id.ToString("N"), user.Policy);
+
+ user.Configuration.HasMigratedToPolicy = true;
+ await UpdateConfiguration(user, user.Configuration, true).ConfigureAwait(false);
+ }
+ }
+
public UserDto GetUserDto(User user, string remoteEndPoint = null)
{
if (user == null)
@@ -449,6 +496,11 @@ namespace MediaBrowser.Server.Implementations.Library
throw new ArgumentNullException("name");
}
+ if (!IsValidUsername(name))
+ {
+ throw new ArgumentException("Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)");
+ }
+
if (Users.Any(u => u.Name.Equals(name, StringComparison.OrdinalIgnoreCase)))
{
throw new ArgumentException(string.Format("A user with the name '{0}' already exists.", name));
@@ -509,7 +561,7 @@ namespace MediaBrowser.Server.Implementations.Library
throw new ArgumentException(string.Format("The user '{0}' cannot be deleted because there must be at least one user in the system.", user.Name));
}
- if (user.Configuration.IsAdministrator && allUsers.Count(i => i.Configuration.IsAdministrator) == 1)
+ if (user.Policy.IsAdministrator && allUsers.Count(i => i.Policy.IsAdministrator) == 1)
{
throw new ArgumentException(string.Format("The user '{0}' cannot be deleted because there must be at least one admin user in the system.", user.Name));
}
@@ -518,17 +570,17 @@ namespace MediaBrowser.Server.Implementations.Library
try
{
- await UserRepository.DeleteUser(user, CancellationToken.None).ConfigureAwait(false);
+ var configPath = GetConfigurationFilePath(user);
- var path = user.ConfigurationFilePath;
+ await UserRepository.DeleteUser(user, CancellationToken.None).ConfigureAwait(false);
try
{
- File.Delete(path);
+ File.Delete(configPath);
}
catch (IOException ex)
{
- _logger.ErrorException("Error deleting file {0}", ex, path);
+ _logger.ErrorException("Error deleting file {0}", ex, configPath);
}
DeleteUserPolicy(user);
@@ -613,15 +665,6 @@ namespace MediaBrowser.Server.Implementations.Library
};
}
- public void UpdateConfiguration(User user, UserConfiguration newConfiguration)
- {
- var xmlPath = user.ConfigurationFilePath;
- Directory.CreateDirectory(Path.GetDirectoryName(xmlPath));
- _xmlSerializer.SerializeToFile(newConfiguration, xmlPath);
-
- EventHelper.FireEventIfNotNull(UserConfigurationUpdated, this, new GenericEventArgs<User> { Argument = user }, _logger);
- }
-
private string PasswordResetFile
{
get { return Path.Combine(ConfigurationManager.ApplicationPaths.ProgramDataPath, "passwordreset.txt"); }
@@ -689,7 +732,7 @@ namespace MediaBrowser.Server.Implementations.Library
string pinFile = null;
DateTime? expirationDate = null;
- if (user != null && !user.Configuration.IsAdministrator)
+ if (user != null && !user.Policy.IsAdministrator)
{
action = ForgotPasswordAction.ContactAdmin;
}
@@ -784,28 +827,72 @@ namespace MediaBrowser.Server.Implementations.Library
return (UserPolicy)_xmlSerializer.DeserializeFromFile(typeof(UserPolicy), path);
}
}
+ catch (DirectoryNotFoundException)
+ {
+ return GetDefaultPolicy(user);
+ }
+ catch (FileNotFoundException)
+ {
+ return GetDefaultPolicy(user);
+ }
catch (Exception ex)
{
_logger.ErrorException("Error reading policy file: {0}", ex, path);
- return new UserPolicy
- {
- EnableSync = !user.ConnectLinkType.HasValue || user.ConnectLinkType.Value != UserLinkType.Guest
- };
+ return GetDefaultPolicy(user);
}
}
+ private UserPolicy GetDefaultPolicy(User user)
+ {
+ return new UserPolicy
+ {
+ EnableSync = true
+ };
+ }
+
private readonly object _policySyncLock = new object();
- public async Task UpdateUserPolicy(string userId, UserPolicy userPolicy)
+ public Task UpdateUserPolicy(string userId, UserPolicy userPolicy)
{
var user = GetUserById(userId);
+ return UpdateUserPolicy(user, userPolicy, true);
+ }
+
+ private async Task UpdateUserPolicy(User user, UserPolicy userPolicy, bool fireEvent)
+ {
+ // The xml serializer will output differently if the type is not exact
+ if (userPolicy.GetType() != typeof(UserPolicy))
+ {
+ var json = _jsonSerializer.SerializeToString(userPolicy);
+ userPolicy = _jsonSerializer.DeserializeFromString<UserPolicy>(json);
+ }
+
+ var updateConfig = user.Policy.IsAdministrator != userPolicy.IsAdministrator ||
+ user.Policy.EnableLiveTvManagement != userPolicy.EnableLiveTvManagement ||
+ user.Policy.EnableLiveTvAccess != userPolicy.EnableLiveTvAccess ||
+ user.Policy.EnableMediaPlayback != userPolicy.EnableMediaPlayback ||
+ user.Policy.EnableContentDeletion != userPolicy.EnableContentDeletion;
+
var path = GetPolifyFilePath(user);
+ Directory.CreateDirectory(Path.GetDirectoryName(path));
+
lock (_policySyncLock)
{
_xmlSerializer.SerializeToFile(userPolicy, path);
user.Policy = userPolicy;
}
+
+ if (updateConfig)
+ {
+ user.Configuration.IsAdministrator = user.Policy.IsAdministrator;
+ user.Configuration.EnableLiveTvManagement = user.Policy.EnableLiveTvManagement;
+ user.Configuration.EnableLiveTvAccess = user.Policy.EnableLiveTvAccess;
+ user.Configuration.EnableMediaPlayback = user.Policy.EnableMediaPlayback;
+ user.Configuration.EnableContentDeletion = user.Policy.EnableContentDeletion;
+
+ await UpdateConfiguration(user, user.Configuration, true).ConfigureAwait(false);
+ }
}
private void DeleteUserPolicy(User user)
@@ -833,5 +920,69 @@ namespace MediaBrowser.Server.Implementations.Library
{
return Path.Combine(user.ConfigurationDirectoryPath, "policy.xml");
}
+
+ private string GetConfigurationFilePath(User user)
+ {
+ return Path.Combine(user.ConfigurationDirectoryPath, "config.xml");
+ }
+
+ public UserConfiguration GetUserConfiguration(User user)
+ {
+ var path = GetConfigurationFilePath(user);
+
+ try
+ {
+ lock (_configSyncLock)
+ {
+ return (UserConfiguration)_xmlSerializer.DeserializeFromFile(typeof(UserConfiguration), path);
+ }
+ }
+ catch (DirectoryNotFoundException)
+ {
+ return new UserConfiguration();
+ }
+ catch (FileNotFoundException)
+ {
+ return new UserConfiguration();
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error reading policy file: {0}", ex, path);
+
+ return new UserConfiguration();
+ }
+ }
+
+ private readonly object _configSyncLock = new object();
+ public Task UpdateConfiguration(string userId, UserConfiguration config)
+ {
+ var user = GetUserById(userId);
+ return UpdateConfiguration(user, config, true);
+ }
+
+ private async Task UpdateConfiguration(User user, UserConfiguration config, bool fireEvent)
+ {
+ var path = GetConfigurationFilePath(user);
+
+ // The xml serializer will output differently if the type is not exact
+ if (config.GetType() != typeof (UserConfiguration))
+ {
+ var json = _jsonSerializer.SerializeToString(config);
+ config = _jsonSerializer.DeserializeFromString<UserConfiguration>(json);
+ }
+
+ Directory.CreateDirectory(Path.GetDirectoryName(path));
+
+ lock (_configSyncLock)
+ {
+ _xmlSerializer.SerializeToFile(config, path);
+ user.Configuration = config;
+ }
+
+ if (fireEvent)
+ {
+ EventHelper.FireEventIfNotNull(UserConfigurationUpdated, this, new GenericEventArgs<User> { Argument = user }, _logger);
+ }
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
index 83fe992b6..ac742f04a 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -1846,7 +1846,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private bool IsLiveTvEnabled(User user)
{
- return user.Configuration.EnableLiveTvAccess && ActiveService != null;
+ return user.Policy.EnableLiveTvAccess && ActiveService != null;
}
public IEnumerable<User> GetEnabledUsers()
@@ -1854,7 +1854,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var service = ActiveService;
return _userManager.Users
- .Where(i => i.Configuration.EnableLiveTvAccess && service != null);
+ .Where(i => i.Policy.EnableLiveTvAccess && service != null);
}
/// <summary>
@@ -1872,12 +1872,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
var user = string.IsNullOrEmpty(userId) ? null : _userManager.GetUserById(userId);
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
-
var folder = await GetInternalLiveTvFolder(userId, cancellationToken).ConfigureAwait(false);
- return _dtoService.GetBaseItemDto(folder, fields, user);
+ return _dtoService.GetBaseItemDto(folder, new DtoOptions(), user);
}
public async Task<Folder> GetInternalLiveTvFolder(string userId, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json
index 81f648728..f42b623ad 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json
@@ -40,6 +40,11 @@
"LabelStopping": "Stopping",
"LabelCancelled": "(cancelled)",
"LabelFailed": "(failed)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Library Access",
+ "HeaderChannelAccess": "Channel Access",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Aborted by server shutdown)",
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
"HeaderDeleteTaskTrigger": "Delete Task Trigger",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Move right",
"ButtonBrowseOnlineImages": "Browse online images",
"HeaderDeleteItem": "Delete Item",
- "ConfirmDeleteItem": "Are you sure you wish to delete this item from your library?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Please enter a name or an external Id.",
"MessageValueNotCorrect": "The value entered is not correct. Please try again.",
"MessageItemSaved": "Item saved.",
@@ -396,6 +401,7 @@
"LabelYear": "Year:",
"LabelDateOfBirth": "Date of birth:",
"LabelBirthYear": "Birth year:",
+ "LabelBirthDate": "Birth date:",
"LabelDeathDate": "Death date:",
"HeaderRemoveMediaLocation": "Remove Media Location",
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Media Locations",
"LabelFolderTypeValue": "Folder type: {0}",
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
- "FolderTypeMixed": "Mixed movies & tv",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Movies",
"FolderTypeMusic": "Music",
"FolderTypeAdultVideos": "Adult videos",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Home videos",
"FolderTypeGames": "Games",
"FolderTypeBooks": "Books",
- "FolderTypeTvShows": "TV shows",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Movies",
"TabSeries": "Series",
"TabEpisodes": "\u0627\u0644\u062d\u0644\u0642\u0627\u062a",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
"MessageEnjoyYourStay": "Enjoy your stay",
"DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Easily create user accounts for your friends and family, each with their own permissions, library access, parental controls and more.",
"DashboardTourCinemaMode": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
"DashboardTourChapters": "Enable chapter image generation for your videos for a more pleasing presentation while viewing.",
@@ -642,7 +649,12 @@
"OptionLow": "Low",
"HeaderSettings": "Settings",
"OptionAutomaticallySyncNewContent": "Automatically sync new content",
- "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.",
+ "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
"OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
- "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
+ "LabelItemLimit": "Item limit:",
+ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+ "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+ "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json
index d0dfd608b..909f5ada6 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json
@@ -40,6 +40,11 @@
"LabelStopping": "Stopping",
"LabelCancelled": "(cancelled)",
"LabelFailed": "(failed)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Library Access",
+ "HeaderChannelAccess": "Channel Access",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Aborted by server shutdown)",
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
"HeaderDeleteTaskTrigger": "Delete Task Trigger",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Move right",
"ButtonBrowseOnlineImages": "Browse online images",
"HeaderDeleteItem": "Delete Item",
- "ConfirmDeleteItem": "Are you sure you wish to delete this item from your library?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Please enter a name or an external Id.",
"MessageValueNotCorrect": "The value entered is not correct. Please try again.",
"MessageItemSaved": "Item saved.",
@@ -396,6 +401,7 @@
"LabelYear": "Year:",
"LabelDateOfBirth": "Date of birth:",
"LabelBirthYear": "Birth year:",
+ "LabelBirthDate": "Birth date:",
"LabelDeathDate": "Death date:",
"HeaderRemoveMediaLocation": "Remove Media Location",
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Media Locations",
"LabelFolderTypeValue": "Folder type: {0}",
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
- "FolderTypeMixed": "Mixed movies & tv",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Movies",
"FolderTypeMusic": "Music",
"FolderTypeAdultVideos": "Adult videos",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Home videos",
"FolderTypeGames": "Games",
"FolderTypeBooks": "Books",
- "FolderTypeTvShows": "TV shows",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Movies",
"TabSeries": "Series",
"TabEpisodes": "Episodes",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
"MessageEnjoyYourStay": "Enjoy your stay",
"DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Easily create user accounts for your friends and family, each with their own permissions, library access, parental controls and more.",
"DashboardTourCinemaMode": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
"DashboardTourChapters": "Enable chapter image generation for your videos for a more pleasing presentation while viewing.",
@@ -642,7 +649,12 @@
"OptionLow": "Low",
"HeaderSettings": "Settings",
"OptionAutomaticallySyncNewContent": "Automatically sync new content",
- "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.",
+ "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
"OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
- "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
+ "LabelItemLimit": "Item limit:",
+ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+ "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+ "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json
index 9f2da7797..0e2af5e4e 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json
@@ -40,6 +40,11 @@
"LabelStopping": "Stopping",
"LabelCancelled": "(zru\u0161eno)",
"LabelFailed": "(failed)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Library Access",
+ "HeaderChannelAccess": "Channel Access",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Aborted by server shutdown)",
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
"HeaderDeleteTaskTrigger": "Delete Task Trigger",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Move right",
"ButtonBrowseOnlineImages": "Browse online images",
"HeaderDeleteItem": "Delete Item",
- "ConfirmDeleteItem": "Are you sure you wish to delete this item from your library?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Please enter a name or an external Id.",
"MessageValueNotCorrect": "The value entered is not correct. Please try again.",
"MessageItemSaved": "Item saved.",
@@ -396,6 +401,7 @@
"LabelYear": "Year:",
"LabelDateOfBirth": "Date of birth:",
"LabelBirthYear": "Birth year:",
+ "LabelBirthDate": "Birth date:",
"LabelDeathDate": "Death date:",
"HeaderRemoveMediaLocation": "Remove Media Location",
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Media Locations",
"LabelFolderTypeValue": "Folder type: {0}",
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
- "FolderTypeMixed": "Mixed movies & tv",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Movies",
"FolderTypeMusic": "Music",
"FolderTypeAdultVideos": "Adult videos",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Home videos",
"FolderTypeGames": "Games",
"FolderTypeBooks": "Books",
- "FolderTypeTvShows": "TV shows",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Filmy",
"TabSeries": "S\u00e9rie",
"TabEpisodes": "Epizody",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
"MessageEnjoyYourStay": "Enjoy your stay",
"DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Easily create user accounts for your friends and family, each with their own permissions, library access, parental controls and more.",
"DashboardTourCinemaMode": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
"DashboardTourChapters": "Enable chapter image generation for your videos for a more pleasing presentation while viewing.",
@@ -642,7 +649,12 @@
"OptionLow": "Low",
"HeaderSettings": "Settings",
"OptionAutomaticallySyncNewContent": "Automatically sync new content",
- "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.",
+ "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
"OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
- "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
+ "LabelItemLimit": "Item limit:",
+ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+ "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+ "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/da.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/da.json
index 4bd7d3103..75e6a1b48 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/da.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/da.json
@@ -40,6 +40,11 @@
"LabelStopping": "Stopping",
"LabelCancelled": "(cancelled)",
"LabelFailed": "(failed)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Library Access",
+ "HeaderChannelAccess": "Channel Access",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Aborted by server shutdown)",
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
"HeaderDeleteTaskTrigger": "Delete Task Trigger",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Move right",
"ButtonBrowseOnlineImages": "Browse online images",
"HeaderDeleteItem": "Delete Item",
- "ConfirmDeleteItem": "Are you sure you wish to delete this item from your library?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Please enter a name or an external Id.",
"MessageValueNotCorrect": "The value entered is not correct. Please try again.",
"MessageItemSaved": "Item saved.",
@@ -396,6 +401,7 @@
"LabelYear": "Year:",
"LabelDateOfBirth": "Date of birth:",
"LabelBirthYear": "Birth year:",
+ "LabelBirthDate": "Birth date:",
"LabelDeathDate": "Death date:",
"HeaderRemoveMediaLocation": "Remove Media Location",
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Media Locations",
"LabelFolderTypeValue": "Folder type: {0}",
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
- "FolderTypeMixed": "Mixed movies & tv",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Movies",
"FolderTypeMusic": "Music",
"FolderTypeAdultVideos": "Adult videos",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Home videos",
"FolderTypeGames": "Games",
"FolderTypeBooks": "Books",
- "FolderTypeTvShows": "TV shows",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Film",
"TabSeries": "Serier",
"TabEpisodes": "Episoder",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
"MessageEnjoyYourStay": "Enjoy your stay",
"DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Easily create user accounts for your friends and family, each with their own permissions, library access, parental controls and more.",
"DashboardTourCinemaMode": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
"DashboardTourChapters": "Enable chapter image generation for your videos for a more pleasing presentation while viewing.",
@@ -642,7 +649,12 @@
"OptionLow": "Low",
"HeaderSettings": "Settings",
"OptionAutomaticallySyncNewContent": "Automatically sync new content",
- "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.",
+ "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
"OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
- "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
+ "LabelItemLimit": "Item limit:",
+ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+ "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+ "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/de.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/de.json
index d8a8036b0..051e8a745 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/de.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/de.json
@@ -40,6 +40,11 @@
"LabelStopping": "Stoppe",
"LabelCancelled": "(abgebrochen)",
"LabelFailed": "(fehlgeschlagen)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Bibliothekszugriff",
+ "HeaderChannelAccess": "Channelzugriff",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Durch herunterfahrenden Server abgebrochen)",
"LabelScheduledTaskLastRan": "Zuletzt ausgef\u00fchrt vor: {0}. Ben\u00f6tigte Zeit: {1}.",
"HeaderDeleteTaskTrigger": "Entferne Aufgabenausl\u00f6ser",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Nach rechts",
"ButtonBrowseOnlineImages": "Durchsuche Onlinebilder",
"HeaderDeleteItem": "L\u00f6sche Element",
- "ConfirmDeleteItem": "Bist du dir sicher dieses Element aus deiner Bibliothek zu l\u00f6schen?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Bitte gib einen Namen oder eine externe Id an.",
"MessageValueNotCorrect": "Der eingegeben Wert ist nicht korrekt. Bitte versuche es noch einmal.",
"MessageItemSaved": "Element gespeichert",
@@ -396,6 +401,7 @@
"LabelYear": "Jahr:",
"LabelDateOfBirth": "Geburtsatum:",
"LabelBirthYear": "Geburtsjahr:",
+ "LabelBirthDate": "Geburtsdatum:",
"LabelDeathDate": "Todesdatum:",
"HeaderRemoveMediaLocation": "Entferne Medienquelle",
"MessageConfirmRemoveMediaLocation": "Bist du dir sicher diese Medienquelle entfernen zu wollen?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Medienquellen",
"LabelFolderTypeValue": "Verzeichnistyp: {0}",
"LabelPathSubstitutionHelp": "Optional: Die Pfadersetzung kann Serverpfade zu Netzwerkfreigaben umleiten, die von Endger\u00e4ten f\u00fcr die direkte Wiedergabe genutzt werden k\u00f6nnen.",
- "FolderTypeMixed": "Filme & Serien gemischt",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Filme",
"FolderTypeMusic": "Musik",
"FolderTypeAdultVideos": "Videos f\u00fcr Erwachsene",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Heimvideos",
"FolderTypeGames": "Spiele",
"FolderTypeBooks": "B\u00fccher",
- "FolderTypeTvShows": "TV Serien",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Filme",
"TabSeries": "Serie",
"TabEpisodes": "Episoden",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "und steuert einfach andere Ger\u00e4te und Media Browser Anwendungen",
"MessageEnjoyYourStay": "Genie\u00dfe deinen Aufenthalt",
"DashboardTourDashboard": "Die Server\u00fcbersicht erlaubt es dir deinen Server und dessen Benutzer im Blick zu behalten. Somit wei\u00dft du immer wer gerade was macht und wo er sich befindet.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Erstelle einfach Benutzeraccounts f\u00fcr Freunde und Familie. Jeder mit seinen individuellen Einstellungen bei Berechtigungen, Blibliothekenzugriff, Kindersicherung und mehr.",
"DashboardTourCinemaMode": "Der Kino-Modus bringt das Kinoerlebnis direkt in dein Wohnzimmer, mit der F\u00e4higkeit Trailer und benutzerdefinierte Intros vor dem Hauptfilm zu spielen.",
"DashboardTourChapters": "Aktiviere die Bildgenerierung f\u00fcr die Kapitel deiner Videos f\u00fcr eine bessere Darstellung w\u00e4hrend des Ansehens.",
@@ -642,7 +649,12 @@
"OptionLow": "Niedrig",
"HeaderSettings": "Einstellungen",
"OptionAutomaticallySyncNewContent": "Synchronisiere neue Inhalte automatisch",
- "OptionAutomaticallySyncNewContentHelp": "Neu hinzugef\u00fcgte Inhalte zu diesen Verzeichnissen werden automatisch zum Ger\u00e4t synchronisiert.",
+ "OptionAutomaticallySyncNewContentHelp": "Neue Inhalte dieser Kategorie werden automatisch mit dem Ger\u00e4t synchronisiert.",
"OptionSyncUnwatchedVideosOnly": "Synchronisiere nur ungesehene Videos.",
- "OptionSyncUnwatchedVideosOnlyHelp": "Nur ungesehene Video werden synchronisiert. Videos werden entfernt sobald diese auf dem Ger\u00e4t angeschaut wurden."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Nur ungesehene Video werden synchronisiert. Videos werden entfernt sobald diese auf dem Ger\u00e4t angeschaut wurden.",
+ "LabelItemLimit": "Maximale Anzahl:",
+ "LabelItemLimitHelp": "Optional. Legen Sie die maximale Anzahl der zu synchronisierenden Eintr\u00e4ge fest.",
+ "MessageBookPluginRequired": "Setzt die Installation des Bookshelf-Plugins voraus.",
+ "MessageGamePluginRequired": "Setzt die Installation des GameBrowser-Plugins voraus.",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/el.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/el.json
index 20c9de1ef..0e3340427 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/el.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/el.json
@@ -40,6 +40,11 @@
"LabelStopping": "Stopping",
"LabelCancelled": "(cancelled)",
"LabelFailed": "(failed)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Library Access",
+ "HeaderChannelAccess": "Channel Access",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Aborted by server shutdown)",
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
"HeaderDeleteTaskTrigger": "Delete Task Trigger",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Move right",
"ButtonBrowseOnlineImages": "Browse online images",
"HeaderDeleteItem": "Delete Item",
- "ConfirmDeleteItem": "Are you sure you wish to delete this item from your library?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Please enter a name or an external Id.",
"MessageValueNotCorrect": "The value entered is not correct. Please try again.",
"MessageItemSaved": "Item saved.",
@@ -396,6 +401,7 @@
"LabelYear": "Year:",
"LabelDateOfBirth": "Date of birth:",
"LabelBirthYear": "Birth year:",
+ "LabelBirthDate": "Birth date:",
"LabelDeathDate": "Death date:",
"HeaderRemoveMediaLocation": "Remove Media Location",
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Media Locations",
"LabelFolderTypeValue": "Folder type: {0}",
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
- "FolderTypeMixed": "Mixed movies & tv",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Movies",
"FolderTypeMusic": "Music",
"FolderTypeAdultVideos": "Adult videos",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Home videos",
"FolderTypeGames": "Games",
"FolderTypeBooks": "Books",
- "FolderTypeTvShows": "TV shows",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Movies",
"TabSeries": "Series",
"TabEpisodes": "\u0395\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
"MessageEnjoyYourStay": "Enjoy your stay",
"DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Easily create user accounts for your friends and family, each with their own permissions, library access, parental controls and more.",
"DashboardTourCinemaMode": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
"DashboardTourChapters": "Enable chapter image generation for your videos for a more pleasing presentation while viewing.",
@@ -642,7 +649,12 @@
"OptionLow": "Low",
"HeaderSettings": "Settings",
"OptionAutomaticallySyncNewContent": "Automatically sync new content",
- "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.",
+ "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
"OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
- "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
+ "LabelItemLimit": "Item limit:",
+ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+ "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+ "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json
index fec45e70c..0df62070c 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json
@@ -40,6 +40,11 @@
"LabelStopping": "Stopping",
"LabelCancelled": "(cancelled)",
"LabelFailed": "(failed)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Library Access",
+ "HeaderChannelAccess": "Channel Access",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Aborted by server shutdown)",
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
"HeaderDeleteTaskTrigger": "Delete Task Trigger",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Move right",
"ButtonBrowseOnlineImages": "Browse online images",
"HeaderDeleteItem": "Delete Item",
- "ConfirmDeleteItem": "Are you sure you wish to delete this item from your library?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Please enter a name or an external Id.",
"MessageValueNotCorrect": "The value entered is not correct. Please try again.",
"MessageItemSaved": "Item saved.",
@@ -396,6 +401,7 @@
"LabelYear": "Year:",
"LabelDateOfBirth": "Date of birth:",
"LabelBirthYear": "Birth year:",
+ "LabelBirthDate": "Birth date:",
"LabelDeathDate": "Death date:",
"HeaderRemoveMediaLocation": "Remove Media Location",
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Media Locations",
"LabelFolderTypeValue": "Folder type: {0}",
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
- "FolderTypeMixed": "Mixed movies & tv",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Movies",
"FolderTypeMusic": "Music",
"FolderTypeAdultVideos": "Adult videos",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Home videos",
"FolderTypeGames": "Games",
"FolderTypeBooks": "Books",
- "FolderTypeTvShows": "TV shows",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Movies",
"TabSeries": "Series",
"TabEpisodes": "Episodes",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
"MessageEnjoyYourStay": "Enjoy your stay",
"DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Easily create user accounts for your friends and family, each with their own permissions, library access, parental controls and more.",
"DashboardTourCinemaMode": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
"DashboardTourChapters": "Enable chapter image generation for your videos for a more pleasing presentation while viewing.",
@@ -642,7 +649,12 @@
"OptionLow": "Low",
"HeaderSettings": "Settings",
"OptionAutomaticallySyncNewContent": "Automatically sync new content",
- "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.",
+ "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
"OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
- "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
+ "LabelItemLimit": "Item limit:",
+ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+ "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+ "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json
index 369299be0..db2ddc4ec 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json
@@ -40,6 +40,11 @@
"LabelStopping": "Stopping",
"LabelCancelled": "(cancelled)",
"LabelFailed": "(failed)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Library Access",
+ "HeaderChannelAccess": "Channel Access",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Aborted by server shutdown)",
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
"HeaderDeleteTaskTrigger": "Delete Task Trigger",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Move right",
"ButtonBrowseOnlineImages": "Browse online images",
"HeaderDeleteItem": "Delete Item",
- "ConfirmDeleteItem": "Are you sure you wish to delete this item from your library?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Please enter a name or an external Id.",
"MessageValueNotCorrect": "The value entered is not correct. Please try again.",
"MessageItemSaved": "Item saved.",
@@ -396,6 +401,7 @@
"LabelYear": "Year:",
"LabelDateOfBirth": "Date of birth:",
"LabelBirthYear": "Birth year:",
+ "LabelBirthDate": "Birth date:",
"LabelDeathDate": "Death date:",
"HeaderRemoveMediaLocation": "Remove Media Location",
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Media Locations",
"LabelFolderTypeValue": "Folder type: {0}",
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
- "FolderTypeMixed": "Mixed movies & tv",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Movies",
"FolderTypeMusic": "Music",
"FolderTypeAdultVideos": "Adult videos",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Home videos",
"FolderTypeGames": "Games",
"FolderTypeBooks": "Books",
- "FolderTypeTvShows": "TV shows",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Movies",
"TabSeries": "Series",
"TabEpisodes": "Episodes",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
"MessageEnjoyYourStay": "Enjoy your stay",
"DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Easily create user accounts for your friends and family, each with their own permissions, library access, parental controls and more.",
"DashboardTourCinemaMode": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
"DashboardTourChapters": "Enable chapter image generation for your videos for a more pleasing presentation while viewing.",
@@ -642,7 +649,12 @@
"OptionLow": "Low",
"HeaderSettings": "Settings",
"OptionAutomaticallySyncNewContent": "Automatically sync new content",
- "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.",
+ "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
"OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
- "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
+ "LabelItemLimit": "Item limit:",
+ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+ "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+ "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/es.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/es.json
index d2957340c..c4c980ff5 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/es.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/es.json
@@ -40,6 +40,11 @@
"LabelStopping": "Deteniendo",
"LabelCancelled": "(cancelado)",
"LabelFailed": "(failed)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Library Access",
+ "HeaderChannelAccess": "Channel Access",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Abortado por cierre del servidor)",
"LabelScheduledTaskLastRan": "\u00daltima ejecuci\u00f3n {0}, teniendo {1}.",
"HeaderDeleteTaskTrigger": "Eliminar tarea de activaci\u00f3n",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Mover derecha",
"ButtonBrowseOnlineImages": "Navegar im\u00e1genes online",
"HeaderDeleteItem": "Borrar elemento",
- "ConfirmDeleteItem": "\u00bfEst\u00e1 seguro que desea borrar este elemento de su biblioteca?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Introduzca un nombre o un identificador externo.",
"MessageValueNotCorrect": "El valor introducido no es correcto. Intentelo de nuevo.",
"MessageItemSaved": "Elemento grabado.",
@@ -396,6 +401,7 @@
"LabelYear": "Year:",
"LabelDateOfBirth": "Date of birth:",
"LabelBirthYear": "Birth year:",
+ "LabelBirthDate": "Birth date:",
"LabelDeathDate": "Death date:",
"HeaderRemoveMediaLocation": "Remove Media Location",
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Media Locations",
"LabelFolderTypeValue": "Folder type: {0}",
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
- "FolderTypeMixed": "Mixed movies & tv",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Movies",
"FolderTypeMusic": "Music",
"FolderTypeAdultVideos": "Adult videos",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Home videos",
"FolderTypeGames": "Games",
"FolderTypeBooks": "Books",
- "FolderTypeTvShows": "TV shows",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Pel\u00edculas",
"TabSeries": "Series",
"TabEpisodes": "Episodios",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
"MessageEnjoyYourStay": "Enjoy your stay",
"DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Easily create user accounts for your friends and family, each with their own permissions, library access, parental controls and more.",
"DashboardTourCinemaMode": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
"DashboardTourChapters": "Enable chapter image generation for your videos for a more pleasing presentation while viewing.",
@@ -642,7 +649,12 @@
"OptionLow": "Low",
"HeaderSettings": "Settings",
"OptionAutomaticallySyncNewContent": "Automatically sync new content",
- "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.",
+ "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
"OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
- "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
+ "LabelItemLimit": "Item limit:",
+ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+ "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+ "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json
index fda5b65b3..5d085ef49 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json
@@ -40,6 +40,11 @@
"LabelStopping": "Deteniendo",
"LabelCancelled": "(cancelado)",
"LabelFailed": "(Fallido)",
+ "ButtonHelp": "Ayuda",
+ "HeaderLibraryAccess": "Acceso a la Biblioteca",
+ "HeaderChannelAccess": "Acceso a los Canales",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Abortada por apagado del servidor)",
"LabelScheduledTaskLastRan": "Ejecutado hace {0}, tomando {1}.",
"HeaderDeleteTaskTrigger": "Borrar Disparador de Tarea",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Mover a la derecha",
"ButtonBrowseOnlineImages": "Buscar im\u00e1genes en l\u00ednea",
"HeaderDeleteItem": "Eliminar \u00cdtem",
- "ConfirmDeleteItem": "\u00bfEst\u00e1 seguro de querer eleiminar este \u00edtem de su biblioteca?",
+ "ConfirmDeleteItem": "Al eliminar este \u00edtem se eliminar\u00e1 tanto del sistema de archivos como de su biblioteca de medios. \u00bfEsta seguro de querer continuar?",
"MessagePleaseEnterNameOrId": "Por favor ingrese un nombre o id externo.",
"MessageValueNotCorrect": "El valor ingresado no es correcto. Intente nuevamente por favor.",
"MessageItemSaved": "\u00cdtem guardado.",
@@ -396,6 +401,7 @@
"LabelYear": "A\u00f1o:",
"LabelDateOfBirth": "Fecha de nacimiento:",
"LabelBirthYear": "A\u00f1o de nacimiento:",
+ "LabelBirthDate": "Fecha de Nacimiento:",
"LabelDeathDate": "Fecha de defunci\u00f3n:",
"HeaderRemoveMediaLocation": "Eliminar Ubicaci\u00f3n de Medios",
"MessageConfirmRemoveMediaLocation": "\u00bfEst\u00e1 seguro de querer eliminar esta ubicaci\u00f3n?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Ubicaciones de Medios",
"LabelFolderTypeValue": "Tipo de carpeta: {0}",
"LabelPathSubstitutionHelp": "Opcional: La sustituci\u00f3n de trayectoras puede mapear trayectorias del servidor a recursos de red comaprtidos que los clientes pueden acceder para reproducir de manera directa.",
- "FolderTypeMixed": "Pel\u00edculas y TV mezclados",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Pel\u00edculas",
"FolderTypeMusic": "M\u00fasica",
"FolderTypeAdultVideos": "Videos para adultos",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Videos caseros",
"FolderTypeGames": "Juegos",
"FolderTypeBooks": "Libros",
- "FolderTypeTvShows": "Programas de TV",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Pel\u00edculas",
"TabSeries": "Series",
"TabEpisodes": "Episodios",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "y controla f\u00e1cilmente otros dispositivos y apps de Media Browser",
"MessageEnjoyYourStay": "Disfrute su visita",
"DashboardTourDashboard": "El panel de control del servidor le permite monitorear su servidor y sus usuarios. Siempre sabr\u00e1 quien est\u00e1 haciendo qu\u00e9 y donde se encuentran.",
+ "DashboardTourHelp": "La ayuda dentro de la app proporciona botones simples para abrir p\u00e1ginas de la wiki relacionadas con el contenido en pantalla.",
"DashboardTourUsers": "Cree cuentas f\u00e1cilmente para sus amigos y familia, cada una con sus propios permisos, accesos a la biblioteca, controles parentales y m\u00e1s.",
"DashboardTourCinemaMode": "El modo cine trae la experiencia del cine directo a su sala de TV con la capacidad de reproducir avances e intros personalizados antes de la presentaci\u00f3n estelar.",
"DashboardTourChapters": "Active la generaci\u00f3n de im\u00e1genes de cap\u00edtulos de sus videos para una presentaci\u00f3n m\u00e1s agradable al desplegar.",
@@ -642,7 +649,12 @@
"OptionLow": "Baja",
"HeaderSettings": "Configuraci\u00f3n",
"OptionAutomaticallySyncNewContent": "Sincronizar autom\u00e1ticamente nuevos contenidos",
- "OptionAutomaticallySyncNewContentHelp": "Los contenidos nuevos que sean agregados a estas carpetas ser\u00e1n sincronizados autom\u00e1ticamente con el dispositivo.",
+ "OptionAutomaticallySyncNewContentHelp": "Los contenidos nuevos agregados a esta categor\u00eda ser\u00e1n sincronizados autom\u00e1ticamente con el dispositivo.",
"OptionSyncUnwatchedVideosOnly": "Sincronizar \u00fanicamente videos no vistos",
- "OptionSyncUnwatchedVideosOnlyHelp": "Solamente los videos a\u00fan no vistos ser\u00e1n sincronizados, se eliminar\u00e1n los videos del dispositivo conforme \u00e9stos sean vistos."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Solamente los videos a\u00fan no vistos ser\u00e1n sincronizados, se eliminar\u00e1n los videos del dispositivo conforme \u00e9stos sean vistos.",
+ "LabelItemLimit": "L\u00edmite de \u00cdtems:",
+ "LabelItemLimitHelp": "Opcional. Establece un l\u00edmite en el n\u00famero de \u00edtems que ser\u00e1n sincronizados.",
+ "MessageBookPluginRequired": "Requiere instalaci\u00f3n del complemento Bookshelf",
+ "MessageGamePluginRequired": "Requiere instalaci\u00f3n del complemento de GameBrowser",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/fi.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/fi.json
index e9c6263e2..bdb51842f 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/fi.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/fi.json
@@ -40,6 +40,11 @@
"LabelStopping": "Stopping",
"LabelCancelled": "(cancelled)",
"LabelFailed": "(failed)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Library Access",
+ "HeaderChannelAccess": "Channel Access",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Aborted by server shutdown)",
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
"HeaderDeleteTaskTrigger": "Delete Task Trigger",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Move right",
"ButtonBrowseOnlineImages": "Browse online images",
"HeaderDeleteItem": "Delete Item",
- "ConfirmDeleteItem": "Are you sure you wish to delete this item from your library?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Please enter a name or an external Id.",
"MessageValueNotCorrect": "The value entered is not correct. Please try again.",
"MessageItemSaved": "Item saved.",
@@ -396,6 +401,7 @@
"LabelYear": "Year:",
"LabelDateOfBirth": "Date of birth:",
"LabelBirthYear": "Birth year:",
+ "LabelBirthDate": "Birth date:",
"LabelDeathDate": "Death date:",
"HeaderRemoveMediaLocation": "Remove Media Location",
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Media Locations",
"LabelFolderTypeValue": "Folder type: {0}",
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
- "FolderTypeMixed": "Mixed movies & tv",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Movies",
"FolderTypeMusic": "Music",
"FolderTypeAdultVideos": "Adult videos",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Home videos",
"FolderTypeGames": "Games",
"FolderTypeBooks": "Books",
- "FolderTypeTvShows": "TV shows",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Movies",
"TabSeries": "Series",
"TabEpisodes": "Episodes",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
"MessageEnjoyYourStay": "Enjoy your stay",
"DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Easily create user accounts for your friends and family, each with their own permissions, library access, parental controls and more.",
"DashboardTourCinemaMode": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
"DashboardTourChapters": "Enable chapter image generation for your videos for a more pleasing presentation while viewing.",
@@ -642,7 +649,12 @@
"OptionLow": "Low",
"HeaderSettings": "Settings",
"OptionAutomaticallySyncNewContent": "Automatically sync new content",
- "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.",
+ "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
"OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
- "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
+ "LabelItemLimit": "Item limit:",
+ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+ "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+ "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json
index d3c95bfa4..262a25585 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json
@@ -40,6 +40,11 @@
"LabelStopping": "En cours d'arr\u00eat",
"LabelCancelled": "(annul\u00e9)",
"LabelFailed": "(\u00e9chou\u00e9)",
+ "ButtonHelp": "Aide",
+ "HeaderLibraryAccess": "Acc\u00e8s \u00e0 la librairie",
+ "HeaderChannelAccess": "Acc\u00e8s Cha\u00eene",
+ "HeaderDeviceAccess": "Acc\u00e8s \u00e0 l'appareil",
+ "HeaderSelectDevices": "S\u00e9lectionnez un appareil",
"LabelAbortedByServerShutdown": "(Annul\u00e9 par fermeture du serveur)",
"LabelScheduledTaskLastRan": "Derni\u00e8re ex\u00e9cution {0}, dur\u00e9e {1}.",
"HeaderDeleteTaskTrigger": "Supprimer le d\u00e9clencheur de t\u00e2che",
@@ -55,7 +60,7 @@
"LabelForcedStream": "(Forc\u00e9)",
"LabelDefaultForcedStream": "(Par d\u00e9faut\/Forc\u00e9)",
"LabelUnknownLanguage": "Langue inconnue",
- "ButtonMute": "Sourdine",
+ "ButtonMute": "Muet",
"ButtonUnmute": "D\u00e9sactiver sourdine",
"ButtonStop": "Arr\u00eat",
"ButtonNextTrack": "Piste suivante",
@@ -77,7 +82,7 @@
"MessageInvalidUser": "Nom d'utilisateur ou mot de passe incorrect. R\u00e9essayer.",
"HeaderLoginFailure": "\u00c9chec de la connection",
"HeaderAllRecordings": "Tous les enregistrements",
- "RecommendationBecauseYouLike": "Parce-que vous aimez {0}",
+ "RecommendationBecauseYouLike": "Parce que vous aimez {0}",
"RecommendationBecauseYouWatched": "Parce que vous avez regard\u00e9 {0}",
"RecommendationDirectedBy": "R\u00e9alis\u00e9 par {0}",
"RecommendationStarring": "Mettant en vedette {0}",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "D\u00e9placer \u00e0 droite",
"ButtonBrowseOnlineImages": "Parcourir les images en ligne",
"HeaderDeleteItem": "Supprimer l'item",
- "ConfirmDeleteItem": "\u00cates-vous s\u00fbr de vouloir supprimer cet item de votre biblioth\u00e8que ?",
+ "ConfirmDeleteItem": "Supprimer cet \u00e9l\u00e9ment l'effacera \u00e0 la fois du syst\u00e8me de fichiers et de votre biblioth\u00e8que de media. Etes-vous s\u00fbr de vouloir continuer ?",
"MessagePleaseEnterNameOrId": "Merci de saisir un nom ou un ID externe.",
"MessageValueNotCorrect": "La valeur saisie est incorrecte. Merci de r\u00e9\u00e9ssayer.",
"MessageItemSaved": "Item sauvegard\u00e9.",
@@ -396,6 +401,7 @@
"LabelYear": "Ann\u00e9e :",
"LabelDateOfBirth": "Date de naissance :",
"LabelBirthYear": "Ann\u00e9e de naissance :",
+ "LabelBirthDate": "Date de naissance :",
"LabelDeathDate": "Date de d\u00e9c\u00e8s :",
"HeaderRemoveMediaLocation": "Supprimer l'emplacement m\u00e9dia",
"MessageConfirmRemoveMediaLocation": "Etes vous sur de vouloir supprimer cet emplacement?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Emplacement des M\u00e9dias",
"LabelFolderTypeValue": "Type de r\u00e9pertoire: {0}",
"LabelPathSubstitutionHelp": "Optionnel: La substitution de chemin peut rediriger les r\u00e9pertoires serveurs vers des partages r\u00e9seau afin que le client acc\u00e8de directement \u00e0 la lecture.",
- "FolderTypeMixed": "Film et TV m\u00e9lang\u00e9s",
+ "FolderTypeUnset": "Non d\u00e9fini (contenu m\u00e9lang\u00e9)",
"FolderTypeMovies": "Films",
"FolderTypeMusic": "Musique",
"FolderTypeAdultVideos": "Vid\u00e9os Adultes",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Vid\u00e9os personnelles",
"FolderTypeGames": "Jeux",
"FolderTypeBooks": "Livres",
- "FolderTypeTvShows": "S\u00e9ries TV",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Films",
"TabSeries": "S\u00e9ries",
"TabEpisodes": "\u00c9pisodes",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "et controles facilement les autres p\u00e9riph\u00e9riques et applications Medi Browser",
"MessageEnjoyYourStay": "Profitez en bien",
"DashboardTourDashboard": "Le tableau de bord du serveur vous permet de g\u00e9rer votre serveur et vos utilisateurs. Vous saurez toujours qui fait quoi et o\u00f9 ils sont.",
+ "DashboardTourHelp": "L'aide contextuelle de l'application permet d'ouvrir les pages du wiki relatives au contenu affich\u00e9.",
"DashboardTourUsers": "Cr\u00e9er facilement des comptes utilisateurs pour vos amis et votre famille, chacun avec ses propres droits, biblioth\u00e8ques accessibles, contr\u00f4le parental et plus encore.",
"DashboardTourCinemaMode": "Le mode cin\u00e9ma apporte l'exp\u00e9rience du cin\u00e9ma directement dans votre salon avec l'abilit\u00e9 de lire les bandes-annonces et les introductions personnalis\u00e9es avant le programme principal.",
"DashboardTourChapters": "Autoriser la g\u00e9n\u00e9ration des images des chapitres de vos vid\u00e9os pour une pr\u00e9sentation plus agr\u00e9able pendant le visionnage",
@@ -636,13 +643,18 @@
"MessageSyncJobCreated": "Job de synchronisation cr\u00e9\u00e9.",
"LabelSyncTo": "Synchronis\u00e9 avec:",
"LabelSyncJobName": "Nom du job de synchronisation:",
- "LabelQuality": "Quality:",
- "OptionHigh": "High",
- "OptionMedium": "Medium",
+ "LabelQuality": "Qualit\u00e9:",
+ "OptionHigh": "Haute",
+ "OptionMedium": "Moyenne",
"OptionLow": "Basse",
"HeaderSettings": "Param\u00e8tres",
"OptionAutomaticallySyncNewContent": "Synchroniser automatiquement le nouveau contenu",
- "OptionAutomaticallySyncNewContentHelp": "Le nouveau contenu ajout\u00e9 \u00e0 ces r\u00e9pertoires sera automatiquement synchronis\u00e9 \u00e0 votre p\u00e9riph\u00e9rique.",
+ "OptionAutomaticallySyncNewContentHelp": "Les nouveaux contenus ajout\u00e9s \u00e0 cette cat\u00e9gorie seront automatiquement synchronis\u00e9s avec le p\u00e9riph\u00e9rique.",
"OptionSyncUnwatchedVideosOnly": "Synchroniser seulement les vid\u00e9os non lus.",
- "OptionSyncUnwatchedVideosOnlyHelp": "Seulement les vid\u00e9os non lus seront synchronis\u00e9es et seront supprim\u00e9es du p\u00e9riph\u00e9rique au fur et \u00e0 mesure qu'elles sont lus."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Seulement les vid\u00e9os non lus seront synchronis\u00e9es et seront supprim\u00e9es du p\u00e9riph\u00e9rique au fur et \u00e0 mesure qu'elles sont lus.",
+ "LabelItemLimit": "Maximum d'\u00e9l\u00e9ments :",
+ "LabelItemLimitHelp": "Optionnel : d\u00e9finit le nombre maximum d'\u00e9l\u00e9ments qui seront synchronis\u00e9s.",
+ "MessageBookPluginRequired": "N\u00e9cessite l'installation du plugin Bookshelf",
+ "MessageGamePluginRequired": "N\u00e9cessite l'installation du plugin GameBrowser",
+ "MessageUnsetContentHelp": "Le contenu sera affich\u00e9 sous forme de r\u00e9pertoires. Pour un r\u00e9sultat optimal, utilisez le gestionnaire de m\u00e9tadonn\u00e9es pour d\u00e9finir le type de contenu des sous-r\u00e9pertoires."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/he.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/he.json
index 7d268200b..d20c54f9b 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/he.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/he.json
@@ -40,6 +40,11 @@
"LabelStopping": "Stopping",
"LabelCancelled": "(cancelled)",
"LabelFailed": "(failed)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Library Access",
+ "HeaderChannelAccess": "Channel Access",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Aborted by server shutdown)",
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
"HeaderDeleteTaskTrigger": "Delete Task Trigger",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Move right",
"ButtonBrowseOnlineImages": "Browse online images",
"HeaderDeleteItem": "Delete Item",
- "ConfirmDeleteItem": "Are you sure you wish to delete this item from your library?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Please enter a name or an external Id.",
"MessageValueNotCorrect": "The value entered is not correct. Please try again.",
"MessageItemSaved": "Item saved.",
@@ -396,6 +401,7 @@
"LabelYear": "Year:",
"LabelDateOfBirth": "Date of birth:",
"LabelBirthYear": "Birth year:",
+ "LabelBirthDate": "Birth date:",
"LabelDeathDate": "Death date:",
"HeaderRemoveMediaLocation": "Remove Media Location",
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Media Locations",
"LabelFolderTypeValue": "Folder type: {0}",
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
- "FolderTypeMixed": "Mixed movies & tv",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Movies",
"FolderTypeMusic": "Music",
"FolderTypeAdultVideos": "Adult videos",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Home videos",
"FolderTypeGames": "Games",
"FolderTypeBooks": "Books",
- "FolderTypeTvShows": "TV shows",
+ "FolderTypeTvShows": "TV",
"TabMovies": "\u05e1\u05e8\u05d8\u05d9\u05dd",
"TabSeries": "\u05e1\u05d3\u05e8\u05d5\u05ea",
"TabEpisodes": "\u05e4\u05e8\u05e7\u05d9\u05dd",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
"MessageEnjoyYourStay": "Enjoy your stay",
"DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Easily create user accounts for your friends and family, each with their own permissions, library access, parental controls and more.",
"DashboardTourCinemaMode": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
"DashboardTourChapters": "Enable chapter image generation for your videos for a more pleasing presentation while viewing.",
@@ -642,7 +649,12 @@
"OptionLow": "Low",
"HeaderSettings": "Settings",
"OptionAutomaticallySyncNewContent": "Automatically sync new content",
- "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.",
+ "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
"OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
- "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
+ "LabelItemLimit": "Item limit:",
+ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+ "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+ "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/hr.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/hr.json
index ef186d800..ea7dfc4e9 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/hr.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/hr.json
@@ -40,6 +40,11 @@
"LabelStopping": "Stopping",
"LabelCancelled": "(cancelled)",
"LabelFailed": "(failed)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Library Access",
+ "HeaderChannelAccess": "Channel Access",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Aborted by server shutdown)",
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
"HeaderDeleteTaskTrigger": "Delete Task Trigger",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Move right",
"ButtonBrowseOnlineImages": "Browse online images",
"HeaderDeleteItem": "Delete Item",
- "ConfirmDeleteItem": "Are you sure you wish to delete this item from your library?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Please enter a name or an external Id.",
"MessageValueNotCorrect": "The value entered is not correct. Please try again.",
"MessageItemSaved": "Item saved.",
@@ -396,6 +401,7 @@
"LabelYear": "Year:",
"LabelDateOfBirth": "Date of birth:",
"LabelBirthYear": "Birth year:",
+ "LabelBirthDate": "Birth date:",
"LabelDeathDate": "Death date:",
"HeaderRemoveMediaLocation": "Remove Media Location",
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Media Locations",
"LabelFolderTypeValue": "Folder type: {0}",
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
- "FolderTypeMixed": "Mixed movies & tv",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Movies",
"FolderTypeMusic": "Music",
"FolderTypeAdultVideos": "Adult videos",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Home videos",
"FolderTypeGames": "Games",
"FolderTypeBooks": "Books",
- "FolderTypeTvShows": "TV shows",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Filmovi",
"TabSeries": "Series",
"TabEpisodes": "Epizode",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
"MessageEnjoyYourStay": "Enjoy your stay",
"DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Easily create user accounts for your friends and family, each with their own permissions, library access, parental controls and more.",
"DashboardTourCinemaMode": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
"DashboardTourChapters": "Enable chapter image generation for your videos for a more pleasing presentation while viewing.",
@@ -642,7 +649,12 @@
"OptionLow": "Low",
"HeaderSettings": "Settings",
"OptionAutomaticallySyncNewContent": "Automatically sync new content",
- "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.",
+ "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
"OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
- "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
+ "LabelItemLimit": "Item limit:",
+ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+ "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+ "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/it.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/it.json
index 8e324b335..f6d57b44c 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/it.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/it.json
@@ -40,6 +40,11 @@
"LabelStopping": "Sto fermando",
"LabelCancelled": "(cancellato)",
"LabelFailed": "(fallito)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Accesso libreria",
+ "HeaderChannelAccess": "Accesso canali",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Interrotto dalla chiusura del server)",
"LabelScheduledTaskLastRan": "Ultima esecuzione {0}, taking {1}.",
"HeaderDeleteTaskTrigger": "Elimina Operazione pianificata",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Muovi a destra",
"ButtonBrowseOnlineImages": "Sfoglia le immagini Online",
"HeaderDeleteItem": "Elimina elemento",
- "ConfirmDeleteItem": "Sei sicuro di voler eliminare questo elemento dalla tua libreria?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Inserisci il nome o id esterno.",
"MessageValueNotCorrect": "Il valore inserito non \u00e8 corretto.Riprova di nuovo.",
"MessageItemSaved": "Elemento salvato.",
@@ -396,6 +401,7 @@
"LabelYear": "Anno:",
"LabelDateOfBirth": "Data nascita:",
"LabelBirthYear": "Anno nascita:",
+ "LabelBirthDate": "Birth date:",
"LabelDeathDate": "Anno morte:",
"HeaderRemoveMediaLocation": "Rimuovi percorso media",
"MessageConfirmRemoveMediaLocation": "Sei sicuro di voler rimuovere questa posizione?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Posizioni Media",
"LabelFolderTypeValue": "Tipo cartella: {0}",
"LabelPathSubstitutionHelp": "Opzionale: cambio Path pu\u00f2 mappare i percorsi del server a condivisioni di rete che i clienti possono accedere per la riproduzione diretta.",
- "FolderTypeMixed": "Misto Film & Tv",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Film",
"FolderTypeMusic": "Musica",
"FolderTypeAdultVideos": "Video per adulti",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Video personali",
"FolderTypeGames": "Giochi",
"FolderTypeBooks": "Libri",
- "FolderTypeTvShows": "Serie TV",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Film",
"TabSeries": "Serie TV",
"TabEpisodes": "Episodi",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "e controlla facilmente altri dispositivi e applicazioni Media Browser",
"MessageEnjoyYourStay": "Godetevi il vostro soggiorno",
"DashboardTourDashboard": "Il pannello di controllo del server consente di monitorare il vostro server e gli utenti. Potrai sempre sapere chi sta facendo cosa e dove sono.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Facile creazione di account utente per i vostri amici e la famiglia, ognuno con le proprie autorizzazioni, accesso alla libreria, controlli parentali e altro ancora.",
"DashboardTourCinemaMode": "Modalit\u00e0 Cinema porta l'esperienza del teatro direttamente nel tuo salotto con la possibilit\u00e0 di giocare trailer e intro personalizzati prima la caratteristica principale.",
"DashboardTourChapters": "Abilita capitolo generazione di immagini per i vostri video per una presentazione pi\u00f9 gradevole durante la visualizzazione.",
@@ -642,7 +649,12 @@
"OptionLow": "Low",
"HeaderSettings": "Settings",
"OptionAutomaticallySyncNewContent": "Automatically sync new content",
- "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.",
+ "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
"OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
- "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
+ "LabelItemLimit": "Item limit:",
+ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+ "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+ "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
index b90370246..ed52684c1 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
@@ -40,6 +40,11 @@
"LabelStopping": "Stopping",
"LabelCancelled": "(cancelled)",
"LabelFailed": "(failed)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Library Access",
+ "HeaderChannelAccess": "Channel Access",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Aborted by server shutdown)",
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
"HeaderDeleteTaskTrigger": "Delete Task Trigger",
@@ -251,7 +256,7 @@
"ButtonMoveRight": "Move right",
"ButtonBrowseOnlineImages": "Browse online images",
"HeaderDeleteItem": "Delete Item",
- "ConfirmDeleteItem": "Are you sure you wish to delete this item from your library?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Please enter a name or an external Id.",
"MessageValueNotCorrect": "The value entered is not correct. Please try again.",
"MessageItemSaved": "Item saved.",
@@ -402,6 +407,7 @@
"LabelYear": "Year:",
"LabelDateOfBirth": "Date of birth:",
"LabelBirthYear": "Birth year:",
+ "LabelBirthDate": "Birth date:",
"LabelDeathDate": "Death date:",
"HeaderRemoveMediaLocation": "Remove Media Location",
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
@@ -416,9 +422,9 @@
"ButtonChangeType": "Change type",
"ButtonRemove": "Remove",
"HeaderMediaLocations": "Media Locations",
- "LabelFolderTypeValue": "Folder type: {0}",
+ "LabelContentTypeValue": "Content type: {0}",
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
- "FolderTypeMixed": "Mixed movies & tv",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Movies",
"FolderTypeMusic": "Music",
"FolderTypeAdultVideos": "Adult videos",
@@ -427,7 +433,7 @@
"FolderTypeHomeVideos": "Home videos",
"FolderTypeGames": "Games",
"FolderTypeBooks": "Books",
- "FolderTypeTvShows": "TV shows",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Movies",
"TabSeries": "Series",
"TabEpisodes": "Episodes",
@@ -595,6 +601,7 @@
"WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
"MessageEnjoyYourStay": "Enjoy your stay",
"DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Easily create user accounts for your friends and family, each with their own permissions, library access, parental controls and more.",
"DashboardTourCinemaMode": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
"DashboardTourChapters": "Enable chapter image generation for your videos for a more pleasing presentation while viewing.",
@@ -650,9 +657,12 @@
"OptionLow": "Low",
"HeaderSettings": "Settings",
"OptionAutomaticallySyncNewContent": "Automatically sync new content",
- "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.",
+ "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
"OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
"OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
"LabelItemLimit": "Item limit:",
- "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced."
+ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+ "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+ "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
}
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json
index 85cd90d11..b8fe0fa31 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json
@@ -40,6 +40,11 @@
"LabelStopping": "\u0422\u043e\u049b\u0442\u0430\u0442\u044b\u043b\u0443\u0434\u0430",
"LabelCancelled": "(\u0431\u043e\u043b\u0434\u044b\u0440\u044b\u043b\u043c\u0430\u0434\u044b)",
"LabelFailed": "(\u0441\u04d9\u0442\u0441\u0456\u0437)",
+ "ButtonHelp": "\u0410\u043d\u044b\u049b\u0442\u0430\u043c\u0430",
+ "HeaderLibraryAccess": "\u0422\u0430\u0441\u0443\u0448\u044b\u0445\u0430\u043d\u0430\u0493\u0430 \u049b\u0430\u0442\u044b\u043d\u0430\u0441\u0443",
+ "HeaderChannelAccess": "\u0410\u0440\u043d\u0430\u0493\u0430 \u049b\u0430\u0442\u044b\u043d\u0430\u0441\u0443",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(\u0421\u0435\u0440\u0432\u0435\u0440 \u0436\u04b1\u043c\u044b\u0441\u044b \u0430\u044f\u049b\u0442\u0430\u043b\u0443\u044b\u043d\u0430 \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u0442\u044b \u04af\u0437\u0456\u043b\u0434\u0456)",
"LabelScheduledTaskLastRan": "\u0421\u043e\u04a3\u0493\u044b \u0456\u0441\u043a\u0435 \u049b\u043e\u0441\u044b\u043b\u0493\u0430\u043d\u044b {0}, {1} \u0443\u0430\u049b\u044b\u0442 \u0430\u043b\u0434\u044b.",
"HeaderDeleteTaskTrigger": "\u0422\u0430\u043f\u0441\u044b\u0440\u043c\u0430 \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u0456\u043d \u0436\u043e\u044e",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "\u041e\u04a3\u0493\u0430 \u0436\u044b\u043b\u0436\u044b\u0442\u0443",
"ButtonBrowseOnlineImages": "\u0416\u0435\u043b\u0456\u0434\u0435\u0433\u0456 \u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440\u0434\u0456 \u0448\u043e\u043b\u0443",
"HeaderDeleteItem": "\u042d\u043b\u0435\u043c\u0435\u043d\u0442\u0442\u0456 \u0436\u043e\u044e",
- "ConfirmDeleteItem": "\u0428\u044b\u043d\u044b\u043c\u0435\u043d \u043e\u0441\u044b \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0442\u0456 \u0442\u0430\u0441\u0443\u0448\u044b\u0445\u0430\u043d\u0430\u0434\u0430\u043d \u0436\u043e\u044e \u049b\u0430\u0436\u0435\u0442 \u043f\u0435?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "\u0410\u0442\u044b\u043d \u043d\u0435\u043c\u0435\u0441\u0435 \u0441\u044b\u0440\u0442\u049b\u044b ID \u0435\u043d\u0433\u0456\u0437\u0456\u04a3\u0456\u0437.",
"MessageValueNotCorrect": "\u0415\u043d\u0433\u0456\u0437\u0456\u043b\u0433\u0435\u043d \u043c\u04d9\u043d \u0434\u04b1\u0440\u044b\u0441 \u0435\u043c\u0435\u0441. \u04d8\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437.",
"MessageItemSaved": "\u042d\u043b\u0435\u043c\u0435\u043d\u0442 \u0441\u0430\u049b\u0442\u0430\u043b\u0434\u044b.",
@@ -396,6 +401,7 @@
"LabelYear": "\u0416\u044b\u043b\u044b:",
"LabelDateOfBirth": "\u0422\u0443\u0493\u0430\u043d \u043a\u04af\u043d\u0456:",
"LabelBirthYear": "\u0422\u0443\u0493\u0430\u043d \u0436\u044b\u043b\u044b:",
+ "LabelBirthDate": "\u0422\u0443\u0493\u0430\u043d \u043a\u04af\u043d\u0456:",
"LabelDeathDate": "\u04e8\u043b\u0433\u0435\u043d \u043a\u04af\u043d\u0456:",
"HeaderRemoveMediaLocation": "\u0422\u0430\u0441\u0443\u0448\u044b\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u043e\u0440\u043d\u0430\u043b\u0430\u0441\u0443\u044b\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u0443",
"MessageConfirmRemoveMediaLocation": "\u0428\u044b\u043d\u044b\u043c\u0435\u043d \u043e\u0441\u044b \u043e\u0440\u043d\u0430\u043b\u0430\u0441\u0443\u0434\u044b \u0430\u043b\u0430\u0441\u0442\u0430\u0443 \u049b\u0430\u0436\u0435\u0442 \u043f\u0435?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "\u0422\u0430\u0441\u0443\u0448\u044b \u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u043e\u0440\u043d\u0430\u043b\u0430\u0441\u0443\u043b\u0430\u0440\u044b",
"LabelFolderTypeValue": "\u049a\u0430\u043b\u0442\u0430 \u0442\u04af\u0440\u0456: {0}",
"LabelPathSubstitutionHelp": "\u049a\u0430\u043b\u0430\u0443 \u0431\u043e\u0439\u044b\u043d\u0448\u0430: \u0416\u043e\u043b \u0430\u043b\u043c\u0430\u0441\u0442\u044b\u0440\u0443 \u0430\u0440\u049b\u044b\u043b\u044b \u0441\u0435\u0440\u0432\u0435\u0440\u0434\u0435\u0433\u0456 \u0436\u043e\u043b\u0434\u0430\u0440\u0434\u044b \u0442\u0456\u043a\u0435\u043b\u0435\u0439 \u043e\u0439\u043d\u0430\u0442\u0443 \u04af\u0448\u0456\u043d \u043a\u043b\u0438\u0435\u043d\u0442\u0442\u0435\u0440 \u049b\u0430\u0442\u044b\u043d\u0430\u0441\u0430 \u0430\u043b\u0430\u0442\u044b\u043d \u0436\u0435\u043b\u0456\u043b\u0456\u043a \u049b\u043e\u0440 \u043a\u04e9\u0437\u0434\u0435\u0440\u0456\u043c\u0435\u043d \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u0442\u044b\u0440\u0443\u044b \u043c\u04af\u043c\u043a\u0456\u043d.",
- "FolderTypeMixed": "\u0410\u0440\u0430\u043b\u0430\u0441 (\u043a\u0438\u043d\u043e \u0436\u04d9\u043d\u0435 \u0442\u0434)",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "\u0424\u0438\u043b\u044c\u043c\u0434\u0435\u0440",
"FolderTypeMusic": "\u041c\u0443\u0437\u044b\u043a\u0430",
"FolderTypeAdultVideos": "\u0415\u0440\u0435\u0441\u0435\u043a\u0442\u0456\u043a \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "\u04ae\u0439 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440\u0456",
"FolderTypeGames": "\u041e\u0439\u044b\u043d\u0434\u0430\u0440",
"FolderTypeBooks": "\u041a\u0456\u0442\u0430\u043f\u0442\u0430\u0440",
- "FolderTypeTvShows": "\u0422\u0414 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043c\u0434\u0435\u0440\u0456",
+ "FolderTypeTvShows": "\u0422\u0414",
"TabMovies": "\u0424\u0438\u043b\u044c\u043c\u0434\u0435\u0440",
"TabSeries": "\u0421\u0435\u0440\u0438\u0430\u043b",
"TabEpisodes": "\u042d\u043f\u0438\u0437\u043e\u0434\u0442\u0430\u0440",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "\u0441\u043e\u043d\u044b\u043c\u0435\u043d \u049b\u0430\u0442\u0430\u0440 \u0431\u0430\u0441\u049b\u0430 \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u043b\u0430\u0440\u0434\u044b \u0436\u04d9\u043d\u0435 Media Browser \u049b\u043e\u043b\u0434\u0430\u043d\u0431\u0430\u043b\u0430\u0440\u044b\u043d \u0431\u0430\u0441\u049b\u0430\u0440\u0430\u0434\u044b",
"MessageEnjoyYourStay": "\u0416\u0430\u0493\u044b\u043c\u0434\u044b \u0435\u0440\u043c\u0435\u043a \u0435\u0442\u0456\u04a3\u0456\u0437",
"DashboardTourDashboard": "\u0421\u0435\u0440\u0432\u0435\u0440\u0434\u0456\u04a3 \u0431\u0430\u049b\u044b\u043b\u0430\u0443 \u0442\u0430\u049b\u0442\u0430\u0441\u044b \u0441\u0435\u0440\u0432\u0435\u0440\u0434\u0456 \u0436\u04d9\u043d\u0435 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043b\u0430\u0440\u0434\u044b \u0431\u0430\u049b\u044b\u043b\u0430\u0443\u044b \u043c\u04af\u043c\u043a\u0456\u043d\u0434\u0456\u0433\u0456\u043d\u0435 \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0435\u0434\u0456. \u041a\u0456\u043c \u043d\u0435 \u0456\u0441\u0442\u0435\u0433\u0435\u043d\u0456\u043d \u0436\u04d9\u043d\u0435 \u049b\u0430\u0439\u0434\u0430 \u0442\u04b1\u0440\u0493\u0430\u043d\u044b\u043d \u0431\u0456\u043b\u0456\u043f \u0436\u0430\u0442\u0430\u0441\u044b\u0437.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "\u0414\u043e\u0441\u0442\u0430\u0440\u044b\u04a3\u044b\u0437 \u0431\u0435\u043d \u043e\u0442\u0431\u0430\u0441\u044b\u04a3\u044b\u0437 \u04d9\u0440\u049b\u0430\u0439\u0441\u044b\u043d\u0430 \u04e9\u0437\u0456\u043d\u0456\u04a3 \u049b\u04b1\u049b\u044b\u049b\u0442\u0430\u0440\u044b, \u0442\u0430\u0441\u0443\u0448\u044b\u0445\u0430\u043d\u0430 \u049b\u0430\u0442\u044b\u043d\u0430\u0441\u0443\u044b, \u043c\u0430\u0437\u043c\u04b1\u043d \u0431\u0430\u0441\u049b\u0430\u0440\u0443\u044b \u0436\u04d9\u043d\u0435 \u0442.\u0431. \u0431\u0430\u0440 \u0442\u0456\u0440\u043a\u0435\u043b\u0433\u0456\u043b\u0435\u0440\u0456\u043d \u0436\u0435\u04a3\u0456\u043b \u0436\u0430\u0441\u0430\u04a3\u044b\u0437.",
"DashboardTourCinemaMode": "\u041a\u0438\u043d\u043e\u0442\u0435\u0430\u0442\u0440 \u0440\u0435\u0436\u0456\u043c\u0456 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043b\u0435\u0440\u0434\u0456 \u0436\u04d9\u043d\u0435 \u0442\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u043a\u04e9\u0440\u043d\u0435\u0443\u0434\u0456 \u0431\u0430\u0441\u0442\u044b \u049b\u0430\u0441\u0438\u0435\u0442\u0442\u0456\u04a3 \u0430\u043b\u0434\u044b\u043d\u0434\u0430 \u043e\u0439\u043d\u0430\u0442\u0443 \u049b\u0430\u0431\u0456\u043b\u0435\u0442\u0456\u043c\u0435\u043d \u043a\u0438\u043d\u043e \u043a\u04e9\u0440\u0441\u0435\u0442\u0435\u0442\u0456\u043d \u0437\u0430\u043b \u04d9\u0441\u0435\u0440\u0456\u043d \u049b\u043e\u043d\u0430\u049b\u0436\u0430\u0439\u044b\u04a3\u044b\u0437\u0493\u0430 \u0442\u0456\u043a\u0435\u043b\u0435\u0439 \u0436\u0435\u0442\u043a\u0456\u0437\u0435\u0434\u0456.",
"DashboardTourChapters": "\u0411\u0435\u0439\u043d\u0435\u043b\u0435\u0440\u0434\u0456 \u049b\u0430\u0440\u0430\u0493\u0430\u043d \u043a\u0435\u0437\u0434\u0435 \u04b1\u043d\u0430\u043c\u0434\u044b\u043b\u0430\u0443 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043c \u04af\u0448\u0456\u043d \u0441\u0430\u0445\u043d\u0430 \u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440\u0456\u043d \u0442\u0443\u0434\u044b\u0440\u0443\u044b\u043d \u049b\u043e\u0441\u044b\u04a3\u044b\u0437.",
@@ -642,7 +649,12 @@
"OptionLow": "\u0422\u04e9\u043c\u0435\u043d",
"HeaderSettings": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440",
"OptionAutomaticallySyncNewContent": "\u0416\u0430\u04a3\u0430 \u043c\u0430\u0437\u043c\u04b1\u043d\u0434\u044b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0442\u04af\u0440\u0434\u0435 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0434\u0430\u0443",
- "OptionAutomaticallySyncNewContentHelp": "\u041e\u0441\u044b \u049b\u0430\u043b\u0442\u0430\u043b\u0430\u0440\u0493\u0430 \u04af\u0441\u0442\u0435\u043b\u0456\u043d\u0433\u0435\u043d \u0436\u0430\u04a3\u0430 \u043c\u0430\u0437\u043c\u04b1\u043d \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u043c\u0435\u043d \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0442\u04af\u0440\u0434\u0435 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0434\u0430\u043b\u0430\u0434\u044b.",
+ "OptionAutomaticallySyncNewContentHelp": "\u041e\u0441\u044b \u0441\u0430\u043d\u0430\u0442\u049b\u0430 \u049b\u043e\u0441\u044b\u043b\u0493\u0430\u043d \u0436\u0430\u04a3\u0430 \u043c\u0430\u0437\u043c\u04b1\u043d \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0442\u04af\u0440\u0434\u0435 \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u043c\u0435\u043d \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0434\u0430\u043b\u044b\u043d\u0430\u0434\u044b.",
"OptionSyncUnwatchedVideosOnly": "\u0422\u0435\u043a \u049b\u0430\u043d\u0430 \u043a\u04e9\u0440\u0456\u043b\u043c\u0435\u0433\u0435\u043d \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440\u0434\u0456 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0434\u0430\u0443",
- "OptionSyncUnwatchedVideosOnlyHelp": "\u0422\u0435\u043a \u049b\u0430\u043d\u0430 \u049b\u0430\u0440\u0430\u0440\u043c\u0430\u0493\u0430\u043d \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0434\u0430\u043b\u0430\u0434\u044b, \u0436\u04d9\u043d\u0435 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440 \u049b\u0430\u0440\u0430\u043b\u0493\u0430\u043d\u043d\u0430\u043d \u043a\u0435\u0439\u0456\u043d \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u0434\u0430\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u043b\u0430\u0434\u044b."
+ "OptionSyncUnwatchedVideosOnlyHelp": "\u0422\u0435\u043a \u049b\u0430\u043d\u0430 \u049b\u0430\u0440\u0430\u0440\u043c\u0430\u0493\u0430\u043d \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0434\u0430\u043b\u044b\u043d\u0430\u0434\u044b, \u0436\u04d9\u043d\u0435 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440 \u049b\u0430\u0440\u0430\u043b\u0493\u0430\u043d\u043d\u0430\u043d \u043a\u0435\u0439\u0456\u043d \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u0434\u0430\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u043b\u0430\u0434\u044b.",
+ "LabelItemLimit": "\u042d\u043b\u0435\u043c\u0435\u043d\u0442\u0442\u0435\u0440 \u0448\u0435\u0433\u0456:",
+ "LabelItemLimitHelp": "\u049a\u0430\u043b\u0430\u0443 \u0431\u043e\u0439\u044b\u043d\u0448\u0430: \u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0434\u0430\u043b\u0430\u0442\u044b\u043d \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0442\u0435\u0440 \u0441\u0430\u043d\u044b \u04af\u0448\u0456\u043d \u0448\u0435\u043a\u0442\u0456 \u043e\u0440\u043d\u0430\u0442\u044b\u04a3\u044b\u0437.",
+ "MessageBookPluginRequired": "Bookshelf \u043f\u043b\u0430\u0433\u0438\u043d\u0456\u043d \u043e\u0440\u043d\u0430\u0442\u0443\u0434\u044b \u049b\u0430\u0436\u0435\u0442 \u0435\u0442\u0435\u0434\u0456",
+ "MessageGamePluginRequired": "GameBrowser \u043f\u043b\u0430\u0433\u0438\u043d\u0456\u043d \u043e\u0440\u043d\u0430\u0442\u0443\u0434\u044b \u049b\u0430\u0436\u0435\u0442 \u0435\u0442\u0435\u0434\u0456",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json
index 89aefed9d..4243d1f76 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json
@@ -40,6 +40,11 @@
"LabelStopping": "Stopping",
"LabelCancelled": "(cancelled)",
"LabelFailed": "(failed)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Library Access",
+ "HeaderChannelAccess": "Channel Access",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Aborted by server shutdown)",
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
"HeaderDeleteTaskTrigger": "Delete Task Trigger",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Move right",
"ButtonBrowseOnlineImages": "Browse online images",
"HeaderDeleteItem": "Delete Item",
- "ConfirmDeleteItem": "Are you sure you wish to delete this item from your library?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Please enter a name or an external Id.",
"MessageValueNotCorrect": "The value entered is not correct. Please try again.",
"MessageItemSaved": "Item saved.",
@@ -396,6 +401,7 @@
"LabelYear": "Year:",
"LabelDateOfBirth": "Date of birth:",
"LabelBirthYear": "Birth year:",
+ "LabelBirthDate": "Birth date:",
"LabelDeathDate": "Death date:",
"HeaderRemoveMediaLocation": "Remove Media Location",
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Media Locations",
"LabelFolderTypeValue": "Folder type: {0}",
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
- "FolderTypeMixed": "Mixed movies & tv",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Movies",
"FolderTypeMusic": "Music",
"FolderTypeAdultVideos": "Adult videos",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Home videos",
"FolderTypeGames": "Games",
"FolderTypeBooks": "Books",
- "FolderTypeTvShows": "TV shows",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Movies",
"TabSeries": "Series",
"TabEpisodes": "Episodes",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
"MessageEnjoyYourStay": "Enjoy your stay",
"DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Easily create user accounts for your friends and family, each with their own permissions, library access, parental controls and more.",
"DashboardTourCinemaMode": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
"DashboardTourChapters": "Enable chapter image generation for your videos for a more pleasing presentation while viewing.",
@@ -642,7 +649,12 @@
"OptionLow": "Low",
"HeaderSettings": "Settings",
"OptionAutomaticallySyncNewContent": "Automatically sync new content",
- "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.",
+ "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
"OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
- "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
+ "LabelItemLimit": "Item limit:",
+ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+ "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+ "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json
index a5fd9bb9b..2e53bc8a2 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json
@@ -40,6 +40,11 @@
"LabelStopping": "Stoppe",
"LabelCancelled": "(kansellert)",
"LabelFailed": "(Feilet)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Bibliotek tilgang",
+ "HeaderChannelAccess": "Kanal tilgang",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Avbrutt av server shutdown)",
"LabelScheduledTaskLastRan": "Sist kj\u00f8rt {0}, tar {1}.",
"HeaderDeleteTaskTrigger": "Slett Oppgave Trigger",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Flytt til h\u00f8yre",
"ButtonBrowseOnlineImages": "Bla igjennom bilder online",
"HeaderDeleteItem": "Slett element",
- "ConfirmDeleteItem": "Er du sikker p\u00e5 at du vil slette dette elementet fra ditt bibliotek?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Vennligst skriv ett navn eller en ekstern id.",
"MessageValueNotCorrect": "Verdien som ble skrevet er ikke korrekt. Vennligst pr\u00f8v igjen.",
"MessageItemSaved": "Element lagret.",
@@ -396,6 +401,7 @@
"LabelYear": "\u00c5r:",
"LabelDateOfBirth": "F\u00f8dseldato:",
"LabelBirthYear": "F\u00f8dsels\u00e5r:",
+ "LabelBirthDate": "Birth date:",
"LabelDeathDate": "D\u00f8ds dato:",
"HeaderRemoveMediaLocation": "Fjern Media Mappe",
"MessageConfirmRemoveMediaLocation": "Er du sikker p\u00e5 at du vil slette dette stedet??",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Media Steder",
"LabelFolderTypeValue": "Mappe type: {0}",
"LabelPathSubstitutionHelp": "Valgfritt: Sti erstatter kan koble server stier til nettverkressurser som klienter har tilgang til for direkte avspilling.",
- "FolderTypeMixed": "Mikset filmer & tv",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Filmer",
"FolderTypeMusic": "Musikk",
"FolderTypeAdultVideos": "Voksen videoer",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Hjemme videoer",
"FolderTypeGames": "Spill",
"FolderTypeBooks": "B\u00f8ker",
- "FolderTypeTvShows": "TV program",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Filmer",
"TabSeries": "Serier",
"TabEpisodes": "Episoder",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "og enkelt styrer andre enheter og mediabrowser apps",
"MessageEnjoyYourStay": "Nyt oppholdet",
"DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Opprett bruker kontoer enkelt for dine venner og familie, hver med deres egne rettigheter, bibliotek tillgang, foreldre kontroll og mere til.",
"DashboardTourCinemaMode": "Kino-modus bringer kinoopplevelsen direkte til din stue med muligheten til \u00e5 spille trailere og tilpassede introer f\u00f8r filmen begynner.",
"DashboardTourChapters": "Aktiver generering av kapittel bilder for dine videoer for en mer behagelig presentasjon mens du ser p\u00e5.",
@@ -642,7 +649,12 @@
"OptionLow": "Low",
"HeaderSettings": "Settings",
"OptionAutomaticallySyncNewContent": "Automatically sync new content",
- "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.",
+ "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
"OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
- "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
+ "LabelItemLimit": "Item limit:",
+ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+ "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+ "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json
index 53445c370..75a7d6bc2 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json
@@ -40,6 +40,11 @@
"LabelStopping": "Stoppen",
"LabelCancelled": "(Geannuleerd)",
"LabelFailed": "(mislukt)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Bibliotheek toegang",
+ "HeaderChannelAccess": "Kanaal toegang",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Afgebroken door afsluiten van de server)",
"LabelScheduledTaskLastRan": "Laatste keer {0}, duur {1}.",
"HeaderDeleteTaskTrigger": "Verwijderen Taak Trigger",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Verplaats naar rechts",
"ButtonBrowseOnlineImages": "Blader door online afbeeldingen",
"HeaderDeleteItem": "Item verwijderen",
- "ConfirmDeleteItem": "Weet u zeker dat u dit item uit uw bibliotheek wilt verwijderen?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Voer een naam of een externe Id in",
"MessageValueNotCorrect": "De ingevoerde waarde is niet correct. Probeer het opnieuw.",
"MessageItemSaved": "Item opgeslagen.",
@@ -396,6 +401,7 @@
"LabelYear": "Jaar:",
"LabelDateOfBirth": "Geboortedatum:",
"LabelBirthYear": "Geboorte jaar:",
+ "LabelBirthDate": "Geboortedatum:",
"LabelDeathDate": "Overlijdens datum:",
"HeaderRemoveMediaLocation": "Verwijder media locatie",
"MessageConfirmRemoveMediaLocation": "Weet je zeker dat je deze locatie wilt verwijderen?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Media Locaties",
"LabelFolderTypeValue": "Map type: {0}",
"LabelPathSubstitutionHelp": "Optioneel: Pad vervanging kan server paden naar netwerk locaties verwijzen zodat clients direct kunnen afspelen.",
- "FolderTypeMixed": "Gemixte films en TV",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Films",
"FolderTypeMusic": "Muziek",
"FolderTypeAdultVideos": "Adult video's",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Thuis video's",
"FolderTypeGames": "Games",
"FolderTypeBooks": "Boeken",
- "FolderTypeTvShows": "TV programma's",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Films",
"TabSeries": "Serie",
"TabEpisodes": "Afleveringen",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "en kan elke andere Media Browser app bedienen",
"MessageEnjoyYourStay": "Geniet van uw verblijf",
"DashboardTourDashboard": "Het server-dashboard steld u in staat uw server en uw gebruikers te monitoren . U zult altijd weten wie wat doet en waar ze zijn.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Maak gemakkelijk gebruikersaccounts voor uw vrienden en familie, elk met hun eigen machtigingen, bibliotheek toegang, ouderlijk toezicht en meer.",
"DashboardTourCinemaMode": "Cinema mode brengt de theater ervaring naar je woonkamer met de mogelijkheid om trailers en eigen intro's voor de film af te spelen",
"DashboardTourChapters": "Schakel hoofdstuk afbeeldingen genereren in voor uw video's voor een aantrekkelijker presentatie tijdens het kijken.",
@@ -642,7 +649,12 @@
"OptionLow": "Laag",
"HeaderSettings": "Instellingen",
"OptionAutomaticallySyncNewContent": "Nieuwe inhoud automatisch synchroniseren",
- "OptionAutomaticallySyncNewContentHelp": "Nieuwe inhoud in deze mappen zal automatisch gesynchroniseerd worden met het apparaat.",
+ "OptionAutomaticallySyncNewContentHelp": "Nieuwe inhoud toegevoegd aan deze categorie wordt automatisch gesynchroniseerd met het apparaat.",
"OptionSyncUnwatchedVideosOnly": "Synchroniseer alleen ongeziene video's",
- "OptionSyncUnwatchedVideosOnlyHelp": "Alleen ongeziene video's zulle gesynchroniseerd worden en van het apparaat verwijderd worden als ze gezien zijn."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Alleen ongeziene video's zulle gesynchroniseerd worden en van het apparaat verwijderd worden als ze gezien zijn.",
+ "LabelItemLimit": "Item limiet:",
+ "LabelItemLimitHelp": "Optioneel. Een limiet stellen aan het aantal items die zullen worden gesynchroniseerd.",
+ "MessageBookPluginRequired": "Vereist installatie van de Bookshelf plugin",
+ "MessageGamePluginRequired": "Vereist installatie van de GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json
index 98a8b5947..d703defa6 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json
@@ -40,6 +40,11 @@
"LabelStopping": "Stopping",
"LabelCancelled": "(cancelled)",
"LabelFailed": "(failed)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Library Access",
+ "HeaderChannelAccess": "Channel Access",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Aborted by server shutdown)",
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
"HeaderDeleteTaskTrigger": "Delete Task Trigger",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Move right",
"ButtonBrowseOnlineImages": "Browse online images",
"HeaderDeleteItem": "Delete Item",
- "ConfirmDeleteItem": "Are you sure you wish to delete this item from your library?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Please enter a name or an external Id.",
"MessageValueNotCorrect": "The value entered is not correct. Please try again.",
"MessageItemSaved": "Item saved.",
@@ -396,6 +401,7 @@
"LabelYear": "Year:",
"LabelDateOfBirth": "Date of birth:",
"LabelBirthYear": "Birth year:",
+ "LabelBirthDate": "Birth date:",
"LabelDeathDate": "Death date:",
"HeaderRemoveMediaLocation": "Remove Media Location",
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Media Locations",
"LabelFolderTypeValue": "Folder type: {0}",
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
- "FolderTypeMixed": "Mixed movies & tv",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Movies",
"FolderTypeMusic": "Music",
"FolderTypeAdultVideos": "Adult videos",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Home videos",
"FolderTypeGames": "Games",
"FolderTypeBooks": "Books",
- "FolderTypeTvShows": "TV shows",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Filmy",
"TabSeries": "Series",
"TabEpisodes": "Odcinki",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
"MessageEnjoyYourStay": "Enjoy your stay",
"DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Easily create user accounts for your friends and family, each with their own permissions, library access, parental controls and more.",
"DashboardTourCinemaMode": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
"DashboardTourChapters": "Enable chapter image generation for your videos for a more pleasing presentation while viewing.",
@@ -642,7 +649,12 @@
"OptionLow": "Low",
"HeaderSettings": "Settings",
"OptionAutomaticallySyncNewContent": "Automatically sync new content",
- "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.",
+ "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
"OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
- "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
+ "LabelItemLimit": "Item limit:",
+ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+ "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+ "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json
index 492b402ca..96f55451c 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json
@@ -40,6 +40,11 @@
"LabelStopping": "Parando",
"LabelCancelled": "(cancelado)",
"LabelFailed": "(falhou)",
+ "ButtonHelp": "Ajuda",
+ "HeaderLibraryAccess": "Acesso \u00e0 Biblioteca",
+ "HeaderChannelAccess": "Acesso ao Canal",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Abortada pelo desligamento do servidor)",
"LabelScheduledTaskLastRan": "\u00daltima execu\u00e7\u00e3o {0}, demorando {1}.",
"HeaderDeleteTaskTrigger": "Excluir Disparador da Tarefa",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Mover \u00e0 direita",
"ButtonBrowseOnlineImages": "Procurar imagens online",
"HeaderDeleteItem": "Excluir item",
- "ConfirmDeleteItem": "Deseja realmente excluir este item de sua biblioteca?",
+ "ConfirmDeleteItem": "Excluir este item o excluir\u00e1 do sistema de arquivos e tamb\u00e9m da biblioteca de m\u00eddias. Deseja realmente continuar?",
"MessagePleaseEnterNameOrId": "Por favor, digite um nome ou Id externo.",
"MessageValueNotCorrect": "O valor digitado n\u00e3o est\u00e1 correto. Por favor, tente novamente.",
"MessageItemSaved": "Item salvo.",
@@ -396,6 +401,7 @@
"LabelYear": "Ano:",
"LabelDateOfBirth": "Data de nascimento:",
"LabelBirthYear": "Ano de nascimento:",
+ "LabelBirthDate": "Data de nascimento:",
"LabelDeathDate": "Data da morte:",
"HeaderRemoveMediaLocation": "Remover Localiza\u00e7\u00e3o da M\u00eddia",
"MessageConfirmRemoveMediaLocation": "Deseja realmente remover esta localiza\u00e7\u00e3o?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Localiza\u00e7\u00f5es de M\u00eddia",
"LabelFolderTypeValue": "Tipo de pasta: {0}",
"LabelPathSubstitutionHelp": "Opcional: Substitui\u00e7\u00e3o de caminho pode mapear caminhos do servidor para compartilhamentos de rede de forma a que os clientes possam acessar para reprodu\u00e7\u00e3o direta.",
- "FolderTypeMixed": "Filmes & tv misturados",
+ "FolderTypeUnset": "Indefinida (conte\u00fado misto)",
"FolderTypeMovies": "Filmes",
"FolderTypeMusic": "M\u00fasica",
"FolderTypeAdultVideos": "V\u00eddeos adultos",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "V\u00eddeos caseiros",
"FolderTypeGames": "Jogos",
"FolderTypeBooks": "Livros",
- "FolderTypeTvShows": "S\u00e9ries de TV",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Filmes",
"TabSeries": "S\u00e9ries",
"TabEpisodes": "Epis\u00f3dios",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "e controle facilmente outros dispositivos e apps do Media Browser",
"MessageEnjoyYourStay": "Divirta-se",
"DashboardTourDashboard": "O painel do servidor permite monitorar seu servidor e seus usu\u00e1rios. Voc\u00ea sempre poder\u00e1 saber quem est\u00e1 fazendo o qu\u00ea e onde est\u00e3o.",
+ "DashboardTourHelp": "A ajuda dentro da app fornece bot\u00f5es para abrir p\u00e1ginas wiki relacionadas ao conte\u00fado na tela.",
"DashboardTourUsers": "Crie facilmente contas de usu\u00e1rios para seus amigos e fam\u00edlia, cada um com sua permiss\u00e3o, acesso \u00e0 biblioteca, controle parental e mais.",
"DashboardTourCinemaMode": "O modo cinema traz a experi\u00eancia do cinema para sua sala, permitindo reproduzir trailers e intros personalizadas antes da fun\u00e7\u00e3o principal.",
"DashboardTourChapters": "Ative a gera\u00e7\u00e3o de imagem do cap\u00edtulo para seus v\u00eddeos para ter uma apresenta\u00e7\u00e3o mais prazeirosa.",
@@ -642,7 +649,12 @@
"OptionLow": "Baixa",
"HeaderSettings": "Ajustes",
"OptionAutomaticallySyncNewContent": "Sincronizar novo conte\u00fado automaticamente",
- "OptionAutomaticallySyncNewContentHelp": "Novo conte\u00fado adicionado a estas pastas ser\u00e1 automaticamente sincronizado com o dispositivo.",
+ "OptionAutomaticallySyncNewContentHelp": "Novo conte\u00fado adicionado a esta categoria ser\u00e1 automaticamente sincronizado com o dispositivo.",
"OptionSyncUnwatchedVideosOnly": "Sincronizar apenas v\u00eddeos n\u00e3o assistidos",
- "OptionSyncUnwatchedVideosOnlyHelp": "Apenas v\u00eddeos n\u00e3o assistidos ser\u00e3o sincronizados, e os v\u00eddeos ser\u00e3o removidos do dispositivo assim que forem assistidos."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Apenas v\u00eddeos n\u00e3o assistidos ser\u00e3o sincronizados, e os v\u00eddeos ser\u00e3o removidos do dispositivo assim que forem assistidos.",
+ "LabelItemLimit": "Limite de itens:",
+ "LabelItemLimitHelp": "Opcional. Defina o n\u00famero limite de itens que ser\u00e3o sincronizados.",
+ "MessageBookPluginRequired": "Requer a instala\u00e7\u00e3o do plugin Bookshelf",
+ "MessageGamePluginRequired": "Requer a instala\u00e7\u00e3o do plugin GameBrowser",
+ "MessageUnsetContentHelp": "O conte\u00fado ser\u00e1 exibido em pastas simples. Para melhor resultado, use o gerenciador de metadados para definir os tipos de conte\u00fado das sub-pastas."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json
index 5007ae444..cb7db972a 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json
@@ -36,10 +36,15 @@
"LabelMovie": "Movie",
"LabelMusicVideo": "Music Video",
"LabelEpisode": "Episode",
- "LabelSeries": "Series",
+ "LabelSeries": "S\u00e9rie",
"LabelStopping": "Stopping",
"LabelCancelled": "(cancelled)",
- "LabelFailed": "(failed)",
+ "LabelFailed": "(falhou)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Library Access",
+ "HeaderChannelAccess": "Channel Access",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Aborted by server shutdown)",
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
"HeaderDeleteTaskTrigger": "Delete Task Trigger",
@@ -63,7 +68,7 @@
"ButtonPlay": "Reproduzir",
"ButtonEdit": "Editar",
"ButtonQueue": "Queue",
- "ButtonPlayTrailer": "Play trailer",
+ "ButtonPlayTrailer": "Reproduzir trailer",
"ButtonPlaylist": "Playlist",
"ButtonPreviousTrack": "Faixa Anterior",
"LabelEnabled": "Enabled",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Move right",
"ButtonBrowseOnlineImages": "Browse online images",
"HeaderDeleteItem": "Delete Item",
- "ConfirmDeleteItem": "Are you sure you wish to delete this item from your library?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Please enter a name or an external Id.",
"MessageValueNotCorrect": "The value entered is not correct. Please try again.",
"MessageItemSaved": "Item saved.",
@@ -384,7 +389,7 @@
"PersonTypePerson": "Person",
"LabelTitleDisplayOrder": "Title display order:",
"OptionSortName": "Sort name",
- "OptionReleaseDate": "Release date",
+ "OptionReleaseDate": "Data de lan\u00e7amento",
"LabelSeasonNumber": "N\u00famero da temporada:",
"LabelDiscNumber": "Disc number",
"LabelParentNumber": "Parent number",
@@ -396,6 +401,7 @@
"LabelYear": "Year:",
"LabelDateOfBirth": "Date of birth:",
"LabelBirthYear": "Birth year:",
+ "LabelBirthDate": "Birth date:",
"LabelDeathDate": "Death date:",
"HeaderRemoveMediaLocation": "Remove Media Location",
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Media Locations",
"LabelFolderTypeValue": "Folder type: {0}",
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
- "FolderTypeMixed": "Mixed movies & tv",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Movies",
"FolderTypeMusic": "Music",
"FolderTypeAdultVideos": "Adult videos",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Home videos",
"FolderTypeGames": "Games",
"FolderTypeBooks": "Books",
- "FolderTypeTvShows": "TV shows",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Filmes",
"TabSeries": "S\u00e9ries",
"TabEpisodes": "Epis\u00f3dios",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
"MessageEnjoyYourStay": "Enjoy your stay",
"DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Easily create user accounts for your friends and family, each with their own permissions, library access, parental controls and more.",
"DashboardTourCinemaMode": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
"DashboardTourChapters": "Enable chapter image generation for your videos for a more pleasing presentation while viewing.",
@@ -642,7 +649,12 @@
"OptionLow": "Low",
"HeaderSettings": "Settings",
"OptionAutomaticallySyncNewContent": "Automatically sync new content",
- "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.",
+ "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
"OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
- "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
+ "LabelItemLimit": "Item limit:",
+ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+ "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+ "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json
index 15e489fb3..e39e94f93 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json
@@ -40,6 +40,11 @@
"LabelStopping": "\u041e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430",
"LabelCancelled": "(\u043e\u0442\u043c\u0435\u043d\u0435\u043d\u043e)",
"LabelFailed": "(\u043d\u0435\u0443\u0434\u0430\u0447\u043d\u043e)",
+ "ButtonHelp": "\u0421\u043f\u0440\u0430\u0432\u043a\u0430",
+ "HeaderLibraryAccess": "\u0414\u043e\u0441\u0442\u0443\u043f \u043a \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0435",
+ "HeaderChannelAccess": "\u0414\u043e\u0441\u0442\u0443\u043f \u043a \u043a\u0430\u043d\u0430\u043b\u0430\u043c",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(\u041f\u0440\u0435\u0440\u0432\u0430\u043d\u043e \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0430)",
"LabelScheduledTaskLastRan": "\u0412\u044b\u043f\u043e\u043b\u043d\u044f\u043b\u0430\u0441\u044c {0}, \u0437\u0430\u043d\u044f\u043b\u0430 {1}.",
"HeaderDeleteTaskTrigger": "\u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u0430 \u0437\u0430\u0434\u0430\u0447\u0438",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "\u0414\u0432\u0438\u0433\u0430\u0442\u044c \u0432\u043f\u0440\u0430\u0432\u043e",
"ButtonBrowseOnlineImages": "\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0440\u0438\u0441\u0443\u043d\u043a\u0438 \u0432 \u0441\u0435\u0442\u0438",
"HeaderDeleteItem": "\u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430",
- "ConfirmDeleteItem": "\u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0438\u0437 \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438?",
+ "ConfirmDeleteItem": "\u041f\u0440\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430, \u043e\u043d \u0443\u0434\u0430\u043b\u0438\u0442\u0441\u044f \u0438 \u0438\u0437 \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b, \u0438 \u0438\u0437 \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438. \u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c?",
"MessagePleaseEnterNameOrId": "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0438\u043b\u0438 \u0432\u043d\u0435\u0448\u043d\u0438\u0439 ID.",
"MessageValueNotCorrect": "\u0412\u0432\u0435\u0434\u0451\u043d\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043d\u0435 \u0432\u0435\u0440\u043d\u043e. \u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443.",
"MessageItemSaved": "\u042d\u043b\u0435\u043c\u0435\u043d\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u0451\u043d.",
@@ -396,6 +401,7 @@
"LabelYear": "\u0413\u043e\u0434:",
"LabelDateOfBirth": "\u0414\u0430\u0442\u0430 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f:",
"LabelBirthYear": "\u0413\u043e\u0434 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f:",
+ "LabelBirthDate": "\u0414\u0430\u0442\u0430 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f:",
"LabelDeathDate": "\u0414\u0430\u0442\u0430 \u0441\u043c\u0435\u0440\u0442\u0438:",
"HeaderRemoveMediaLocation": "\u0418\u0437\u044a\u044f\u0442\u0438\u0435 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445",
"MessageConfirmRemoveMediaLocation": "\u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u0438\u0437\u044a\u044f\u0442\u044c \u044d\u0442\u043e \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "\u0420\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445",
"LabelFolderTypeValue": "\u0422\u0438\u043f \u043f\u0430\u043f\u043a\u0438: {0}",
"LabelPathSubstitutionHelp": "\u041d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e: \u041f\u043e\u0434\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043f\u0443\u0442\u0435\u0439 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0445 \u043f\u0443\u0442\u0435\u0439 \u0441\u043e \u0441\u0435\u0442\u0435\u0432\u044b\u043c\u0438 \u043e\u0431\u0449\u0438\u043c\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c \u0434\u043b\u044f \u043f\u0440\u044f\u043c\u043e\u0433\u043e \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f.",
- "FolderTypeMixed": "\u0421\u043c\u0435\u0448\u0430\u043d\u043d\u044b\u0439 (\u0444\u0438\u043b\u044c\u043c\u044b \u0438 \u0422\u0412)",
+ "FolderTypeUnset": "\u041d\u0435\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044b\u0439 (\u0440\u0430\u0437\u043d\u043e\u0442\u0438\u043f\u043d\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435)",
"FolderTypeMovies": "\u0424\u0438\u043b\u044c\u043c\u044b",
"FolderTypeMusic": "\u041c\u0443\u0437\u044b\u043a\u0430",
"FolderTypeAdultVideos": "\u0412\u0437\u0440\u043e\u0441\u043b\u044b\u0435 \u0432\u0438\u0434\u0435\u043e",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "\u0414\u043e\u043c\u0430\u0448\u043d\u0438\u0435 \u0432\u0438\u0434\u0435\u043e",
"FolderTypeGames": "\u0418\u0433\u0440\u044b",
"FolderTypeBooks": "\u041a\u043d\u0438\u0433\u0438",
- "FolderTypeTvShows": "\u0422\u0412 \u0446\u0438\u043a\u043b\u044b",
+ "FolderTypeTvShows": "\u0422\u0412",
"TabMovies": "\u0424\u0438\u043b\u044c\u043c\u044b",
"TabSeries": "\u0421\u0435\u0440\u0438\u0430\u043b\u044b",
"TabEpisodes": "\u042d\u043f\u0438\u0437\u043e\u0434\u044b",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "\u0438 \u0441 \u043b\u0435\u0433\u043a\u043e\u0441\u0442\u044c\u044e \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438 \u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438 Media Browser",
"MessageEnjoyYourStay": "\u041f\u0440\u0438\u044f\u0442\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u044f\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0435\u043d\u0438\u044f",
"DashboardTourDashboard": "\u0421\u0435\u0440\u0432\u0435\u0440\u043d\u0430\u044f \u0418\u043d\u0444\u043e\u043f\u0430\u043d\u0435\u043b\u044c \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u043e \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044e \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439. \u0412\u044b \u0431\u0443\u0434\u0435\u0442\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0437\u043d\u0430\u0442\u044c, \u043a\u0442\u043e \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u0447\u0435\u043c \u0438 \u0433\u0434\u0435 \u043e\u043d\u0438 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f.",
+ "DashboardTourHelp": "\u0412\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u0430\u044f \u0441\u043f\u0440\u0430\u0432\u043a\u0430 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u043a\u043d\u043e\u043f\u043a\u0438, \u0447\u0442\u043e\u0431\u044b \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0442\u044c \u0432\u0438\u043a\u0438-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, \u043e\u0442\u043d\u043e\u0441\u044f\u0449\u0438\u0445\u0441\u044f \u043a \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044e \u044d\u043a\u0440\u0430\u043d\u0430.",
"DashboardTourUsers": "\u0421\u0432\u043e\u0431\u043e\u0434\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0443\u0447\u0451\u0442\u043d\u044b\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0434\u043b\u044f \u0432\u0430\u0448\u0438\u0445 \u0434\u0440\u0443\u0437\u0435\u0439 \u0438 \u0447\u043b\u0435\u043d\u043e\u0432 \u0441\u0435\u043c\u044c\u0438, \u043a\u0430\u0436\u0434\u0443\u044e \u0441 \u0438\u0445 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c\u0438 \u043f\u0440\u0430\u0432\u0430\u043c\u0438, \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c \u043a \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0435, \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435\u043c \u0438 \u0442.\u0434.",
"DashboardTourCinemaMode": "\u0420\u0435\u0436\u0438\u043c \u043a\u0438\u043d\u043e\u0442\u0435\u0430\u0442\u0440\u0430 \u043f\u0440\u0438\u0432\u043d\u043e\u0441\u0438\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043a\u0438\u043d\u043e\u0437\u0430\u043b\u0430 \u043f\u0440\u044f\u043c\u0438\u043a\u043e\u043c \u0432 \u0432\u0430\u0448\u0443 \u0433\u043e\u0441\u0442\u0438\u043d\u0443\u044e, \u0432\u043c\u0435\u0441\u0442\u0435 \u0441\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c\u044e \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u044b \u0438 \u043d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u0437\u0430\u0441\u0442\u0430\u0432\u043a\u0438 \u043f\u0435\u0440\u0435\u0434 \u0433\u043b\u0430\u0432\u043d\u044b\u043c \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u043c.",
"DashboardTourChapters": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u0435 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u0438\u0441\u0443\u043d\u043a\u043e\u0432 \u0441\u0446\u0435\u043d \u043a \u0432\u0438\u0434\u0435\u043e, \u0434\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u0438\u0432\u043b\u0435\u043a\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u043f\u0440\u0435\u0437\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430.",
@@ -641,8 +648,13 @@
"OptionMedium": "\u0421\u0440\u0435\u0434\u043d\u0435\u0435",
"OptionLow": "\u041d\u0438\u0437\u043a\u043e\u0435",
"HeaderSettings": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b",
- "OptionAutomaticallySyncNewContent": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435",
- "OptionAutomaticallySyncNewContentHelp": "\u041d\u043e\u0432\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435, \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0435 \u0432 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0430\u043f\u043a\u0438, \u0431\u0443\u0434\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441 \u0434\u0430\u043d\u043d\u044b\u043c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u043c.",
- "OptionSyncUnwatchedVideosOnly": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0435 \u0432\u0438\u0434\u0435\u043e\u0444\u0430\u0439\u043b\u044b.",
- "OptionSyncUnwatchedVideosOnlyHelp": "\u0422\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0435 \u0432\u0438\u0434\u0435\u043e\u0444\u0430\u0439\u043b\u044b \u0431\u0443\u0434\u0443\u0442 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f, \u0430 \u0432\u0438\u0434\u0435\u043e\u0444\u0430\u0439\u043b\u044b \u0431\u0443\u0434\u0443\u0442 \u0438\u0437\u044b\u043c\u0430\u0442\u044c\u0441\u044f \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043f\u043e\u0441\u043b\u0435 \u0438\u0445 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430."
+ "OptionAutomaticallySyncNewContent": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0438\u043d\u0445\u0440-\u0442\u044c \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435",
+ "OptionAutomaticallySyncNewContentHelp": "\u041d\u043e\u0432\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435, \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0435 \u0432 \u0434\u0430\u043d\u043d\u0443\u044e \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044e, \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u043c.",
+ "OptionSyncUnwatchedVideosOnly": "\u0421\u0438\u043d\u0445\u0440-\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0435 \u0432\u0438\u0434\u0435\u043e",
+ "OptionSyncUnwatchedVideosOnlyHelp": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0435 \u0432\u0438\u0434\u0435\u043e, \u0430 \u0441\u0430\u043c\u0438 \u0432\u0438\u0434\u0435\u043e \u0438\u0437\u044b\u043c\u0430\u044e\u0442\u0441\u044f \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043f\u043e\u0441\u043b\u0435 \u0438\u0445 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430.",
+ "LabelItemLimit": "\u041f\u0440\u0435\u0434\u0435\u043b \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432:",
+ "LabelItemLimitHelp": "\u041d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e. \u0417\u0430\u0434\u0430\u0442\u044c \u043f\u0440\u0435\u0434\u0435\u043b\u044c\u043d\u043e\u0435 \u0447\u0438\u0441\u043b\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f.",
+ "MessageBookPluginRequired": "\u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043f\u043b\u0430\u0433\u0438\u043d\u0430 Bookshelf",
+ "MessageGamePluginRequired": "\u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043f\u043b\u0430\u0433\u0438\u043d\u0430 GameBrowser",
+ "MessageUnsetContentHelp": "\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u043e\u0431\u044b\u0447\u043d\u044b\u0435 \u043f\u0430\u043f\u043a\u0438. \u0414\u043b\u044f \u043d\u0430\u0438\u043b\u0443\u0447\u0448\u0438\u0445 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445, \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0437\u043d\u0430\u0447\u0430\u0442\u044c \u0442\u0438\u043f \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f \u043f\u043e\u0434\u043f\u0430\u043f\u043e\u043a."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json
index a0b86f576..9aa55bb90 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json
@@ -40,6 +40,11 @@
"LabelStopping": "Avbryter",
"LabelCancelled": "(avbr\u00f6ts)",
"LabelFailed": "(misslyckades)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Library Access",
+ "HeaderChannelAccess": "Channel Access",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(avbr\u00f6ts eftersom servern st\u00e4ngdes av)",
"LabelScheduledTaskLastRan": "Senast k\u00f6rd {0}, tog {1}",
"HeaderDeleteTaskTrigger": "Ta bort aktivitetsutl\u00f6sare",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "H\u00f6ger",
"ButtonBrowseOnlineImages": "Bl\u00e4ddra bland bilder online",
"HeaderDeleteItem": "Radera objekt",
- "ConfirmDeleteItem": "\u00c4r du s\u00e4ker p\u00e5 att du vill radera det h\u00e4r objektet fr\u00e5n biblioteket?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Ange ett namn eller externt id.",
"MessageValueNotCorrect": "Det angivna v\u00e4rdet \u00e4r felaktigt. Var god f\u00f6rs\u00f6k igen.",
"MessageItemSaved": "Objektet har sparats.",
@@ -396,6 +401,7 @@
"LabelYear": "\u00c5r:",
"LabelDateOfBirth": "F\u00f6delsedatum:",
"LabelBirthYear": "F\u00f6delse\u00e5r:",
+ "LabelBirthDate": "Birth date:",
"LabelDeathDate": "D\u00f6d:",
"HeaderRemoveMediaLocation": "Ta bort mediaplats",
"MessageConfirmRemoveMediaLocation": "\u00c4r du s\u00e4ker p\u00e5 att du vill ta bort den h\u00e4r platsen?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Lagringsplatser f\u00f6r media",
"LabelFolderTypeValue": "Typ av mapp: {0}",
"LabelPathSubstitutionHelp": "Tillval: S\u00f6kv\u00e4gsutbyte betyder att en plats p\u00e5 servern kopplas till en lokal fils\u00f6kv\u00e4g p\u00e5 en klient. P\u00e5 s\u00e5 s\u00e4tt f\u00e5r klienten direkt tillg\u00e5ng till material p\u00e5 servern och kan spela upp det direkt via n\u00e4tverket.",
- "FolderTypeMixed": "Blandat film & TV",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Filmer",
"FolderTypeMusic": "Musik",
"FolderTypeAdultVideos": "Inneh\u00e5ll f\u00f6r vuxna",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Hemvideor",
"FolderTypeGames": "Spel",
"FolderTypeBooks": "B\u00f6cker",
- "FolderTypeTvShows": "TV-serier",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Filmer",
"TabSeries": "Serie",
"TabEpisodes": "Avsnitt",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "och kan enkelt fj\u00e4rrstyra andra enheter och Media Browser-appar",
"MessageEnjoyYourStay": "Ha ett trevligt bes\u00f6k",
"DashboardTourDashboard": "Via serverns kontrollpanel kan du \u00f6vervaka din server och alla anv\u00e4ndare. Du kommer alltid att kunna veta vem som g\u00f6r vad och var de \u00e4r.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Skapa enkelt anv\u00e4ndarkonton f\u00f6r dina v\u00e4nner och familj, alla med sina egna beh\u00f6righeter, biblioteks \u00e5tkomst, f\u00f6r\u00e4ldrakontroll och mycket mer.",
"DashboardTourCinemaMode": "Biol\u00e4get g\u00f6r ditt vardagsrum till en biograf genom m\u00f6jligheten att visa trailers och egna vinjetter innan filmen b\u00f6rjar.",
"DashboardTourChapters": "Ta fram kapitelbildrutor fr\u00e5n videofiler f\u00f6r att f\u00e5 en snyggare presentation.",
@@ -642,7 +649,12 @@
"OptionLow": "Low",
"HeaderSettings": "Settings",
"OptionAutomaticallySyncNewContent": "Automatically sync new content",
- "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.",
+ "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
"OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
- "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
+ "LabelItemLimit": "Item limit:",
+ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+ "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+ "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json
index e8ecf0de0..c6713f948 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json
@@ -40,6 +40,11 @@
"LabelStopping": "Stopping",
"LabelCancelled": "(cancelled)",
"LabelFailed": "(failed)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Library Access",
+ "HeaderChannelAccess": "Channel Access",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Aborted by server shutdown)",
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
"HeaderDeleteTaskTrigger": "Delete Task Trigger",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Move right",
"ButtonBrowseOnlineImages": "Browse online images",
"HeaderDeleteItem": "Delete Item",
- "ConfirmDeleteItem": "Are you sure you wish to delete this item from your library?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Please enter a name or an external Id.",
"MessageValueNotCorrect": "The value entered is not correct. Please try again.",
"MessageItemSaved": "Item saved.",
@@ -396,6 +401,7 @@
"LabelYear": "Year:",
"LabelDateOfBirth": "Date of birth:",
"LabelBirthYear": "Birth year:",
+ "LabelBirthDate": "Birth date:",
"LabelDeathDate": "Death date:",
"HeaderRemoveMediaLocation": "Remove Media Location",
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Media Locations",
"LabelFolderTypeValue": "Folder type: {0}",
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
- "FolderTypeMixed": "Mixed movies & tv",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Movies",
"FolderTypeMusic": "Music",
"FolderTypeAdultVideos": "Adult videos",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Home videos",
"FolderTypeGames": "Games",
"FolderTypeBooks": "Books",
- "FolderTypeTvShows": "TV shows",
+ "FolderTypeTvShows": "TV",
"TabMovies": "Filmler",
"TabSeries": "Seriler",
"TabEpisodes": "B\u00f6l\u00fcmler",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
"MessageEnjoyYourStay": "Enjoy your stay",
"DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Easily create user accounts for your friends and family, each with their own permissions, library access, parental controls and more.",
"DashboardTourCinemaMode": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
"DashboardTourChapters": "Enable chapter image generation for your videos for a more pleasing presentation while viewing.",
@@ -642,7 +649,12 @@
"OptionLow": "Low",
"HeaderSettings": "Settings",
"OptionAutomaticallySyncNewContent": "Automatically sync new content",
- "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.",
+ "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
"OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
- "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
+ "LabelItemLimit": "Item limit:",
+ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+ "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+ "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json
index e94761156..351a69ceb 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json
@@ -40,6 +40,11 @@
"LabelStopping": "Stopping",
"LabelCancelled": "(cancelled)",
"LabelFailed": "(failed)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Library Access",
+ "HeaderChannelAccess": "Channel Access",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Aborted by server shutdown)",
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
"HeaderDeleteTaskTrigger": "Delete Task Trigger",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Move right",
"ButtonBrowseOnlineImages": "Browse online images",
"HeaderDeleteItem": "Delete Item",
- "ConfirmDeleteItem": "Are you sure you wish to delete this item from your library?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Please enter a name or an external Id.",
"MessageValueNotCorrect": "The value entered is not correct. Please try again.",
"MessageItemSaved": "Item saved.",
@@ -396,6 +401,7 @@
"LabelYear": "Year:",
"LabelDateOfBirth": "Date of birth:",
"LabelBirthYear": "Birth year:",
+ "LabelBirthDate": "Birth date:",
"LabelDeathDate": "Death date:",
"HeaderRemoveMediaLocation": "Remove Media Location",
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Media Locations",
"LabelFolderTypeValue": "Folder type: {0}",
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
- "FolderTypeMixed": "Mixed movies & tv",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Movies",
"FolderTypeMusic": "Music",
"FolderTypeAdultVideos": "Adult videos",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Home videos",
"FolderTypeGames": "Games",
"FolderTypeBooks": "Books",
- "FolderTypeTvShows": "TV shows",
+ "FolderTypeTvShows": "TV",
"TabMovies": "C\u00e1c phim",
"TabSeries": "Series",
"TabEpisodes": "C\u00e1c t\u1eadp phim",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
"MessageEnjoyYourStay": "Enjoy your stay",
"DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Easily create user accounts for your friends and family, each with their own permissions, library access, parental controls and more.",
"DashboardTourCinemaMode": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
"DashboardTourChapters": "Enable chapter image generation for your videos for a more pleasing presentation while viewing.",
@@ -642,7 +649,12 @@
"OptionLow": "Low",
"HeaderSettings": "Settings",
"OptionAutomaticallySyncNewContent": "Automatically sync new content",
- "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.",
+ "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
"OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
- "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
+ "LabelItemLimit": "Item limit:",
+ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+ "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+ "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_CN.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_CN.json
index ad9a6c6a5..8df63af86 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_CN.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_CN.json
@@ -40,6 +40,11 @@
"LabelStopping": "\u505c\u6b62",
"LabelCancelled": "(\u5df2\u53d6\u6d88)",
"LabelFailed": "(\u5931\u8d25)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Library Access",
+ "HeaderChannelAccess": "Channel Access",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(\u56e0\u4e3a\u670d\u52a1\u5668\u5173\u95ed\u88ab\u4e2d\u6b62)",
"LabelScheduledTaskLastRan": "\u6700\u540e\u8fd0\u884c {0}, \u82b1\u8d39\u65f6\u95f4 {1}.",
"HeaderDeleteTaskTrigger": "\u5220\u9664\u4efb\u52a1\u89e6\u53d1\u6761\u4ef6",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "\u53f3\u79fb",
"ButtonBrowseOnlineImages": "\u6d4f\u89c8\u5728\u7ebf\u56fe\u7247",
"HeaderDeleteItem": "\u5220\u9664\u9879\u76ee",
- "ConfirmDeleteItem": "\u4f60\u786e\u5b9a\u5e0c\u671b\u4ece\u5a92\u4f53\u5e93\u91cc\u5220\u9664\u8fd9\u4e2a\u9879\u76ee\uff1f",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "\u8bf7\u8f93\u5165\u4e00\u4e2a\u540d\u79f0\u6216\u4e00\u4e2a\u5916\u90e8ID\u3002",
"MessageValueNotCorrect": "\u8f93\u5165\u7684\u503c\u4e0d\u6b63\u786e\u3002\u8bf7\u91cd\u8bd5\u3002",
"MessageItemSaved": "\u9879\u76ee\u5df2\u4fdd\u5b58\u3002",
@@ -396,6 +401,7 @@
"LabelYear": "\u5e74\uff1a",
"LabelDateOfBirth": "\u51fa\u751f\u65e5\u671f\uff1a",
"LabelBirthYear": "\u51fa\u751f\u5e74\u4efd\uff1a",
+ "LabelBirthDate": "Birth date:",
"LabelDeathDate": "\u53bb\u4e16\u65e5\u671f\uff1a",
"HeaderRemoveMediaLocation": "\u79fb\u9664\u5a92\u4f53\u4f4d\u7f6e",
"MessageConfirmRemoveMediaLocation": "\u4f60\u786e\u5b9a\u8981\u79fb\u9664\u6b64\u4f4d\u7f6e\uff1f",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "\u5a92\u4f53\u4f4d\u7f6e",
"LabelFolderTypeValue": "\u6587\u4ef6\u5939\u7c7b\u578b\uff1a {0}",
"LabelPathSubstitutionHelp": "\u53ef\u9009\uff1a\u66ff\u4ee3\u8def\u5f84\u80fd\u628a\u670d\u52a1\u5668\u8def\u5f84\u6620\u5c04\u5230\u7f51\u7edc\u5171\u4eab\uff0c\u4ece\u800c\u4f7f\u5ba2\u6237\u7aef\u53ef\u4ee5\u76f4\u63a5\u64ad\u653e\u3002",
- "FolderTypeMixed": "\u6df7\u5408\u7684\u7535\u5f71\u548c\u7535\u89c6",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "\u7535\u5f71",
"FolderTypeMusic": "\u97f3\u4e50",
"FolderTypeAdultVideos": "\u6210\u4eba\u89c6\u9891",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "\u5bb6\u5ead\u89c6\u9891",
"FolderTypeGames": "\u6e38\u620f",
"FolderTypeBooks": "\u4e66\u7c4d",
- "FolderTypeTvShows": "\u7535\u89c6\u8282\u76ee",
+ "FolderTypeTvShows": "TV",
"TabMovies": "\u7535\u5f71",
"TabSeries": "\u7535\u89c6\u5267",
"TabEpisodes": "\u5267\u96c6",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
"MessageEnjoyYourStay": "Enjoy your stay",
"DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Easily create user accounts for your friends and family, each with their own permissions, library access, parental controls and more.",
"DashboardTourCinemaMode": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
"DashboardTourChapters": "Enable chapter image generation for your videos for a more pleasing presentation while viewing.",
@@ -642,7 +649,12 @@
"OptionLow": "Low",
"HeaderSettings": "Settings",
"OptionAutomaticallySyncNewContent": "Automatically sync new content",
- "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.",
+ "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
"OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
- "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
+ "LabelItemLimit": "Item limit:",
+ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+ "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+ "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json
index 706299704..2f4c18f7f 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json
@@ -40,6 +40,11 @@
"LabelStopping": "Stopping",
"LabelCancelled": "(cancelled)",
"LabelFailed": "(failed)",
+ "ButtonHelp": "Help",
+ "HeaderLibraryAccess": "Library Access",
+ "HeaderChannelAccess": "Channel Access",
+ "HeaderDeviceAccess": "Device Access",
+ "HeaderSelectDevices": "Select Devices",
"LabelAbortedByServerShutdown": "(Aborted by server shutdown)",
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
"HeaderDeleteTaskTrigger": "Delete Task Trigger",
@@ -249,7 +254,7 @@
"ButtonMoveRight": "Move right",
"ButtonBrowseOnlineImages": "Browse online images",
"HeaderDeleteItem": "Delete Item",
- "ConfirmDeleteItem": "Are you sure you wish to delete this item from your library?",
+ "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
"MessagePleaseEnterNameOrId": "Please enter a name or an external Id.",
"MessageValueNotCorrect": "The value entered is not correct. Please try again.",
"MessageItemSaved": "Item saved.",
@@ -396,6 +401,7 @@
"LabelYear": "Year:",
"LabelDateOfBirth": "Date of birth:",
"LabelBirthYear": "Birth year:",
+ "LabelBirthDate": "Birth date:",
"LabelDeathDate": "Death date:",
"HeaderRemoveMediaLocation": "Remove Media Location",
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
@@ -411,7 +417,7 @@
"HeaderMediaLocations": "Media Locations",
"LabelFolderTypeValue": "Folder type: {0}",
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
- "FolderTypeMixed": "Mixed movies & tv",
+ "FolderTypeUnset": "Unset (mixed content)",
"FolderTypeMovies": "Movies",
"FolderTypeMusic": "Music",
"FolderTypeAdultVideos": "Adult videos",
@@ -420,7 +426,7 @@
"FolderTypeHomeVideos": "Home videos",
"FolderTypeGames": "Games",
"FolderTypeBooks": "Books",
- "FolderTypeTvShows": "TV shows",
+ "FolderTypeTvShows": "TV",
"TabMovies": "\u96fb\u5f71",
"TabSeries": "\u96fb\u8996\u5287",
"TabEpisodes": "\u55ae\u5143",
@@ -587,6 +593,7 @@
"WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
"MessageEnjoyYourStay": "Enjoy your stay",
"DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
+ "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
"DashboardTourUsers": "Easily create user accounts for your friends and family, each with their own permissions, library access, parental controls and more.",
"DashboardTourCinemaMode": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
"DashboardTourChapters": "Enable chapter image generation for your videos for a more pleasing presentation while viewing.",
@@ -642,7 +649,12 @@
"OptionLow": "Low",
"HeaderSettings": "Settings",
"OptionAutomaticallySyncNewContent": "Automatically sync new content",
- "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.",
+ "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
"OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
- "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched."
+ "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
+ "LabelItemLimit": "Item limit:",
+ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+ "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+ "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+ "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/ar.json b/MediaBrowser.Server.Implementations/Localization/Server/ar.json
index 97302a0ff..e8826e5f4 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/ar.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/ar.json
@@ -37,10 +37,21 @@
"ButtonOk": "\u0645\u0648\u0627\u0641\u0642",
"ButtonCancel": "\u0627\u0644\u063a\u0627\u0621",
"ButtonNew": "New",
+ "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": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "\u0627\u0639\u062f\u0627\u062f \u0645\u0643\u062a\u0628\u0629 \u0627\u0644\u0648\u0633\u0627\u0626\u0637",
"ButtonAddMediaFolder": "\u0627\u0636\u0627\u0641\u0629 \u0645\u062c\u0644\u062f \u0644\u0644\u0648\u0633\u0627\u0626\u0637",
"LabelFolderType": "\u0646\u0648\u0639 \u0627\u0644\u0645\u062c\u0644\u062f:",
- "MediaFolderHelpPluginRequired": "* Requires the use of a plugin, e.g. GameBrowser or MB Bookshelf.",
"ReferToMediaLibraryWiki": "\u0627\u0644\u0631\u062c\u0648\u0639 \u0627\u0644\u0649 wiki \u0644\u0645\u0643\u062a\u0628\u0629 \u0627\u0644\u0648\u0633\u0627\u0626\u0637",
"LabelCountry": "\u0627\u0644\u0628\u0644\u062f:",
"LabelLanguage": "\u0627\u0644\u0644\u063a\u0629:",
@@ -52,12 +63,16 @@
"TabPreferences": "\u062a\u0641\u0636\u064a\u0644\u0627\u062a",
"TabPassword": "\u0643\u0644\u0645\u0629 \u0627\u0644\u0633\u0631",
"TabLibraryAccess": "\u0627\u0644\u062f\u062e\u0648\u0644 \u0627\u0644\u0649 \u0627\u0644\u0645\u0643\u062a\u0628\u0629",
+ "TabAccess": "Access",
"TabImage": "\u0635\u0648\u0631\u0629",
"TabProfile": "\u0633\u062c\u0644",
"TabMetadata": "Metadata",
"TabImages": "Images",
"TabNotifications": "Notifications",
"TabCollectionTitles": "Titles",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons",
"LabelUnairedMissingEpisodesWithinSeasons": "Display unaired episodes within seasons",
"HeaderVideoPlaybackSettings": "\u0627\u0639\u062f\u0627\u062f\u0627\u062a \u062a\u0634\u063a\u064a\u0644 \u0627\u0644\u0641\u064a\u062f\u064a\u0648",
@@ -365,8 +380,8 @@
"LabelMaxScreenshotsPerItem": "Maximum number of screenshots per item:",
"LabelMinBackdropDownloadWidth": "Minimum backdrop download width:",
"LabelMinScreenshotDownloadWidth": "Minimum screenshot download width:",
- "ButtonAddScheduledTaskTrigger": "Add Task Trigger",
- "HeaderAddScheduledTaskTrigger": "Add Task Trigger",
+ "ButtonAddScheduledTaskTrigger": "Add Trigger",
+ "HeaderAddScheduledTaskTrigger": "Add Trigger",
"ButtonAdd": "Add",
"LabelTriggerType": "Trigger Type:",
"OptionDaily": "Daily",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer Reel",
"OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
"HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
- "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "New Users",
"ButtonSignUp": "Sign up",
"ButtonForgotPassword": "Forgot password?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/ca.json b/MediaBrowser.Server.Implementations/Localization/Server/ca.json
index 655cabcaf..65464c2ce 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/ca.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/ca.json
@@ -37,10 +37,21 @@
"ButtonOk": "Ok",
"ButtonCancel": "Cancel",
"ButtonNew": "New",
+ "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": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "Setup your media library",
"ButtonAddMediaFolder": "Add media folder",
"LabelFolderType": "Folder type:",
- "MediaFolderHelpPluginRequired": "* Requires the use of a plugin, e.g. GameBrowser or MB Bookshelf.",
"ReferToMediaLibraryWiki": "Refer to the media library wiki.",
"LabelCountry": "Country:",
"LabelLanguage": "Language:",
@@ -52,12 +63,16 @@
"TabPreferences": "Preferences",
"TabPassword": "Password",
"TabLibraryAccess": "Library Access",
+ "TabAccess": "Access",
"TabImage": "Image",
"TabProfile": "Profile",
"TabMetadata": "Metadata",
"TabImages": "Images",
"TabNotifications": "Notifications",
"TabCollectionTitles": "Titles",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons",
"LabelUnairedMissingEpisodesWithinSeasons": "Display unaired episodes within seasons",
"HeaderVideoPlaybackSettings": "Video Playback Settings",
@@ -365,8 +380,8 @@
"LabelMaxScreenshotsPerItem": "Maximum number of screenshots per item:",
"LabelMinBackdropDownloadWidth": "Minimum backdrop download width:",
"LabelMinScreenshotDownloadWidth": "Minimum screenshot download width:",
- "ButtonAddScheduledTaskTrigger": "Add Task Trigger",
- "HeaderAddScheduledTaskTrigger": "Add Task Trigger",
+ "ButtonAddScheduledTaskTrigger": "Add Trigger",
+ "HeaderAddScheduledTaskTrigger": "Add Trigger",
"ButtonAdd": "Add",
"LabelTriggerType": "Trigger Type:",
"OptionDaily": "Daily",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer Reel",
"OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
"HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
- "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "New Users",
"ButtonSignUp": "Sign up",
"ButtonForgotPassword": "Forgot password?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/cs.json b/MediaBrowser.Server.Implementations/Localization/Server/cs.json
index 74aa0cd37..bcedf0c9f 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/cs.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/cs.json
@@ -37,10 +37,21 @@
"ButtonOk": "Ok",
"ButtonCancel": "Zru\u0161it",
"ButtonNew": "Nov\u00e9",
+ "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": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "Nastaven\u00ed Va\u0161i knihovny m\u00e9di\u00ed",
"ButtonAddMediaFolder": "P\u0159idat slo\u017eku m\u00e9di\u00ed",
"LabelFolderType": "Typ slo\u017eky:",
- "MediaFolderHelpPluginRequired": "* Vy\u017eaduje pou\u017eit\u00ed pluginu, nap\u0159. GameBrowser nebo MB Bookshelf",
"ReferToMediaLibraryWiki": "Pod\u00edvejte se na wiki knihovny m\u00e9di\u00ed.",
"LabelCountry": "Zem\u011b:",
"LabelLanguage": "Jazyk:",
@@ -52,12 +63,16 @@
"TabPreferences": "P\u0159edvolby",
"TabPassword": "Heslo",
"TabLibraryAccess": "P\u0159\u00edstup ke knihovn\u011b",
+ "TabAccess": "Access",
"TabImage": "Obr\u00e1zek",
"TabProfile": "Profil",
"TabMetadata": "Metadata",
"TabImages": "Obr\u00e1zky",
"TabNotifications": "Notifications",
"TabCollectionTitles": "N\u00e1zvy",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "Zobrazit chyb\u011bj\u00edc\u00ed epizody",
"LabelUnairedMissingEpisodesWithinSeasons": "Zobrazit neprov\u011btran\u00e9 epizody v r\u00e1mci sez\u00f3n",
"HeaderVideoPlaybackSettings": "Nastaven\u00ed p\u0159ehr\u00e1v\u00e1n\u00ed videa",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer Reel",
"OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
"HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
- "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "New Users",
"ButtonSignUp": "Sign up",
"ButtonForgotPassword": "Forgot password?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/da.json b/MediaBrowser.Server.Implementations/Localization/Server/da.json
index db4c6d535..dcf5d69d7 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/da.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/da.json
@@ -37,10 +37,21 @@
"ButtonOk": "Ok",
"ButtonCancel": "Annuller",
"ButtonNew": "Ny",
+ "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": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "Konfigurer dit medie bibliotek",
"ButtonAddMediaFolder": "Tilf\u00f8j medie mappe",
"LabelFolderType": "Mappe type:",
- "MediaFolderHelpPluginRequired": "* Kr\u00e6ver brug af en tilf\u00f8jelse, fx GameBrowser eller MB Bookshelf.",
"ReferToMediaLibraryWiki": "Der henvises til medie bibliotekets wiki.",
"LabelCountry": "Land:",
"LabelLanguage": "Sprog:",
@@ -52,12 +63,16 @@
"TabPreferences": "Indstillinger",
"TabPassword": "Kode",
"TabLibraryAccess": "Bibliotek adgang",
+ "TabAccess": "Access",
"TabImage": "Billede",
"TabProfile": "Profil",
"TabMetadata": "Metadata",
"TabImages": "Billeder",
"TabNotifications": "Notifications",
"TabCollectionTitles": "Titler",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "Vis manglende episoder i s\u00e6soner",
"LabelUnairedMissingEpisodesWithinSeasons": "Vis endnu ikke sendte episoder i s\u00e6soner",
"HeaderVideoPlaybackSettings": "Video afspilnings indstillinger",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer Reel",
"OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
"HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
- "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "New Users",
"ButtonSignUp": "Sign up",
"ButtonForgotPassword": "Forgot password?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/de.json b/MediaBrowser.Server.Implementations/Localization/Server/de.json
index c5e0715ff..fb886e32d 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/de.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/de.json
@@ -37,10 +37,21 @@
"ButtonOk": "Ok",
"ButtonCancel": "Abbrechen",
"ButtonNew": "Neu",
+ "FolderTypeMixed": "Gemischte Inhalte",
+ "FolderTypeMovies": "Filme",
+ "FolderTypeMusic": "Musik",
+ "FolderTypeAdultVideos": "Videos f\u00fcr Erwachsene",
+ "FolderTypePhotos": "Fotos",
+ "FolderTypeMusicVideos": "Musikvideos",
+ "FolderTypeHomeVideos": "Heimvideos",
+ "FolderTypeGames": "Spiele",
+ "FolderTypeBooks": "B\u00fccher",
+ "FolderTypeTvShows": "TV",
+ "FolderTypeInherit": "\u00dcbernehmen",
+ "LabelContentType": "Inhalte-Typ:",
"HeaderSetupLibrary": "Medienbibliothek einrichten",
"ButtonAddMediaFolder": "Medienverzeichnis hinzuf\u00fcgen",
"LabelFolderType": "Verzeichnistyp:",
- "MediaFolderHelpPluginRequired": "* Ben\u00f6tigt ein Plugin, wie GameBrowser oder MB Bookshelf.",
"ReferToMediaLibraryWiki": "Siehe die Medienbibliothek Wiki",
"LabelCountry": "Land:",
"LabelLanguage": "Sprache:",
@@ -52,12 +63,16 @@
"TabPreferences": "Einstellungen",
"TabPassword": "Passwort",
"TabLibraryAccess": "Bibliothekenzugriff",
+ "TabAccess": "Access",
"TabImage": "Bild",
"TabProfile": "Profil",
"TabMetadata": "Metadata",
"TabImages": "Bilder",
"TabNotifications": "Benachrichtigungen",
"TabCollectionTitles": "Titel",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "Zeige fehlende Episoden innerhalb von Staffeln",
"LabelUnairedMissingEpisodesWithinSeasons": "Zeige noch nicht ausgestahlte Episoden innerhalb von Staffeln",
"HeaderVideoPlaybackSettings": "Videowiedergabe Einstellungen",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer Rolle",
"OptionPlayUnwatchedTrailersOnly": "Spiele nur bisher nicht gesehene Trailer",
"HeaderTrailerReelHelp": "Starte eine Trailer Rolle, um dir eine lang andauernde Playlist mit Trailern anzuschauen.",
- "MessageNoTrailersFound": "Keine Trailer gefunden. Installiere das Trailer Channel Plugin, um eine Bibliothek aus Trailern vom Internet zu importieren.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "Neue Benutzer",
"ButtonSignUp": "Anmeldung",
"ButtonForgotPassword": "Passwort vergessen?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Begrenze auf ein eingebundenes Bild",
"LabelEnableSingleImageInDidlLimitHelp": "Einige Ger\u00e4te zeigen m\u00f6glicherweise Darstellungsfehler wenn mehrere Bilder mit Didl eingebunden wurden.",
"TabActivity": "Aktivit\u00e4t",
- "TitleSync": "Synchronisation"
+ "TitleSync": "Synchronisation",
+ "OptionAllowSyncContent": "Erlaube das Synchronisieren zu Ger\u00e4ten.",
+ "NameSeasonUnknown": "Staffel unbekannt",
+ "NameSeasonNumber": "Staffel {0}",
+ "LabelNewUserNameHelp": "Benutzernamen k\u00f6nnen Zeichen (a-z), Zahlen (0-9), Striche (-), Unterstriche (_), Apostrophe (') und Punkte (.) enthalten."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/el.json b/MediaBrowser.Server.Implementations/Localization/Server/el.json
index 41239b912..708daa681 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/el.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/el.json
@@ -37,10 +37,21 @@
"ButtonOk": "\u03b5\u03bd\u03c4\u03ac\u03be\u03b5\u03b9",
"ButtonCancel": "\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7 ",
"ButtonNew": "New",
+ "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": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "Setup your media library",
"ButtonAddMediaFolder": "\u03a0\u03c1\u03bf\u03c3\u03b8\u03ad\u03c3\u03c4\u03b5 \u03c4\u03bf \u03c6\u03ac\u03ba\u03b5\u03bb\u03bf \u03c4\u03bf\u03c5 Media",
"LabelFolderType": "\u03a4\u03cd\u03c0\u03bf \u03c6\u03b1\u03ba\u03ad\u03bb\u03bf\u03c5 ",
- "MediaFolderHelpPluginRequired": "\u0391\u03c0\u03b1\u03b9\u03c4\u03b5\u03af \u03c4\u03b7 \u03c7\u03c1\u03ae\u03c3\u03b7 \u03b5\u03bd\u03cc\u03c2 plugin.\u03c0.\u03c7. Gamebrowser \u03ae MB Bookshelf.",
"ReferToMediaLibraryWiki": "\u0391\u03bd\u03b1\u03c4\u03c1\u03b5\u03be\u03c4\u03b5 \u03c3\u03c4\u03bf media \u03b2\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7 wiki",
"LabelCountry": "T\u03b7 \u03c7\u03ce\u03c1\u03b1",
"LabelLanguage": "\u03a4\u03b7 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b1",
@@ -52,12 +63,16 @@
"TabPreferences": "\u03a0\u03c1\u03bf\u03c4\u03b9\u03bc\u03ae\u03c3\u03b5\u03b9\u03c2 ",
"TabPassword": "\u03c4\u03bf\u03bd \u03ba\u03c9\u03b4\u03b9\u03ba\u03cc",
"TabLibraryAccess": "\u03a0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7 \u03c3\u03c4\u03b7 \u03b2\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7",
+ "TabAccess": "Access",
"TabImage": "\u03b5\u03b9\u03ba\u03cc\u03bd\u03b1",
"TabProfile": "\u03c0\u03c1\u03bf\u03c6\u03af\u03bb ",
"TabMetadata": "Metadata",
"TabImages": "Images",
"TabNotifications": "Notifications",
"TabCollectionTitles": "Titles",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "\u03b4\u03b5\u03af\u03c7\u03bd\u03bf\u03c5\u03bd \u03bb\u03b5\u03af\u03c0\u03b5\u03b9 \u03b5\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1 \u03b5\u03bd\u03c4\u03cc\u03c2 \u03b5\u03c0\u03bf\u03c7\u03ad\u03c2",
"LabelUnairedMissingEpisodesWithinSeasons": "\u03b4\u03b5\u03af\u03c7\u03bd\u03bf\u03c5\u03bd unaired \u03b5\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1 \u03b5\u03bd\u03c4\u03cc\u03c2 \u03b5\u03c0\u03bf\u03c7\u03ad\u03c2",
"HeaderVideoPlaybackSettings": "\u0391\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2.",
@@ -365,8 +380,8 @@
"LabelMaxScreenshotsPerItem": "Maximum number of screenshots per item:",
"LabelMinBackdropDownloadWidth": "Minimum backdrop download width:",
"LabelMinScreenshotDownloadWidth": "Minimum screenshot download width:",
- "ButtonAddScheduledTaskTrigger": "Add Task Trigger",
- "HeaderAddScheduledTaskTrigger": "Add Task Trigger",
+ "ButtonAddScheduledTaskTrigger": "Add Trigger",
+ "HeaderAddScheduledTaskTrigger": "Add Trigger",
"ButtonAdd": "Add",
"LabelTriggerType": "Trigger Type:",
"OptionDaily": "Daily",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer Reel",
"OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
"HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
- "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "New Users",
"ButtonSignUp": "Sign up",
"ButtonForgotPassword": "Forgot password?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/en_GB.json b/MediaBrowser.Server.Implementations/Localization/Server/en_GB.json
index 9eeac0f85..0063a3af6 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/en_GB.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/en_GB.json
@@ -37,10 +37,21 @@
"ButtonOk": "Ok",
"ButtonCancel": "Cancel",
"ButtonNew": "New",
+ "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": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "Setup your media library",
"ButtonAddMediaFolder": "Add media folder",
"LabelFolderType": "Folder type:",
- "MediaFolderHelpPluginRequired": "* Requires the use of a plugin, e.g. GameBrowser or MB Bookshelf.",
"ReferToMediaLibraryWiki": "Refer to the media library wiki.",
"LabelCountry": "Country:",
"LabelLanguage": "Language:",
@@ -52,12 +63,16 @@
"TabPreferences": "Preferences",
"TabPassword": "Password",
"TabLibraryAccess": "Library Access",
+ "TabAccess": "Access",
"TabImage": "Image",
"TabProfile": "Profile",
"TabMetadata": "Metadata",
"TabImages": "Images",
"TabNotifications": "Notifications",
"TabCollectionTitles": "Titles",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons",
"LabelUnairedMissingEpisodesWithinSeasons": "Display unaired episodes within seasons",
"HeaderVideoPlaybackSettings": "Video Playback Settings",
@@ -365,8 +380,8 @@
"LabelMaxScreenshotsPerItem": "Maximum number of screenshots per item:",
"LabelMinBackdropDownloadWidth": "Minimum backdrop download width:",
"LabelMinScreenshotDownloadWidth": "Minimum screenshot download width:",
- "ButtonAddScheduledTaskTrigger": "Add Task Trigger",
- "HeaderAddScheduledTaskTrigger": "Add Task Trigger",
+ "ButtonAddScheduledTaskTrigger": "Add Trigger",
+ "HeaderAddScheduledTaskTrigger": "Add Trigger",
"ButtonAdd": "Add",
"LabelTriggerType": "Trigger Type:",
"OptionDaily": "Daily",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer Reel",
"OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
"HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
- "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "New Users",
"ButtonSignUp": "Sign up",
"ButtonForgotPassword": "Forgot password?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/en_US.json b/MediaBrowser.Server.Implementations/Localization/Server/en_US.json
index 9cb4fb6c5..82fb1186e 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/en_US.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/en_US.json
@@ -37,10 +37,21 @@
"ButtonOk": "Ok",
"ButtonCancel": "Cancel",
"ButtonNew": "New",
+ "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": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "Setup your media library",
"ButtonAddMediaFolder": "Add media folder",
"LabelFolderType": "Folder type:",
- "MediaFolderHelpPluginRequired": "* Requires the use of a plugin, e.g. GameBrowser or MB Bookshelf.",
"ReferToMediaLibraryWiki": "Refer to the media library wiki.",
"LabelCountry": "Country:",
"LabelLanguage": "Language:",
@@ -52,12 +63,16 @@
"TabPreferences": "Preferences",
"TabPassword": "Password",
"TabLibraryAccess": "Library Access",
+ "TabAccess": "Access",
"TabImage": "Image",
"TabProfile": "Profile",
"TabMetadata": "Metadata",
"TabImages": "Images",
"TabNotifications": "Notifications",
"TabCollectionTitles": "Titles",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons",
"LabelUnairedMissingEpisodesWithinSeasons": "Display unaired episodes within seasons",
"HeaderVideoPlaybackSettings": "Video Playback Settings",
@@ -365,8 +380,8 @@
"LabelMaxScreenshotsPerItem": "Maximum number of screenshots per item:",
"LabelMinBackdropDownloadWidth": "Minimum backdrop download width:",
"LabelMinScreenshotDownloadWidth": "Minimum screenshot download width:",
- "ButtonAddScheduledTaskTrigger": "Add Task Trigger",
- "HeaderAddScheduledTaskTrigger": "Add Task Trigger",
+ "ButtonAddScheduledTaskTrigger": "Add Trigger",
+ "HeaderAddScheduledTaskTrigger": "Add Trigger",
"ButtonAdd": "Add",
"LabelTriggerType": "Trigger Type:",
"OptionDaily": "Daily",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer Reel",
"OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
"HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
- "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "New Users",
"ButtonSignUp": "Sign up",
"ButtonForgotPassword": "Forgot password?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/es.json b/MediaBrowser.Server.Implementations/Localization/Server/es.json
index a720a1510..f4264b4fc 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/es.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/es.json
@@ -37,10 +37,21 @@
"ButtonOk": "OK",
"ButtonCancel": "Cancelar",
"ButtonNew": "Nuevo",
+ "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": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "Configurar biblioteca de medios",
"ButtonAddMediaFolder": "Agregar una carpeta de medios",
"LabelFolderType": "Tipo de carpeta:",
- "MediaFolderHelpPluginRequired": "* Requiere el uso de un plugin, por ejemplo GameBrowser o MB Bookshelf",
"ReferToMediaLibraryWiki": "Consultar el wiki de la biblioteca de medios",
"LabelCountry": "Pa\u00eds:",
"LabelLanguage": "Idioma:",
@@ -52,12 +63,16 @@
"TabPreferences": "Preferencias",
"TabPassword": "Contrase\u00f1a",
"TabLibraryAccess": "Acceso a biblioteca",
+ "TabAccess": "Access",
"TabImage": "imagen",
"TabProfile": "Perfil",
"TabMetadata": "Metadata",
"TabImages": "Im\u00e1genes",
"TabNotifications": "Notificaciones",
"TabCollectionTitles": "T\u00edtulos",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "Mostar episodios no disponibles en temporadas",
"LabelUnairedMissingEpisodesWithinSeasons": "Mostrar episodios a\u00fan no emitidos en temporadas",
"HeaderVideoPlaybackSettings": "Ajustes de Reproducci\u00f3n de Video",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer Reel",
"OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
"HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
- "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "New Users",
"ButtonSignUp": "Sign up",
"ButtonForgotPassword": "Forgot password?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/es_MX.json b/MediaBrowser.Server.Implementations/Localization/Server/es_MX.json
index 7c532182b..5a39eaf7b 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/es_MX.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/es_MX.json
@@ -37,10 +37,21 @@
"ButtonOk": "Ok",
"ButtonCancel": "Cancelar",
"ButtonNew": "Nuevo",
+ "FolderTypeMixed": "Contenido mezclado",
+ "FolderTypeMovies": "Pel\u00edculas",
+ "FolderTypeMusic": "M\u00fasica",
+ "FolderTypeAdultVideos": "Videos para adultos",
+ "FolderTypePhotos": "Fotos",
+ "FolderTypeMusicVideos": "Videos musicales",
+ "FolderTypeHomeVideos": "Videos caseros",
+ "FolderTypeGames": "Juegos",
+ "FolderTypeBooks": "Libros",
+ "FolderTypeTvShows": "TV",
+ "FolderTypeInherit": "Heredar",
+ "LabelContentType": "Tipo de Contenido:",
"HeaderSetupLibrary": "Configurar su biblioteca de medios",
"ButtonAddMediaFolder": "Agregar carpeta de medios",
"LabelFolderType": "Tipo de carpeta:",
- "MediaFolderHelpPluginRequired": "* Requiere el uso de un complemento, p. ej. GameBrowser o MB Bookshelf.",
"ReferToMediaLibraryWiki": "Consultar la wiki de la biblioteca de medios.",
"LabelCountry": "Pa\u00eds:",
"LabelLanguage": "Idioma:",
@@ -52,12 +63,16 @@
"TabPreferences": "Preferencias",
"TabPassword": "Contrase\u00f1a",
"TabLibraryAccess": "Acceso a biblioteca",
+ "TabAccess": "Access",
"TabImage": "Imagen",
"TabProfile": "Perf\u00edl",
"TabMetadata": "Metadatos",
"TabImages": "Im\u00e1genes",
"TabNotifications": "Notificaciones",
"TabCollectionTitles": "T\u00edtulos",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "Mostar episodios no disponibles en las temporadas",
"LabelUnairedMissingEpisodesWithinSeasons": "Mostrar episodios a\u00fan no emitidos en las temporadas",
"HeaderVideoPlaybackSettings": "Ajustes de Reproducci\u00f3n de Video",
@@ -232,10 +247,10 @@
"HeaderFeatureAccess": "Permisos de acceso",
"OptionAllowMediaPlayback": "Permitir reproducci\u00f3n de medios",
"OptionAllowBrowsingLiveTv": "Permitir acceder a TV en vivo",
- "OptionAllowDeleteLibraryContent": "Allow deletion of library content",
+ "OptionAllowDeleteLibraryContent": "Permitir eliminar contenido de la biblioteca",
"OptionAllowManageLiveTv": "Permitir administrar grabaciones de TV en vivo",
- "OptionAllowRemoteControlOthers": "Allow remote control of other users",
- "OptionAllowRemoteSharedDevices": "Allow remote control of shared devices",
+ "OptionAllowRemoteControlOthers": "Permitir control remoto de otros usuarios",
+ "OptionAllowRemoteSharedDevices": "Permitir control remoto de dispositivos compartidos",
"OptionAllowRemoteSharedDevicesHelp": "Los dispositivos dnla son considerados como compartidos hasta que alg\u00fan usuario comienza a controlarlo.",
"HeaderRemoteControl": "Control Remoto",
"OptionMissingTmdbId": "Falta Id de Tmdb",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Carrete de Avances",
"OptionPlayUnwatchedTrailersOnly": "Reproducir \u00fanicamente avances no vistos",
"HeaderTrailerReelHelp": "Iniciar un carrete de avances para reproducir una lista de reproducci\u00f3n de larga duraci\u00f3n de avances.",
- "MessageNoTrailersFound": "No se encontraron avances. Instalar el complemento \"Canal trailers\" para importar una biblioteca de avances de internet.",
+ "MessageNoTrailersFound": "No se encontraron avances. Instale el canal de avances para mejorar su experiencia con pel\u00edculas al agregar una biblioteca de avances desde el Internet.",
"HeaderNewUsers": "Nuevos Usuarios",
"ButtonSignUp": "Registrarse",
"ButtonForgotPassword": "\u00bfOlvidaste la contrase\u00f1a?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limitar a una sola imagen incrustada.",
"LabelEnableSingleImageInDidlLimitHelp": "Algunos dispositivos no renderisaran apropiadamente si hay m\u00faltiples im\u00e1genes incrustadas en el Didl",
"TabActivity": "Actividad",
- "TitleSync": "Sinc"
+ "TitleSync": "Sinc",
+ "OptionAllowSyncContent": "Permitir sincronizaci\u00f3n de medios con dispositivos",
+ "NameSeasonUnknown": "Temporada Desconocida",
+ "NameSeasonNumber": "Temporada {0}",
+ "LabelNewUserNameHelp": "Los nombres de usuario pueden contener letras (a-z), n\u00fameros (0-9), guiones (-), guiones bajos (_) y puntos (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/fi.json b/MediaBrowser.Server.Implementations/Localization/Server/fi.json
index c2c6c8612..ed49df178 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/fi.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/fi.json
@@ -37,10 +37,21 @@
"ButtonOk": "Ok",
"ButtonCancel": "Lopeta",
"ButtonNew": "New",
+ "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": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "Aseta sinun media kirjasto",
"ButtonAddMediaFolder": "Lis\u00e4\u00e4 media kansio",
"LabelFolderType": "Kansion tyyppi:",
- "MediaFolderHelpPluginRequired": "* Vaatii lis\u00e4osan, kuten GameBrowser tai MB Bookshelf.",
"ReferToMediaLibraryWiki": "Viittus media kirjaston wikiin.",
"LabelCountry": "Maa:",
"LabelLanguage": "Kieli:",
@@ -52,12 +63,16 @@
"TabPreferences": "Asetukset",
"TabPassword": "Salasana",
"TabLibraryAccess": "Kirjaston P\u00e4\u00e4sy",
+ "TabAccess": "Access",
"TabImage": "Kuva",
"TabProfile": "Profiili",
"TabMetadata": "Metadata",
"TabImages": "Images",
"TabNotifications": "Notifications",
"TabCollectionTitles": "Titles",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "N\u00e4yt\u00e4 puuttuvat jaksot tuotantokausissa",
"LabelUnairedMissingEpisodesWithinSeasons": "N\u00e4yt\u00e4 julkaisemattomat jaksot tuotantokausissa",
"HeaderVideoPlaybackSettings": "Videon Toistamisen Asetukset",
@@ -365,8 +380,8 @@
"LabelMaxScreenshotsPerItem": "Maximum number of screenshots per item:",
"LabelMinBackdropDownloadWidth": "Minimum backdrop download width:",
"LabelMinScreenshotDownloadWidth": "Minimum screenshot download width:",
- "ButtonAddScheduledTaskTrigger": "Add Task Trigger",
- "HeaderAddScheduledTaskTrigger": "Add Task Trigger",
+ "ButtonAddScheduledTaskTrigger": "Add Trigger",
+ "HeaderAddScheduledTaskTrigger": "Add Trigger",
"ButtonAdd": "Add",
"LabelTriggerType": "Trigger Type:",
"OptionDaily": "Daily",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer Reel",
"OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
"HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
- "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "New Users",
"ButtonSignUp": "Sign up",
"ButtonForgotPassword": "Forgot password?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/fr.json b/MediaBrowser.Server.Implementations/Localization/Server/fr.json
index b3f6ead82..818dcb726 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/fr.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/fr.json
@@ -15,7 +15,7 @@
"LabelFinish": "Terminer",
"LabelNext": "Suivant",
"LabelYoureDone": "Vous avez Termin\u00e9!",
- "WelcomeToMediaBrowser": "Bienvenue \u00e0 Media Browser!",
+ "WelcomeToMediaBrowser": "Bienvenue sur Media Browser!",
"TitleMediaBrowser": "Media Browser",
"ThisWizardWillGuideYou": "Cet assistant vous guidera dans le processus de configuration. Pour commencer, merci de s\u00e9lectionner votre langue pr\u00e9f\u00e9r\u00e9e.",
"TellUsAboutYourself": "Parlez-nous de vous",
@@ -37,10 +37,21 @@
"ButtonOk": "Ok",
"ButtonCancel": "Annuler",
"ButtonNew": "Nouveau",
+ "FolderTypeMixed": "Contenus m\u00e9lang\u00e9s",
+ "FolderTypeMovies": "Films",
+ "FolderTypeMusic": "Musique",
+ "FolderTypeAdultVideos": "Vid\u00e9os Adultes",
+ "FolderTypePhotos": "Photos",
+ "FolderTypeMusicVideos": "Vid\u00e9os Musical",
+ "FolderTypeHomeVideos": "Vid\u00e9os personnelles",
+ "FolderTypeGames": "Jeux",
+ "FolderTypeBooks": "Livres",
+ "FolderTypeTvShows": "TV",
+ "FolderTypeInherit": "H\u00e9rite",
+ "LabelContentType": "Type de contenu :",
"HeaderSetupLibrary": "Configurer votre biblioth\u00e8que de m\u00e9dia",
"ButtonAddMediaFolder": "Ajouter un r\u00e9pertoire de m\u00e9dia",
"LabelFolderType": "Type de r\u00e9pertoire:",
- "MediaFolderHelpPluginRequired": "* N\u00e9cessite l'utilisation d'un plugin, par exemple : \"GameBrowser\" ou \"MB BookShelf\".",
"ReferToMediaLibraryWiki": "Se r\u00e9f\u00e9rer au wiki des biblioth\u00e8ques de m\u00e9dia",
"LabelCountry": "Pays:",
"LabelLanguage": "Langue:",
@@ -52,12 +63,16 @@
"TabPreferences": "Pr\u00e9f\u00e9rences",
"TabPassword": "Mot de passe",
"TabLibraryAccess": "Acc\u00e8s aux biblioth\u00e8ques",
+ "TabAccess": "Acc\u00e8s",
"TabImage": "Image",
"TabProfile": "Profil",
"TabMetadata": "M\u00e9tadonn\u00e9es",
"TabImages": "Images",
"TabNotifications": "Notifications",
"TabCollectionTitles": "Titres",
+ "HeaderDeviceAccess": "Acc\u00e8s \u00e0 l'appareil",
+ "OptionEnableAccessFromAllDevices": "Autoriser l'acc\u00e8s \u00e0 tous les appareils",
+ "DeviceAccessHelp": "Ceci ne s'applique qu'aux appareils qui peuvent \u00eatre identifi\u00e9s de mani\u00e8re unique et qui n'emp\u00eachent pas l'acc\u00e8s au navigateur. Le filtrage de l'acc\u00e8s aux appareil par utilisateur emp\u00eachera l'utilisation de nouveaux appareils jusqu'\u00e0 ce qu'ils soient approuv\u00e9s ici.",
"LabelDisplayMissingEpisodesWithinSeasons": "Afficher les \u00e9pisodes manquants dans les saisons",
"LabelUnairedMissingEpisodesWithinSeasons": "Afficher les \u00e9pisodes non diffus\u00e9s dans les saisons",
"HeaderVideoPlaybackSettings": "Param\u00e8tres de lecture video",
@@ -232,10 +247,10 @@
"HeaderFeatureAccess": "Acc\u00e8s aux caract\u00e9ristiques",
"OptionAllowMediaPlayback": "Autoriser la lecture du m\u00e9dia",
"OptionAllowBrowsingLiveTv": "Autoriser la TV en direct",
- "OptionAllowDeleteLibraryContent": "Allow deletion of library content",
+ "OptionAllowDeleteLibraryContent": "Autoriser la suppression de contenu dans la biblioth\u00e8que",
"OptionAllowManageLiveTv": "Autoriser la gestion des enregistrements de la TV en direct",
- "OptionAllowRemoteControlOthers": "Allow remote control of other users",
- "OptionAllowRemoteSharedDevices": "Allow remote control of shared devices",
+ "OptionAllowRemoteControlOthers": "Autoriser le contr\u00f4le \u00e0 distance d'autres utilisateurs",
+ "OptionAllowRemoteSharedDevices": "Autoriser le contr\u00f4le \u00e0 distance des disques partag\u00e9s",
"OptionAllowRemoteSharedDevicesHelp": "Les p\u00e9riph\u00e9riques Dlna sont consid\u00e9r\u00e9s comme partag\u00e9s tant qu'un utilisateur ne commence pas \u00e0 le contr\u00f4ler.",
"HeaderRemoteControl": "Contr\u00f4le \u00e0 distance",
"OptionMissingTmdbId": "ID TMDb manquant",
@@ -450,7 +465,7 @@
"CustomDlnaProfilesHelp": "Cr\u00e9er un profil personnalis\u00e9 pour cibler un nouveau p\u00e9riph\u00e9rique ou surpasser un profil syst\u00e8me.",
"SystemDlnaProfilesHelp": "Les profils syst\u00e8mes sont en lecture seule. Les modifications apport\u00e9es \u00e0 un profil syst\u00e8me seront enregistr\u00e9es sous un nouveau profil personnalis\u00e9.",
"TitleDashboard": "Tableau de bord",
- "TabHome": "Portail",
+ "TabHome": "Accueil",
"TabInfo": "Info",
"HeaderLinks": "Liens",
"HeaderSystemPaths": "Chemins d'acc\u00e8s syst\u00e8mes",
@@ -529,7 +544,7 @@
"LabelDeleteEmptyFoldersHelp": "Activer cette option pour garder le r\u00e9pertoire de t\u00e9l\u00e9chargement vide.",
"LabelDeleteLeftOverFiles": "Supprimer le reste des fichiers avec les extensions suivantes:",
"LabelDeleteLeftOverFilesHelp": "S\u00e9parer par ;. Par exemple: .nfo;.txt",
- "OptionOverwriteExistingEpisodes": "\u00c9craser les \u00e9pisodes existantes",
+ "OptionOverwriteExistingEpisodes": "\u00c9craser les \u00e9pisodes existants",
"LabelTransferMethod": "M\u00e9thode de transfert",
"OptionCopy": "Copier",
"OptionMove": "D\u00e9placer",
@@ -657,7 +672,7 @@
"NotificationOptionPluginError": "\u00c9chec de plugin",
"ButtonVolumeUp": "Volume haut",
"ButtonVolumeDown": "Volume bas",
- "ButtonMute": "Sourdine",
+ "ButtonMute": "Muet",
"HeaderLatestMedia": "Derniers m\u00e9dias",
"OptionSpecialFeatures": "Bonus",
"HeaderCollections": "Collections",
@@ -1214,7 +1229,7 @@
"TabCameraUpload": "Upload de la cam\u00e9ra",
"TabDevices": "P\u00e9riph\u00e9riques",
"HeaderCameraUploadHelp": "Uploader automatiquement les photos et les vid\u00e9os depuis vos p\u00e9riph\u00e9riques mobiles dans Media Browser.",
- "MessageNoDevicesSupportCameraUpload": "Vous n'avez actuellement aucun p\u00e9riph\u00e9riques support\u00e9 par l'upload de la cam\u00e9ra.",
+ "MessageNoDevicesSupportCameraUpload": "Vous n'avez actuellement aucun p\u00e9riph\u00e9riques supportant l'upload du flux vid\u00e9o de la cam\u00e9ra.",
"LabelCameraUploadPath": "R\u00e9pertoire de l'upload de la camera:",
"LabelCameraUploadPathHelp": "Si vous le souhaitez, vous pouvez choisir un r\u00e9pertoire d'upload personnalis\u00e9. Si vous ne mettez rien, le r\u00e9pertoire par d\u00e9faut sera utilis\u00e9. Si vous utilisez un r\u00e9pertoire personnalis\u00e9, vous devrez le rajouter \u00e0 la biblioth\u00e8que.",
"LabelCreateCameraUploadSubfolder": "Cr\u00e9er un sous-dossier pour chaque p\u00e9riph\u00e9rique",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer reel",
"OptionPlayUnwatchedTrailersOnly": "Lire seulement les bandes-annonces non lus.",
"HeaderTrailerReelHelp": "Commencer un \"trailer reel\" pour lire une longue liste de lecture de bandes-annonces.",
- "MessageNoTrailersFound": "Aucune bande-annonce trouv\u00e9e. Installer le plugin \"Trailer channel\" pour importer une biblioth\u00e8que de bandes-annonces Internet.",
+ "MessageNoTrailersFound": "Aucune bande-annonce trouv\u00e9e. Installez la cha\u00eene Bande-annonces pour am\u00e9liorer votre exp\u00e9rience, par l'ajout d'une biblioth\u00e8que de bandes-annonces disponibles sur Internet.",
"HeaderNewUsers": "Nouveaux utilisateurs",
"ButtonSignUp": "S'inscrire",
"ButtonForgotPassword": "Mot de passe oubli\u00e9 ?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limiter \u00e0 une seule image int\u00e9gr\u00e9e",
"LabelEnableSingleImageInDidlLimitHelp": "Quelques p\u00e9riph\u00e9riques ne fourniront pas un rendu correct si plusieurs images sont int\u00e9gr\u00e9es dans Didl",
"TabActivity": "Activit\u00e9",
- "TitleSync": "Sync."
+ "TitleSync": "Sync.",
+ "OptionAllowSyncContent": "Autoriser la synchronisation des media sur les p\u00e9riph\u00e9riques",
+ "NameSeasonUnknown": "Saison inconnue",
+ "NameSeasonNumber": "Saison {0}",
+ "LabelNewUserNameHelp": "Les noms d'utilisateur peuvent contenir des lettres (a-z), des chiffres (0-9), des tirets (-), des tirets bas (_), des apostrophes (') et des points (.)."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/he.json b/MediaBrowser.Server.Implementations/Localization/Server/he.json
index cecde2022..ae1a06bb3 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/he.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/he.json
@@ -37,10 +37,21 @@
"ButtonOk": "\u05d0\u05e9\u05e8",
"ButtonCancel": "\u05d1\u05d8\u05dc",
"ButtonNew": "\u05d7\u05d3\u05e9",
+ "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": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "\u05d4\u05d2\u05d3\u05e8 \u05d0\u05ea \u05e1\u05e4\u05e8\u05d9\u05d9\u05ea \u05d4\u05de\u05d3\u05d9\u05d4 \u05e9\u05dc\u05da",
"ButtonAddMediaFolder": "\u05d4\u05d5\u05e1\u05e3 \u05ea\u05d9\u05e7\u05d9\u05d9\u05ea \u05de\u05d3\u05d9\u05d4",
"LabelFolderType": "\u05e1\u05d5\u05d2 \u05d4\u05ea\u05d9\u05e7\u05d9\u05d9\u05d4:",
- "MediaFolderHelpPluginRequired": "* \u05de\u05e6\u05e8\u05d9\u05da \u05de\u05d4\u05de\u05e9\u05ea\u05de\u05e9 \u05ea\u05d5\u05e1\u05e3, \u05dc\u05d3\u05d5\u05d2\u05de\u05d0 GameBrowser \u05d0\u05d5 MB Bookshelf",
"ReferToMediaLibraryWiki": "\u05e4\u05e0\u05d4 \u05dc\u05de\u05d9\u05d3\u05e2 \u05d0\u05d5\u05d3\u05d5\u05ea \u05e1\u05e4\u05e8\u05d9\u05d9\u05ea \u05d4\u05de\u05d3\u05d9\u05d4.",
"LabelCountry": "\u05de\u05d3\u05d9\u05e0\u05d4:",
"LabelLanguage": "\u05e9\u05e4\u05d4:",
@@ -52,12 +63,16 @@
"TabPreferences": "\u05d4\u05e2\u05d3\u05e4\u05d5\u05ea",
"TabPassword": "\u05e1\u05d9\u05e1\u05de\u05d0",
"TabLibraryAccess": "\u05d2\u05d9\u05e9\u05d4 \u05dc\u05ea\u05d9\u05e7\u05d9\u05d5\u05ea",
+ "TabAccess": "Access",
"TabImage": "\u05ea\u05de\u05d5\u05e0\u05d4",
"TabProfile": "\u05e4\u05e8\u05d5\u05e4\u05d9\u05dc",
"TabMetadata": "Metadata",
"TabImages": "\u05ea\u05de\u05d5\u05e0\u05d5\u05ea",
"TabNotifications": "\u05d4\u05ea\u05e8\u05d0\u05d5\u05ea",
"TabCollectionTitles": "\u05db\u05d5\u05ea\u05e8\u05d9\u05dd",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "\u05d4\u05e6\u05d2 \u05e4\u05e8\u05e7\u05d9\u05dd \u05d7\u05e1\u05e8\u05d9\u05dd \u05d1\u05ea\u05d5\u05da \u05d4\u05e2\u05d5\u05e0\u05d5\u05ea",
"LabelUnairedMissingEpisodesWithinSeasons": "\u05d4\u05e6\u05d2 \u05e4\u05e8\u05e7\u05d9\u05dd \u05e9\u05e2\u05d3\u05d9\u05df \u05d0\u05dc \u05e9\u05d5\u05d3\u05e8\u05d5 \u05d1\u05ea\u05d5\u05da \u05d4\u05e2\u05d5\u05e0\u05d5\u05ea",
"HeaderVideoPlaybackSettings": "\u05d4\u05d2\u05d3\u05e8\u05d5\u05ea \u05e0\u05d9\u05d2\u05d5\u05df",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer Reel",
"OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
"HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
- "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "New Users",
"ButtonSignUp": "Sign up",
"ButtonForgotPassword": "Forgot password?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/hr.json b/MediaBrowser.Server.Implementations/Localization/Server/hr.json
index f7589ff00..e8f637fe2 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/hr.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/hr.json
@@ -37,10 +37,21 @@
"ButtonOk": "Ok",
"ButtonCancel": "Odustani",
"ButtonNew": "Novo",
+ "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": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "Postavi svoju medijsku biblioteku",
"ButtonAddMediaFolder": "Dodaj mapu sa medijem",
"LabelFolderType": "Tip mape:",
- "MediaFolderHelpPluginRequired": "* Zahtjeva kori\u0161tenje dodatka, npr. GameBrowser ili MB Bookshelf.",
"ReferToMediaLibraryWiki": "Informirajte se o medijskoj bibilioteci wiki",
"LabelCountry": "Zemlja:",
"LabelLanguage": "Jezik:",
@@ -52,12 +63,16 @@
"TabPreferences": "Postavke",
"TabPassword": "Lozinka",
"TabLibraryAccess": "Pristup biblioteci",
+ "TabAccess": "Access",
"TabImage": "Slika",
"TabProfile": "Profil",
"TabMetadata": "Metadata",
"TabImages": "Slike",
"TabNotifications": "Obavijesti",
"TabCollectionTitles": "Naslovi",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "Prika\u017ei epizode koje nedostaju unutar sezone",
"LabelUnairedMissingEpisodesWithinSeasons": "Prika\u017ei epizode koje nisu emitirane unutar sezone",
"HeaderVideoPlaybackSettings": "Postavke video reprodukcije",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer Reel",
"OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
"HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
- "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "New Users",
"ButtonSignUp": "Sign up",
"ButtonForgotPassword": "Forgot password?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/it.json b/MediaBrowser.Server.Implementations/Localization/Server/it.json
index 5daab33d8..c551052bd 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/it.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/it.json
@@ -37,10 +37,21 @@
"ButtonOk": "OK",
"ButtonCancel": "Annulla",
"ButtonNew": "Nuovo",
+ "FolderTypeMixed": "Mixed content",
+ "FolderTypeMovies": "Film",
+ "FolderTypeMusic": "Musica",
+ "FolderTypeAdultVideos": "Video per adulti",
+ "FolderTypePhotos": "Foto",
+ "FolderTypeMusicVideos": "Video musicali",
+ "FolderTypeHomeVideos": "Video personali",
+ "FolderTypeGames": "Giochi",
+ "FolderTypeBooks": "Libri",
+ "FolderTypeTvShows": "TV",
+ "FolderTypeInherit": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "Configura la tua libreria",
"ButtonAddMediaFolder": "Aggiungi cartella",
"LabelFolderType": "Tipo cartella",
- "MediaFolderHelpPluginRequired": "* Richiede l'uso di un plugin, ad esempio GameBrowser o MB Bookshelf.",
"ReferToMediaLibraryWiki": "Fare riferimento alla wiki libreria multimediale.",
"LabelCountry": "Nazione:",
"LabelLanguage": "lingua:",
@@ -52,12 +63,16 @@
"TabPreferences": "Preferenze",
"TabPassword": "Password",
"TabLibraryAccess": "Accesso libreria",
+ "TabAccess": "Access",
"TabImage": "Immagine",
"TabProfile": "Profilo",
"TabMetadata": "Metadata",
"TabImages": "Immagini",
"TabNotifications": "Notifiche",
"TabCollectionTitles": "Titolo",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "Visualizza gli episodi mancanti nelle stagioni",
"LabelUnairedMissingEpisodesWithinSeasons": "Visualizzare episodi mai andati in onda all'interno stagioni",
"HeaderVideoPlaybackSettings": "Impostazioni di riproduzione video",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer b.",
"OptionPlayUnwatchedTrailersOnly": "Riproduci solo i trailer non visti",
"HeaderTrailerReelHelp": "Inizia a riprodurre una lunga playlist di trailer",
- "MessageNoTrailersFound": "Nessun Trailer trovato.Installa Il plug in dei traler per importare la libreria dei trailer da internet",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "Nuovo Utente",
"ButtonSignUp": "Iscriviti",
"ButtonForgotPassword": "Dimenticato la password?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/kk.json b/MediaBrowser.Server.Implementations/Localization/Server/kk.json
index 2d9e4053d..1d997dbac 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/kk.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/kk.json
@@ -37,10 +37,21 @@
"ButtonOk": "\u0416\u0430\u0440\u0430\u0439\u0434\u044b",
"ButtonCancel": "\u0411\u043e\u043b\u0434\u044b\u0440\u043c\u0430\u0443",
"ButtonNew": "\u0416\u0430\u0441\u0430\u0443",
+ "FolderTypeMixed": "\u0410\u0440\u0430\u043b\u0430\u0441 \u043c\u0430\u0437\u043c\u04b1\u043d",
+ "FolderTypeMovies": "\u0424\u0438\u043b\u044c\u043c\u0434\u0435\u0440",
+ "FolderTypeMusic": "\u041c\u0443\u0437\u044b\u043a\u0430",
+ "FolderTypeAdultVideos": "\u0415\u0440\u0435\u0441\u0435\u043a\u0442\u0456\u043a \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440",
+ "FolderTypePhotos": "\u0424\u043e\u0442\u043e\u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440",
+ "FolderTypeMusicVideos": "\u041c\u0443\u0437\u044b\u043a\u0430\u043b\u044b\u049b \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440",
+ "FolderTypeHomeVideos": "\u04ae\u0439 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440\u0456",
+ "FolderTypeGames": "\u041e\u0439\u044b\u043d\u0434\u0430\u0440",
+ "FolderTypeBooks": "\u041a\u0456\u0442\u0430\u043f\u0442\u0430\u0440",
+ "FolderTypeTvShows": "\u0422\u0414",
+ "FolderTypeInherit": "\u041c\u04b1\u0440\u0430\u0493\u0430 \u0438\u0435\u043b\u0435\u043d\u0443",
+ "LabelContentType": "\u041c\u0430\u0437\u043c\u04b1\u043d \u0442\u04af\u0440\u0456:",
"HeaderSetupLibrary": "\u0422\u0430\u0441\u0443\u0448\u044b\u0445\u0430\u043d\u0430\u043d\u044b \u043e\u0440\u043d\u0430\u0442\u0443 \u0436\u04d9\u043d\u0435 \u0442\u0435\u04a3\u0448\u0435\u0443",
"ButtonAddMediaFolder": "\u0422\u0430\u0441\u0443\u0448\u044b \u049b\u0430\u043b\u0442\u0430\u0441\u044b\u043d \u04af\u0441\u0442\u0435\u0443",
"LabelFolderType": "\u049a\u0430\u043b\u0442\u0430 \u0442\u04af\u0440\u0456:",
- "MediaFolderHelpPluginRequired": "* \u041f\u043b\u0430\u0433\u0438\u043d\u0434\u0456 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u044b\u04a3\u044b\u0437, \u043c\u044b\u0441\u0430\u043b\u044b, GameBrowser, \u043d\u0435 MB Bookshelf.",
"ReferToMediaLibraryWiki": "\u0422\u0430\u0441\u0443\u0448\u044b\u0445\u0430\u043d\u0430 \u0442\u0443\u0440\u0430\u043b\u044b \u0443\u0438\u043a\u0438 \u0456\u0448\u0456\u043d\u0435\u043d \u049b\u0430\u0440\u0430\u04a3\u044b\u0437.",
"LabelCountry": "\u0415\u043b:",
"LabelLanguage": "\u0422\u0456\u043b:",
@@ -52,12 +63,16 @@
"TabPreferences": "\u0422\u0435\u04a3\u0448\u0435\u043b\u0456\u043c\u0434\u0435\u0440",
"TabPassword": "\u049a\u04b1\u043f\u0438\u044f \u0441\u04e9\u0437",
"TabLibraryAccess": "\u0422\u0430\u0441\u0443\u0448\u044b\u0445\u0430\u043d\u0430\u0493\u0430 \u049b\u0430\u0442\u044b\u043d\u0430\u0441",
+ "TabAccess": "Access",
"TabImage": "\u0421\u0443\u0440\u0435\u0442",
"TabProfile": "\u041f\u0440\u043e\u0444\u0438\u043b\u044c",
"TabMetadata": "\u041c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a",
"TabImages": "\u0421\u0443\u0440\u0435\u0442\u0442\u0435\u0440",
"TabNotifications": "\u0425\u0430\u0431\u0430\u0440\u043b\u0430\u043d\u0434\u044b\u0440\u0443\u043b\u0430\u0440",
"TabCollectionTitles": "\u0422\u0443\u044b\u043d\u0434\u044b\u043b\u0430\u0440",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "\u0416\u043e\u049b \u044d\u043f\u0438\u0437\u043e\u0434\u0442\u0430\u0440\u0434\u044b \u043c\u0430\u0443\u0441\u044b\u043c \u0456\u0448\u0456\u043d\u0434\u0435 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0443",
"LabelUnairedMissingEpisodesWithinSeasons": "\u041a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u043c\u0435\u0433\u0435\u043d \u044d\u043f\u0438\u0437\u043e\u0434\u0442\u0430\u0440\u0434\u044b \u043c\u0430\u0443\u0441\u044b\u043c \u0456\u0448\u0456\u043d\u0434\u0435 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0443",
"HeaderVideoPlaybackSettings": "\u0411\u0435\u0439\u043d\u0435 \u043e\u0439\u043d\u0430\u0442\u0443 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440\u0456",
@@ -365,8 +380,8 @@
"LabelMaxScreenshotsPerItem": "\u042d\u043b\u0435\u043c\u0435\u043d\u0442 \u0431\u043e\u0439\u044b\u043d\u0448\u0430 \u0435\u04a3 \u043a\u04e9\u043f \u0441\u043a\u0440\u0438\u043d\u0448\u043e\u0442 \u0441\u0430\u043d\u044b:",
"LabelMinBackdropDownloadWidth": "\u0410\u0440\u0442\u049b\u044b \u0441\u0443\u0440\u0435\u0442\u0442\u0456\u04a3 \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u044b\u043d\u0430\u0442\u044b\u043d \u0435\u04a3 \u0430\u0437 \u0435\u043d\u0456:",
"LabelMinScreenshotDownloadWidth": "\u0416\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443 \u04af\u0448\u0456\u043d \u0435\u04a3 \u0430\u0437 \u0441\u043a\u0440\u0438\u043d\u0448\u043e\u0442 \u0435\u043d\u0456:",
- "ButtonAddScheduledTaskTrigger": "\u0422\u0430\u043f\u0441\u044b\u0440\u043c\u0430 \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u0456\u043d \u04af\u0441\u0442\u0435\u0443",
- "HeaderAddScheduledTaskTrigger": "\u0422\u0430\u043f\u0441\u044b\u0440\u043c\u0430 \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u0456\u043d \u04af\u0441\u0442\u0435\u0443",
+ "ButtonAddScheduledTaskTrigger": "\u0422\u0440\u0438\u0433\u0433\u0435\u0440\u0434\u0456 \u04af\u0441\u0442\u0435\u0443",
+ "HeaderAddScheduledTaskTrigger": "\u0422\u0440\u0438\u0433\u0433\u0435\u0440\u0434\u0456 \u04af\u0441\u0442\u0435\u0443",
"ButtonAdd": "\u04ae\u0441\u0442\u0435\u0443",
"LabelTriggerType": "\u0422\u0440\u0438\u0433\u0433\u0435\u0440 \u0442\u04af\u0440\u0456:",
"OptionDaily": "\u041a\u04af\u043d \u0441\u0430\u0439\u044b\u043d",
@@ -683,9 +698,9 @@
"OptionProfilePhoto": "\u0424\u043e\u0442\u043e",
"LabelUserLibrary": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b \u0442\u0430\u0441\u0443\u0448\u044b\u0445\u0430\u043d\u0430\u0441\u044b",
"LabelUserLibraryHelp": "\u049a\u04b1\u0440\u044b\u043b\u0493\u044b\u0434\u0430 \u049b\u0430\u0439 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b \u0442\u0430\u0441\u0443\u0448\u044b\u0445\u0430\u043d\u0430\u0441\u044b\u043d \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0443\u0456\u043d \u0442\u0430\u04a3\u0434\u0430\u04a3\u044b\u0437. \u04d8\u0434\u0435\u043f\u043a\u0456 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u043c\u04b1\u0440\u0430\u0441\u044b\u043d\u0430 \u0438\u0435\u043b\u0435\u043d\u0443 \u04af\u0448\u0456\u043d \u0431\u043e\u0441 \u049b\u0430\u043b\u0434\u044b\u0440\u044b\u04a3\u044b\u0437.",
- "OptionPlainStorageFolders": "\u0411\u0430\u0440\u043b\u044b\u049b \u049b\u0430\u043b\u0442\u0430\u043b\u0430\u0440\u0434\u044b \u0436\u0430\u0439 \u0441\u0430\u049b\u0442\u0430\u0443 \u049b\u0430\u043b\u0442\u0430\u043b\u0430\u0440\u044b \u0440\u0435\u0442\u0456\u043d\u0434\u0435 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0443",
+ "OptionPlainStorageFolders": "\u0411\u0430\u0440\u043b\u044b\u049b \u049b\u0430\u043b\u0442\u0430\u043b\u0430\u0440\u0434\u044b \u043a\u04d9\u0434\u0456\u043c\u0433\u0456 \u0441\u0430\u049b\u0442\u0430\u0443 \u049b\u0430\u043b\u0442\u0430\u043b\u0430\u0440\u044b \u0440\u0435\u0442\u0456\u043d\u0434\u0435 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0443",
"OptionPlainStorageFoldersHelp": "\u049a\u043e\u0441\u044b\u043b\u0493\u0430\u043d\u0434\u0430, \u0431\u0430\u0440\u043b\u044b\u049b \u049b\u0430\u043b\u0442\u0430\u043b\u0430\u0440 DIDL \u0456\u0448\u0456\u043d\u0434\u0435 \"object.container.person.musicArtist\" \u0441\u0438\u044f\u049b\u0442\u044b \u043d\u0430\u049b\u0442\u044b\u043b\u0430\u0443 \u0442\u04af\u0440\u0456\u043d\u0456\u04a3 \u043e\u0440\u043d\u044b\u043d\u0430 \"object.container.storageFolder\" \u0431\u043e\u043b\u044b\u043f \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u043d\u0435\u0434\u0456.",
- "OptionPlainVideoItems": "\u0411\u0430\u0440\u043b\u044b\u049b \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440\u0434\u0456 \u0436\u0430\u0439 \u0431\u0435\u0439\u043d\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0442\u0435\u0440\u0456 \u0440\u0435\u0442\u0456\u043d\u0434\u0435 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0443",
+ "OptionPlainVideoItems": "\u0411\u0430\u0440\u043b\u044b\u049b \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440\u0434\u0456 \u043a\u04d9\u0434\u0456\u043c\u0433\u0456 \u0431\u0435\u0439\u043d\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0442\u0435\u0440\u0456 \u0440\u0435\u0442\u0456\u043d\u0434\u0435 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0443",
"OptionPlainVideoItemsHelp": "\u049a\u043e\u0441\u044b\u043b\u0493\u0430\u043d\u0434\u0430, \u0431\u0430\u0440\u043b\u044b\u049b \u049b\u0430\u043b\u0442\u0430\u043b\u0430\u0440 DIDL \u0456\u0448\u0456\u043d\u0434\u0435 \"object.item.videoItem.movie\" \u0441\u0438\u044f\u049b\u0442\u044b \u043d\u0430\u049b\u0442\u044b\u043b\u0430\u0443 \u0442\u04af\u0440\u0456\u043d\u0456\u04a3 \u043e\u0440\u043d\u044b\u043d\u0430 \"object.item.videoItem\" \u0431\u043e\u043b\u044b\u043f \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u043d\u0435\u0434\u0456.",
"LabelSupportedMediaTypes": "\u049a\u043e\u043b\u0434\u0430\u0443\u0434\u0430\u0493\u044b \u0442\u0430\u0441\u0443\u0448\u044b\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u0442\u04af\u0440\u043b\u0435\u0440\u0456:",
"TabIdentification": "\u0410\u043d\u044b\u049b\u0442\u0430\u0443",
@@ -1050,7 +1065,7 @@
"OptionOthers": "\u0411\u0430\u0441\u049b\u0430\u043b\u0430\u0440",
"HeaderDownloadPeopleMetadataForHelp": "\u049a\u043e\u0441\u044b\u043c\u0448\u0430 \u0442\u0435\u04a3\u0448\u0435\u043b\u0456\u043c\u0434\u0435\u0440\u0434\u0456 \u049b\u043e\u0441\u049b\u0430\u043d\u0434\u0430 \u044d\u043a\u0440\u0430\u043d\u0434\u0430\u0493\u044b \u0430\u049b\u043f\u0430\u0440\u0430\u0442\u0442\u044b \u043a\u04e9\u0431\u0456\u0440\u0435\u043a \u04b1\u0441\u044b\u043d\u0430\u0434\u044b, \u0431\u0456\u0440\u0430\u049b \u0442\u0430\u0441\u0443\u0448\u044b\u0445\u0430\u043d\u0430\u043d\u044b\u04a3 \u0441\u043a\u0430\u043d\u0435\u0440\u043b\u0435\u0443\u043b\u0435\u0440\u0456 \u0431\u0430\u044f\u0443\u043b\u0430\u0439\u0434\u044b.",
"ViewTypeFolders": "\u049a\u0430\u043b\u0442\u0430\u043b\u0430\u0440",
- "LabelDisplayFoldersView": "\u0416\u0430\u0439 \u0442\u0430\u0441\u0443\u0448\u044b \u049b\u0430\u043b\u0442\u0430\u043b\u0430\u0440\u044b\u043d \u043a\u04e9\u0440\u0441\u0435\u0442\u0443 \u04af\u0448\u0456\u043d \u049a\u0430\u043b\u0442\u0430\u043b\u0430\u0440 \u0430\u0441\u043f\u0435\u043a\u0442\u0456\u043d \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0443",
+ "LabelDisplayFoldersView": "\u041a\u04d9\u0434\u0456\u043c\u0433\u0456 \u0442\u0430\u0441\u0443\u0448\u044b \u049b\u0430\u043b\u0442\u0430\u043b\u0430\u0440\u044b\u043d \u043a\u04e9\u0440\u0441\u0435\u0442\u0443 \u04af\u0448\u0456\u043d \u049a\u0430\u043b\u0442\u0430\u043b\u0430\u0440 \u0430\u0441\u043f\u0435\u043a\u0442\u0456\u043d \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0443",
"ViewTypeLiveTvRecordingGroups": "\u0416\u0430\u0437\u0431\u0430\u043b\u0430\u0440",
"ViewTypeLiveTvChannels": "\u0410\u0440\u043d\u0430\u043b\u0430\u0440",
"LabelAllowLocalAccessWithoutPassword": "\u049a\u04b1\u043f\u0438\u044f \u0441\u04e9\u0437\u0441\u0456\u0437 \u0436\u0435\u0440\u0433\u0456\u043b\u0456\u043a\u0442\u0456 \u049b\u0430\u0442\u044b\u043d\u0441\u0443 \u04af\u0448\u0456\u043d \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0443",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "\u0422\u0440\u0435\u0439\u043b\u0435\u0440\u043b\u0435\u0440\u0434\u0456 \u0436\u0430\u043f\u0441\u044b\u0440\u0443",
"OptionPlayUnwatchedTrailersOnly": "\u0422\u0435\u043a \u049b\u0430\u043d\u0430 \u049b\u0430\u0440\u0430\u043b\u043c\u0430\u0493\u0430\u043d \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043b\u0435\u0440\u0434\u0456 \u043e\u0439\u043d\u0430\u0442\u0443",
"HeaderTrailerReelHelp": "\u04b0\u0437\u0430\u049b \u043e\u0440\u044b\u043d\u0434\u0430\u043b\u0430\u0442\u044b\u043d \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043b\u0435\u0440 \u043e\u0439\u043d\u0430\u0442\u0443 \u0442\u0456\u0437\u0456\u043c\u0456\u043d \u043e\u0439\u043d\u0430\u0442\u0443 \u04af\u0448\u0456\u043d \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043b\u0435\u0440\u0434\u0456 \u0436\u0430\u043f\u0441\u044b\u0440\u0443\u0434\u044b \u0431\u0430\u0441\u0442\u0430\u04a3\u044b\u0437.",
- "MessageNoTrailersFound": "\u0415\u0448\u049b\u0430\u043d\u0434\u0430\u0439 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043b\u0435\u0440 \u0442\u0430\u0431\u044b\u043b\u043c\u0430\u0434\u044b. \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043b\u0435\u0440 \u049b\u043e\u0440\u044b\u043d \u0438\u043c\u043f\u043e\u0440\u0442\u0442\u0430\u0443 \u04af\u0448\u0456\u043d \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043b\u0435\u0440 \u0430\u0440\u043d\u0430\u0441\u044b \u043f\u043b\u0430\u0433\u0438\u043d\u0456\u043d \u043e\u0440\u043d\u0430\u0442\u044b\u04a3\u044b\u0437.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "\u0416\u0430\u04a3\u0430 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043b\u0430\u0440",
"ButtonSignUp": "\u0422\u0456\u0440\u043a\u0435\u043b\u0443",
"ButtonForgotPassword": "\u049a\u04b1\u043f\u0438\u044f \u0441\u04e9\u0437\u0434\u0456 \u04b1\u043c\u044b\u0442\u044b\u04a3\u044b\u0437 \u0431\u0430?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "\u0416\u0430\u043b\u0493\u044b\u0437 \u043a\u0456\u0440\u0456\u0441\u0442\u0456\u0440\u0456\u043b\u0433\u0435\u043d \u0441\u0443\u0440\u0435\u0442\u043a\u0435 \u0448\u0435\u043a\u0442\u0435\u0443",
"LabelEnableSingleImageInDidlLimitHelp": "\u0415\u0433\u0435\u0440 \u0431\u0456\u0440\u043d\u0435\u0448\u0435 \u0441\u0443\u0440\u0435\u0442 Didl \u0456\u0448\u0456\u043d\u0435 \u043a\u0456\u0440\u0456\u0441\u0442\u0456\u0440\u0456\u043b\u0441\u0435, \u043a\u0435\u0439\u0431\u0456\u0440 \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u043b\u0430\u0440\u0434\u0430 \u0442\u0438\u0456\u0441\u0442\u0456 \u0442\u04af\u0440\u0434\u0435 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u043d\u0431\u0435\u0439\u0434\u0456.",
"TabActivity": "\u04d8\u0440\u0435\u043a\u0435\u0442\u0442\u0435\u0440",
- "TitleSync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0434\u0430\u0443"
+ "TitleSync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0434\u0430\u0443",
+ "OptionAllowSyncContent": "\u041c\u0435\u0434\u0438\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u043c\u0435\u043d \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0434\u0430\u0443\u0493\u0430 \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0443",
+ "NameSeasonUnknown": "\u0411\u0435\u043b\u0433\u0456\u0441\u0456\u0437 \u043c\u0430\u0443\u0441\u044b\u043c",
+ "NameSeasonNumber": "{0}-\u0441\u0435\u0437\u043e\u043d",
+ "LabelNewUserNameHelp": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b \u0430\u0442\u0442\u0430\u0440\u044b\u043d\u0434\u0430 \u04d9\u0440\u0456\u043f\u0442\u0435\u0440 (a-z), \u0441\u0430\u043d\u0434\u0430\u0440 (0-9), \u0441\u044b\u0437\u044b\u049b\u0448\u0430\u043b\u0430\u0440 (-), \u0430\u0441\u0442\u044b\u04a3\u0493\u044b \u0441\u044b\u0437\u044b\u049b\u0442\u0430\u0440 (_), \u0434\u04d9\u0439\u0435\u043a\u0448\u0435\u043b\u0435\u0440 (') \u0436\u04d9\u043d\u0435 \u043d\u04af\u043a\u0442\u0435\u043b\u0435\u0440 (.) \u0431\u043e\u043b\u0443\u044b \u043c\u04af\u043c\u043a\u0456\u043d"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/ko.json b/MediaBrowser.Server.Implementations/Localization/Server/ko.json
index 2a0bcc74f..8336a5cdd 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/ko.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/ko.json
@@ -37,10 +37,21 @@
"ButtonOk": "Ok",
"ButtonCancel": "Cancel",
"ButtonNew": "New",
+ "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": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "Setup your media library",
"ButtonAddMediaFolder": "Add media folder",
"LabelFolderType": "Folder type:",
- "MediaFolderHelpPluginRequired": "* Requires the use of a plugin, e.g. GameBrowser or MB Bookshelf.",
"ReferToMediaLibraryWiki": "Refer to the media library wiki.",
"LabelCountry": "Country:",
"LabelLanguage": "Language:",
@@ -52,12 +63,16 @@
"TabPreferences": "Preferences",
"TabPassword": "Password",
"TabLibraryAccess": "Library Access",
+ "TabAccess": "Access",
"TabImage": "Image",
"TabProfile": "Profile",
"TabMetadata": "Metadata",
"TabImages": "Images",
"TabNotifications": "Notifications",
"TabCollectionTitles": "Titles",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons",
"LabelUnairedMissingEpisodesWithinSeasons": "Display unaired episodes within seasons",
"HeaderVideoPlaybackSettings": "Video Playback Settings",
@@ -365,8 +380,8 @@
"LabelMaxScreenshotsPerItem": "Maximum number of screenshots per item:",
"LabelMinBackdropDownloadWidth": "Minimum backdrop download width:",
"LabelMinScreenshotDownloadWidth": "Minimum screenshot download width:",
- "ButtonAddScheduledTaskTrigger": "Add Task Trigger",
- "HeaderAddScheduledTaskTrigger": "Add Task Trigger",
+ "ButtonAddScheduledTaskTrigger": "Add Trigger",
+ "HeaderAddScheduledTaskTrigger": "Add Trigger",
"ButtonAdd": "Add",
"LabelTriggerType": "Trigger Type:",
"OptionDaily": "Daily",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer Reel",
"OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
"HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
- "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "New Users",
"ButtonSignUp": "Sign up",
"ButtonForgotPassword": "Forgot password?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/ms.json b/MediaBrowser.Server.Implementations/Localization/Server/ms.json
index adbe36a92..3f91dbccc 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/ms.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/ms.json
@@ -37,10 +37,21 @@
"ButtonOk": "Ok",
"ButtonCancel": "Cancel",
"ButtonNew": "New",
+ "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": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "Setup your media library",
"ButtonAddMediaFolder": "Add media folder",
"LabelFolderType": "Folder type:",
- "MediaFolderHelpPluginRequired": "* Requires the use of a plugin, e.g. GameBrowser or MB Bookshelf.",
"ReferToMediaLibraryWiki": "Refer to the media library wiki.",
"LabelCountry": "Country:",
"LabelLanguage": "Language:",
@@ -52,12 +63,16 @@
"TabPreferences": "Preferences",
"TabPassword": "Password",
"TabLibraryAccess": "Library Access",
+ "TabAccess": "Access",
"TabImage": "Image",
"TabProfile": "Profile",
"TabMetadata": "Metadata",
"TabImages": "Images",
"TabNotifications": "Notifications",
"TabCollectionTitles": "Titles",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons",
"LabelUnairedMissingEpisodesWithinSeasons": "Display unaired episodes within seasons",
"HeaderVideoPlaybackSettings": "Video Playback Settings",
@@ -365,8 +380,8 @@
"LabelMaxScreenshotsPerItem": "Maximum number of screenshots per item:",
"LabelMinBackdropDownloadWidth": "Minimum backdrop download width:",
"LabelMinScreenshotDownloadWidth": "Minimum screenshot download width:",
- "ButtonAddScheduledTaskTrigger": "Add Task Trigger",
- "HeaderAddScheduledTaskTrigger": "Add Task Trigger",
+ "ButtonAddScheduledTaskTrigger": "Add Trigger",
+ "HeaderAddScheduledTaskTrigger": "Add Trigger",
"ButtonAdd": "Add",
"LabelTriggerType": "Trigger Type:",
"OptionDaily": "Daily",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer Reel",
"OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
"HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
- "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "New Users",
"ButtonSignUp": "Sign up",
"ButtonForgotPassword": "Forgot password?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/nb.json b/MediaBrowser.Server.Implementations/Localization/Server/nb.json
index a6a1fa3c4..49073383c 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/nb.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/nb.json
@@ -37,10 +37,21 @@
"ButtonOk": "Ok",
"ButtonCancel": "avbryt",
"ButtonNew": "Ny",
+ "FolderTypeMixed": "Mixed content",
+ "FolderTypeMovies": "Filmer",
+ "FolderTypeMusic": "Musikk",
+ "FolderTypeAdultVideos": "Voksen videoer",
+ "FolderTypePhotos": "Foto",
+ "FolderTypeMusicVideos": "Musikk videoer",
+ "FolderTypeHomeVideos": "Hjemme videoer",
+ "FolderTypeGames": "Spill",
+ "FolderTypeBooks": "B\u00f8ker",
+ "FolderTypeTvShows": "TV",
+ "FolderTypeInherit": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "Konfigurer media-biblioteket",
"ButtonAddMediaFolder": "Legg til media-mappe",
"LabelFolderType": "Mappe typpe",
- "MediaFolderHelpPluginRequired": "* Krever bruk av et programtillegg f.eks GameBrowser eller MB Bookshelf.",
"ReferToMediaLibraryWiki": "Se i media-bibliotek wikien",
"LabelCountry": "LAnd",
"LabelLanguage": "Spr\u00e5k:",
@@ -52,12 +63,16 @@
"TabPreferences": "Preferanser",
"TabPassword": "Passord",
"TabLibraryAccess": "Bibliotektilgang",
+ "TabAccess": "Access",
"TabImage": "Bilde",
"TabProfile": "profil",
"TabMetadata": "Metadata",
"TabImages": "Bilder",
"TabNotifications": "Varslinger",
"TabCollectionTitles": "Titler",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "Vis episoder som sesongen mangler",
"LabelUnairedMissingEpisodesWithinSeasons": "Vis episoder som enn\u00e5 ikke har blitt sendt",
"HeaderVideoPlaybackSettings": "Innstillinger for video-avspilling",
@@ -232,9 +247,9 @@
"HeaderFeatureAccess": "Funksjon Tilgang",
"OptionAllowMediaPlayback": "Tillatt medieavspilling",
"OptionAllowBrowsingLiveTv": "Tillat surfing av Live TV",
- "OptionAllowDeleteLibraryContent": "Allow deletion of library content",
+ "OptionAllowDeleteLibraryContent": "Tillat sletting av bibliotek innhold",
"OptionAllowManageLiveTv": "Tillat styring av Live TV opptak",
- "OptionAllowRemoteControlOthers": "Allow remote control of other users",
+ "OptionAllowRemoteControlOthers": "Tillat fjernstyring av andre brukere",
"OptionAllowRemoteSharedDevices": "Allow remote control of shared devices",
"OptionAllowRemoteSharedDevicesHelp": "Dlna devices are considered shared until a user begins controlling it.",
"HeaderRemoteControl": "Remote Control",
@@ -459,7 +474,7 @@
"LinkApiDocumentation": "Api Dokumentasjon",
"LabelFriendlyServerName": "Vennlig server navn:",
"LabelFriendlyServerNameHelp": "Dette navnet vil bli brukt for \u00e5 identifisere denne serveren. Hvis feltet er tomt, vil maskinens navn bli brukt.",
- "LabelPreferredDisplayLanguage": "Preferred display language:",
+ "LabelPreferredDisplayLanguage": "Foretrukket skjerm spr\u00e5k:",
"LabelPreferredDisplayLanguageHelp": "Oversetting av Media Browser er ett p\u00e5g\u00e5ende prosjekt og er enda ikke fullstendig ferdig.",
"LabelReadHowYouCanContribute": "Les mer om hvordan du kan bidra.",
"HeaderNewCollection": "Ny Samling",
@@ -1228,7 +1243,7 @@
"HeaderSignInWithConnect": "Sign in with Media Browser Connect",
"HeaderGuests": "Gjester",
"HeaderLocalUsers": "Lokale Brukere",
- "HeaderPendingInvitations": "Pending Invitations",
+ "HeaderPendingInvitations": "Ventende invitasjoner",
"TabParentalControl": "Foreldrekontroll",
"HeaderAccessSchedule": "Access Schedule",
"HeaderAccessScheduleHelp": "Create an access schedule to limit access to certain hours.",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer Reel",
"OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
"HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
- "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "Nye Brukere",
"ButtonSignUp": "Registrering",
"ButtonForgotPassword": "Glemt passord?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/nl.json b/MediaBrowser.Server.Implementations/Localization/Server/nl.json
index c4f65de2c..a4245f9ab 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/nl.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/nl.json
@@ -37,10 +37,21 @@
"ButtonOk": "Ok",
"ButtonCancel": "Annuleren",
"ButtonNew": "Nieuw",
+ "FolderTypeMixed": "Gemengde inhoud",
+ "FolderTypeMovies": "Films",
+ "FolderTypeMusic": "Muziek",
+ "FolderTypeAdultVideos": "Adult video's",
+ "FolderTypePhotos": "Foto's",
+ "FolderTypeMusicVideos": "Muziek video's",
+ "FolderTypeHomeVideos": "Thuis video's",
+ "FolderTypeGames": "Games",
+ "FolderTypeBooks": "Boeken",
+ "FolderTypeTvShows": "TV",
+ "FolderTypeInherit": "overerven",
+ "LabelContentType": "Inhoud type:",
"HeaderSetupLibrary": "Stel uw mediabibliotheek in",
"ButtonAddMediaFolder": "Mediamap toevoegen",
"LabelFolderType": "Maptype:",
- "MediaFolderHelpPluginRequired": "* Hiervoor is het gebruik van een Plug-in vereist, bijvoorbeeld GameBrowser of MB Bookshelf.",
"ReferToMediaLibraryWiki": "Raadpleeg de mediabibliotheek wiki.",
"LabelCountry": "Land:",
"LabelLanguage": "Taal:",
@@ -52,12 +63,16 @@
"TabPreferences": "Voorkeuren",
"TabPassword": "Wachtwoord",
"TabLibraryAccess": "Bibliotheek toegang",
+ "TabAccess": "Access",
"TabImage": "Afbeelding",
"TabProfile": "Profiel",
"TabMetadata": "Metagegevens",
"TabImages": "Afbeeldingen",
"TabNotifications": "Meldingen",
"TabCollectionTitles": "Titels",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "Toon ontbrekende afleveringen binnen een seizoen",
"LabelUnairedMissingEpisodesWithinSeasons": "Toon komende afleveringen binnen een seizoen",
"HeaderVideoPlaybackSettings": "Video afspeel instellingen",
@@ -232,10 +247,10 @@
"HeaderFeatureAccess": "Functie toegang",
"OptionAllowMediaPlayback": "Afspelen van media toestaan",
"OptionAllowBrowsingLiveTv": "Bladeren door live tv toestaan",
- "OptionAllowDeleteLibraryContent": "Allow deletion of library content",
+ "OptionAllowDeleteLibraryContent": "Verwijderen van bibliotheek inhoud toestaan",
"OptionAllowManageLiveTv": "Beheer van live tv-opnames toestaan",
- "OptionAllowRemoteControlOthers": "Allow remote control of other users",
- "OptionAllowRemoteSharedDevices": "Allow remote control of shared devices",
+ "OptionAllowRemoteControlOthers": "Op afstand besturen van andere gebruikers toestaan",
+ "OptionAllowRemoteSharedDevices": "Op afstand besturen van gedeelde apparaten toestaan",
"OptionAllowRemoteSharedDevicesHelp": "Dlna apparaten worden als gedeeld apparaat gezien totdat een gebruiker deze gaat gebruiken.",
"HeaderRemoteControl": "Gebruik op afstand",
"OptionMissingTmdbId": "TMDB Id ontbreekt",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer reel",
"OptionPlayUnwatchedTrailersOnly": "Speel alleen ongeziene trailers",
"HeaderTrailerReelHelp": "Start trailer reel om een afspeellijst met trailers af te spelen.",
- "MessageNoTrailersFound": "Geen trailers gevonden. Installeer het trailer kanaal om internet trailers te importeren.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "Nieuwe gebruikers",
"ButtonSignUp": "Aanmelden",
"ButtonForgotPassword": "Wachtwoord vergeten?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Beperk tot \u00e9\u00e9n enkele ingesloten afbeelding",
"LabelEnableSingleImageInDidlLimitHelp": "Sommige apparaten zullen niet goed weergeven als er meerdere afbeeldingen ingesloten zijn in Didl.",
"TabActivity": "Activiteit",
- "TitleSync": "Synchroniseer"
+ "TitleSync": "Synchroniseer",
+ "OptionAllowSyncContent": "Synchroniseren van media naar apparaten toestaan",
+ "NameSeasonUnknown": "Seizoen Onbekend",
+ "NameSeasonNumber": "Seizoen {0}",
+ "LabelNewUserNameHelp": "Gebruikersnamen kunnen letters (az), cijfers (0-9), streepjes, underscores (_), apostrofs (') en punten (.) bevatten\n"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/pl.json b/MediaBrowser.Server.Implementations/Localization/Server/pl.json
index a0d70f6c6..091033f15 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/pl.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/pl.json
@@ -37,10 +37,21 @@
"ButtonOk": "Ok",
"ButtonCancel": "Anuluj",
"ButtonNew": "New",
+ "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": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "Ustaw swoj\u0105 bibliotek\u0119",
"ButtonAddMediaFolder": "Dodaj folder",
"LabelFolderType": "Typ folderu:",
- "MediaFolderHelpPluginRequired": "* Wymaga u\u017cycia wtyczki takiej jak GameBrowser lub MB Bookshelf.",
"ReferToMediaLibraryWiki": "Odnie\u015b si\u0119 do wiki biblioteki.",
"LabelCountry": "Kraj:",
"LabelLanguage": "J\u0119zyk:",
@@ -52,12 +63,16 @@
"TabPreferences": "Preferencje",
"TabPassword": "Has\u0142o",
"TabLibraryAccess": "Dost\u0119p do biblioteki",
+ "TabAccess": "Access",
"TabImage": "Obraz",
"TabProfile": "Profil",
"TabMetadata": "Metadata",
"TabImages": "Images",
"TabNotifications": "Notifications",
"TabCollectionTitles": "Titles",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "Wy\u015bwietl brakuj\u0105ce odcinki w sezonach",
"LabelUnairedMissingEpisodesWithinSeasons": "Wy\u015bwietl nie wydanie odcinki w sezonach",
"HeaderVideoPlaybackSettings": "Ustawienia odtwarzania wideo",
@@ -365,8 +380,8 @@
"LabelMaxScreenshotsPerItem": "Maximum number of screenshots per item:",
"LabelMinBackdropDownloadWidth": "Minimum backdrop download width:",
"LabelMinScreenshotDownloadWidth": "Minimum screenshot download width:",
- "ButtonAddScheduledTaskTrigger": "Add Task Trigger",
- "HeaderAddScheduledTaskTrigger": "Add Task Trigger",
+ "ButtonAddScheduledTaskTrigger": "Add Trigger",
+ "HeaderAddScheduledTaskTrigger": "Add Trigger",
"ButtonAdd": "Add",
"LabelTriggerType": "Trigger Type:",
"OptionDaily": "Daily",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer Reel",
"OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
"HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
- "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "New Users",
"ButtonSignUp": "Sign up",
"ButtonForgotPassword": "Forgot password?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json b/MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json
index 134059faf..4c3b9c6bb 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json
@@ -37,10 +37,21 @@
"ButtonOk": "Ok",
"ButtonCancel": "Cancelar",
"ButtonNew": "Novo",
+ "FolderTypeMixed": "Conte\u00fado misto",
+ "FolderTypeMovies": "Filmes",
+ "FolderTypeMusic": "M\u00fasica",
+ "FolderTypeAdultVideos": "V\u00eddeos adultos",
+ "FolderTypePhotos": "Fotos",
+ "FolderTypeMusicVideos": "V\u00eddeos musicais",
+ "FolderTypeHomeVideos": "V\u00eddeos caseiros",
+ "FolderTypeGames": "Jogos",
+ "FolderTypeBooks": "Livros",
+ "FolderTypeTvShows": "TV",
+ "FolderTypeInherit": "Herdar",
+ "LabelContentType": "Tipo de conte\u00fado:",
"HeaderSetupLibrary": "Configurar sua biblioteca de m\u00eddias",
"ButtonAddMediaFolder": "Adicionar pasta de m\u00eddias",
"LabelFolderType": "Tipo de pasta:",
- "MediaFolderHelpPluginRequired": "* Requer o uso de um plugin, ex. GameBrowser ou MB Bookshelf.",
"ReferToMediaLibraryWiki": "Consultar wiki da biblioteca de m\u00eddias",
"LabelCountry": "Pa\u00eds:",
"LabelLanguage": "Idioma:",
@@ -52,12 +63,16 @@
"TabPreferences": "Prefer\u00eancias",
"TabPassword": "Senha",
"TabLibraryAccess": "Acesso \u00e0 Biblioteca",
+ "TabAccess": "Acesso",
"TabImage": "Imagem",
"TabProfile": "Perfil",
"TabMetadata": "Metadados",
"TabImages": "Imagens",
"TabNotifications": "Notifica\u00e7\u00f5es",
"TabCollectionTitles": "T\u00edtulos",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "Exibir epis\u00f3dios que faltam dentro das temporadas",
"LabelUnairedMissingEpisodesWithinSeasons": "Exibir epis\u00f3dios por estrear dentro das temporadas",
"HeaderVideoPlaybackSettings": "Ajustes da Reprodu\u00e7\u00e3o de V\u00eddeo",
@@ -365,8 +380,8 @@
"LabelMaxScreenshotsPerItem": "N\u00famero m\u00e1ximo de imagens de tela por item:",
"LabelMinBackdropDownloadWidth": "Tamanho m\u00ednimo da imagem de fundo para download:",
"LabelMinScreenshotDownloadWidth": "Tamanho m\u00ednimo da imagem de tela para download:",
- "ButtonAddScheduledTaskTrigger": "Adicionar Disparador da Tarefa",
- "HeaderAddScheduledTaskTrigger": "Adicionar Disparador da Tarefa",
+ "ButtonAddScheduledTaskTrigger": "Adicionar Disparador",
+ "HeaderAddScheduledTaskTrigger": "Adicionar Disparador",
"ButtonAdd": "Adicionar",
"LabelTriggerType": "Tipo de Disparador:",
"OptionDaily": "Di\u00e1rio",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Carrossel de Trailers",
"OptionPlayUnwatchedTrailersOnly": "Reproduzir apenas trailers n\u00e3o assistidos",
"HeaderTrailerReelHelp": "Inicie um carrossel de trailers para reproduzir uma longa lista de reprodu\u00e7\u00e3o de trailers.",
- "MessageNoTrailersFound": "Nenhum trailer encontrado. Instale o plugin de canal para importar uma biblioteca de trailers da internet.",
+ "MessageNoTrailersFound": "Nenhum trailer encontrado. Instale o canal Trailer para melhorar sua experi\u00eancia com filmes, adicionando uma biblioteca de trailers da internet.",
"HeaderNewUsers": "Novos Usu\u00e1rios",
"ButtonSignUp": "Entrar",
"ButtonForgotPassword": "Esqueceu a senha?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limitar a uma imagem incorporada",
"LabelEnableSingleImageInDidlLimitHelp": "Alguns dispositivos n\u00e3o interpretar\u00e3o apropriadamente se m\u00faltiplas imagens estiverem incorporadas dentro do Didl.",
"TabActivity": "Atividade",
- "TitleSync": "Sinc"
+ "TitleSync": "Sinc",
+ "OptionAllowSyncContent": "Permitir sincroniza\u00e7\u00e3o de m\u00eddia com os dispositivos",
+ "NameSeasonUnknown": "Temporada Desconhecida",
+ "NameSeasonNumber": "Temporada {0}",
+ "LabelNewUserNameHelp": "Nomes de usu\u00e1rios podem conter letras (a-z), n\u00fameros (0-9), tra\u00e7os (-), sublinhados (_), ap\u00f3strofes (') e pontos (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json b/MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json
index 792a9eb0f..a13ce7565 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json
@@ -37,10 +37,21 @@
"ButtonOk": "Ok",
"ButtonCancel": "Cancelar",
"ButtonNew": "Novo",
+ "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": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "Configurar biblioteca",
"ButtonAddMediaFolder": "Adicionar pasta de media",
"LabelFolderType": "Tipo de pasta",
- "MediaFolderHelpPluginRequired": "* Requer o uso de uma extens\u00e3o, e.g. GameBrowser ou MB Bookshelf",
"ReferToMediaLibraryWiki": "Consulte a wiki",
"LabelCountry": "Pa\u00eds:",
"LabelLanguage": "Idioma:",
@@ -52,12 +63,16 @@
"TabPreferences": "Prefer\u00eancias",
"TabPassword": "Senha",
"TabLibraryAccess": "Aceder \u00e0 Biblioteca",
+ "TabAccess": "Access",
"TabImage": "Imagem",
"TabProfile": "Perfil",
"TabMetadata": "Metadados",
"TabImages": "Imagens",
"TabNotifications": "Notifica\u00e7\u00f5es",
"TabCollectionTitles": "T\u00edtulos",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "Mostrar epis\u00f3dios em falta dentro das temporadas",
"LabelUnairedMissingEpisodesWithinSeasons": "Mostrar epis\u00f3dios por estrear dentro das temporadas",
"HeaderVideoPlaybackSettings": "Configura\u00e7\u00f5es de Reprodu\u00e7\u00e3o de V\u00eddeo",
@@ -232,9 +247,9 @@
"HeaderFeatureAccess": "Acesso a Caracter\u00edsticas",
"OptionAllowMediaPlayback": "Permitir reprodu\u00e7\u00e3o de multim\u00e9dia",
"OptionAllowBrowsingLiveTv": "Permitir navega\u00e7\u00e3o da tv ao vivo",
- "OptionAllowDeleteLibraryContent": "Allow deletion of library content",
+ "OptionAllowDeleteLibraryContent": "Permitir que conte\u00fado da biblioteca seja apagado",
"OptionAllowManageLiveTv": "Permitir gest\u00e3o das grava\u00e7\u00f5es da tv ao vivo",
- "OptionAllowRemoteControlOthers": "Allow remote control of other users",
+ "OptionAllowRemoteControlOthers": "Permitir controlo remoto de outros utilizadores",
"OptionAllowRemoteSharedDevices": "Allow remote control of shared devices",
"OptionAllowRemoteSharedDevicesHelp": "Dlna devices are considered shared until a user begins controlling it.",
"HeaderRemoteControl": "Remote Control",
@@ -552,10 +567,10 @@
"MessagePleaseRestartServerToFinishUpdating": "Por favor reinicie o servidor para terminar a aplica\u00e7\u00e3o das atualiza\u00e7\u00f5es.",
"LabelDownMixAudioScale": "Escala do aumento de \u00e1udio ao fazer downmix:",
"LabelDownMixAudioScaleHelp": "Aumentar o \u00e1udio ao fazer downmix. Defina como 1 para preservar o volume original.",
- "ButtonLinkKeys": "Transfer Key",
+ "ButtonLinkKeys": "Transferir Chave",
"LabelOldSupporterKey": "Chave de apoiante antiga",
"LabelNewSupporterKey": "Chave de apoiante nova",
- "HeaderMultipleKeyLinking": "Transfer to New Key",
+ "HeaderMultipleKeyLinking": "Transferir para Nova Chave",
"MultipleKeyLinkingHelp": "If you received a new supporter key, use this form to transfer the old key's registrations to your new one.",
"LabelCurrentEmailAddress": "Endere\u00e7o de email atual",
"LabelCurrentEmailAddressHelp": "O endere\u00e7o de email atual para o qual a sua nova chave foi enviada.",
@@ -677,9 +692,9 @@
"HeaderCodecProfileHelp": "Codec profiles indicate the limitations of a device when playing specific codecs. If a limitation applies then the media will be transcoded, even if the codec is configured for direct play.",
"HeaderContainerProfile": "Container Profile",
"HeaderContainerProfileHelp": "Container profiles indicate the limitations of a device when playing specific formats. If a limitation applies then the media will be transcoded, even if the format is configured for direct play.",
- "OptionProfileVideo": "Video",
- "OptionProfileAudio": "Audio",
- "OptionProfileVideoAudio": "Video Audio",
+ "OptionProfileVideo": "V\u00eddeo",
+ "OptionProfileAudio": "\u00c1udio",
+ "OptionProfileVideoAudio": "\u00c1udio do V\u00eddeo",
"OptionProfilePhoto": "Photo",
"LabelUserLibrary": "User library:",
"LabelUserLibraryHelp": "Select which user library to display to the device. Leave empty to inherit the default setting.",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer Reel",
"OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
"HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
- "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "New Users",
"ButtonSignUp": "Sign up",
"ButtonForgotPassword": "Forgot password?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/ru.json b/MediaBrowser.Server.Implementations/Localization/Server/ru.json
index e35d8a097..e7604ba6f 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/ru.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/ru.json
@@ -37,10 +37,21 @@
"ButtonOk": "\u041e\u041a",
"ButtonCancel": "\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c",
"ButtonNew": "\u0421\u043e\u0437\u0434\u0430\u0442\u044c",
+ "FolderTypeMixed": "\u0420\u0430\u0437\u043d\u043e\u0442\u0438\u043f\u043d\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435",
+ "FolderTypeMovies": "\u0424\u0438\u043b\u044c\u043c\u044b",
+ "FolderTypeMusic": "\u041c\u0443\u0437\u044b\u043a\u0430",
+ "FolderTypeAdultVideos": "\u0412\u0437\u0440\u043e\u0441\u043b\u044b\u0435 \u0432\u0438\u0434\u0435\u043e",
+ "FolderTypePhotos": "\u0424\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438",
+ "FolderTypeMusicVideos": "\u041c\u0443\u0437\u044b\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u0432\u0438\u0434\u0435\u043e",
+ "FolderTypeHomeVideos": "\u0414\u043e\u043c\u0430\u0448\u043d\u0438\u0435 \u0432\u0438\u0434\u0435\u043e",
+ "FolderTypeGames": "\u0418\u0433\u0440\u044b",
+ "FolderTypeBooks": "\u041a\u043d\u0438\u0433\u0438",
+ "FolderTypeTvShows": "\u0422\u0412",
+ "FolderTypeInherit": "\u041d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u043c\u044b\u0439",
+ "LabelContentType": "\u0422\u0438\u043f \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f:",
"HeaderSetupLibrary": "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438",
"ButtonAddMediaFolder": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043c\u0435\u0434\u0438\u0430\u043f\u0430\u043f\u043a\u0443",
"LabelFolderType": "\u0422\u0438\u043f \u043f\u0430\u043f\u043a\u0438:",
- "MediaFolderHelpPluginRequired": "* \u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043b\u0430\u0433\u0438\u043d, \u043d\u043f\u0440., GameBrowser \u0438\u043b\u0438 MB Bookshelf.",
"ReferToMediaLibraryWiki": "\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435\u0441\u044c \u043a \u0432\u0438\u043a\u0438 \u043f\u043e \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0435.",
"LabelCountry": "\u0421\u0442\u0440\u0430\u043d\u0430:",
"LabelLanguage": "\u042f\u0437\u044b\u043a:",
@@ -52,12 +63,16 @@
"TabPreferences": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438",
"TabPassword": "\u041f\u0430\u0440\u043e\u043b\u044c",
"TabLibraryAccess": "\u0414\u043e\u0441\u0442\u0443\u043f \u043a \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0435",
+ "TabAccess": "Access",
"TabImage": "\u0420\u0438\u0441\u0443\u043d\u043e\u043a",
"TabProfile": "\u041f\u0440\u043e\u0444\u0438\u043b\u044c",
"TabMetadata": "\u041c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435",
"TabImages": "\u0420\u0438\u0441\u0443\u043d\u043a\u0438",
"TabNotifications": "\u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f",
"TabCollectionTitles": "\u041f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u044d\u043f\u0438\u0437\u043e\u0434\u044b \u0432 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u0445 \u0441\u0435\u0437\u043e\u043d\u043e\u0432",
"LabelUnairedMissingEpisodesWithinSeasons": "\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0435 \u044d\u043f\u0438\u0437\u043e\u0434\u044b \u0432 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u0445 \u0441\u0435\u0437\u043e\u043d\u043e\u0432",
"HeaderVideoPlaybackSettings": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0432\u0438\u0434\u0435\u043e",
@@ -225,17 +240,17 @@
"VisitMediaBrowserWebsiteLong": "\u041f\u043e\u0441\u0435\u0442\u0438\u0442\u0435 \u0441\u0430\u0439\u0442 Media Browser, \u0447\u0442\u043e\u0431\u044b \u0441\u043b\u0435\u0434\u0438\u0442\u044c \u0437\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c\u0438 \u043d\u043e\u0432\u043e\u0441\u0442\u044f\u043c\u0438 \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u043e\u0441\u0432\u0435\u0434\u043e\u043c\u043b\u0451\u043d\u043d\u043e\u0441\u0442\u044c \u043f\u043e \u0431\u043b\u043e\u0433\u0443 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432.",
"OptionHideUser": "\u0421\u043a\u0440\u044b\u0442\u044c \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0441 \u044d\u043a\u0440\u0430\u043d\u043e\u0432 \u0432\u0445\u043e\u0434\u0430",
"OptionDisableUser": "\u0417\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f",
- "OptionDisableUserHelp": "\u041f\u0440\u0438 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438, \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0435 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u043b\u044e\u0431\u044b\u0445 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439 \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0442 \u0440\u0435\u0437\u043a\u043e \u043e\u0431\u043e\u0440\u0432\u0430\u043d\u044b.",
+ "OptionDisableUserHelp": "\u041f\u0440\u0438 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438, \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442 \u043b\u044e\u0431\u044b\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0442 \u0440\u0435\u0437\u043a\u043e \u043e\u0431\u043e\u0440\u0432\u0430\u043d\u044b.",
"HeaderAdvancedControl": "\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435",
"LabelName": "\u0418\u043c\u044f (\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435):",
- "OptionAllowUserToManageServer": "\u042d\u0442\u043e\u043c\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c",
+ "OptionAllowUserToManageServer": "\u042d\u0442\u043e\u043c\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c",
"HeaderFeatureAccess": "\u0414\u043e\u0441\u0442\u0443\u043f \u043a \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438",
"OptionAllowMediaPlayback": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445",
"OptionAllowBrowsingLiveTv": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440 \u0422\u0412-\u044d\u0444\u0438\u0440\u0430",
- "OptionAllowDeleteLibraryContent": "\u041f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438",
+ "OptionAllowDeleteLibraryContent": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438",
"OptionAllowManageLiveTv": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438 \u0441 \u0422\u0412-\u044d\u0444\u0438\u0440\u0430",
- "OptionAllowRemoteControlOthers": "\u041f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u0433\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438",
- "OptionAllowRemoteSharedDevices": "\u041f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u0433\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u0431\u0449\u0438\u043c\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438",
+ "OptionAllowRemoteControlOthers": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438",
+ "OptionAllowRemoteSharedDevices": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e\u0431\u0449\u0438\u043c\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438",
"OptionAllowRemoteSharedDevicesHelp": "DLNA-\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0441\u0447\u0438\u0442\u0430\u044e\u0442\u0441\u044f \u043e\u0431\u0449\u0438\u043c\u0438, \u043f\u043e\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0438\u043c\u0438.",
"HeaderRemoteControl": "\u0423\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435",
"OptionMissingTmdbId": "\u041d\u0435\u0442 TMDb Id",
@@ -258,7 +273,7 @@
"OptionRelease": "\u041e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0432\u044b\u043f\u0443\u0441\u043a",
"OptionBeta": "\u0411\u0435\u0442\u0430-\u0432\u0435\u0440\u0441\u0438\u044f",
"OptionDev": "\u0420\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u0430\u044f (\u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e)",
- "LabelAllowServerAutoRestart": "\u0421\u0435\u0440\u0432\u0435\u0440\u0443 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438, \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439",
+ "LabelAllowServerAutoRestart": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439",
"LabelAllowServerAutoRestartHelp": "\u0421\u0435\u0440\u0432\u0435\u0440 \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u043f\u0435\u0440\u0438\u043e\u0434\u044b \u043f\u0440\u043e\u0441\u0442\u043e\u044f, \u043a\u043e\u0433\u0434\u0430 \u043d\u0438\u043a\u0430\u043a\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u043d\u0435 \u0430\u043a\u0442\u0438\u0432\u043d\u044b.",
"LabelEnableDebugLogging": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u044b\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0416\u0443\u0440\u043d\u0430\u043b\u0435",
"LabelRunServerAtStartup": "\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u0440\u0438 \u0441\u0442\u0430\u0440\u0442\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b",
@@ -365,8 +380,8 @@
"LabelMaxScreenshotsPerItem": "\u041c\u0430\u043a\u0441. \u0447\u0438\u0441\u043b\u043e \u0441\u043d\u0438\u043c\u043a\u043e\u0432 \u044d\u043a\u0440\u0430\u043d\u0430 \u043d\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442:",
"LabelMinBackdropDownloadWidth": "\u041c\u0438\u043d. \u0448\u0438\u0440\u0438\u043d\u0430 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u043e\u0433\u043e \u0437\u0430\u0434\u043d\u0438\u043a\u0430:",
"LabelMinScreenshotDownloadWidth": "\u041c\u0438\u043d. \u0448\u0438\u0440\u0438\u043d\u0430 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u043e\u0433\u043e \u0441\u043d\u0438\u043c\u043a\u0430 \u044d\u043a\u0440\u0430\u043d\u0430:",
- "ButtonAddScheduledTaskTrigger": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u0440\u0438\u0433\u0433\u0435\u0440 \u0437\u0430\u0434\u0430\u0447\u0438",
- "HeaderAddScheduledTaskTrigger": "\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u0430 \u0437\u0430\u0434\u0430\u0447\u0438",
+ "ButtonAddScheduledTaskTrigger": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u0440\u0438\u0433\u0433\u0435\u0440",
+ "HeaderAddScheduledTaskTrigger": "\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u0430",
"ButtonAdd": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c",
"LabelTriggerType": "\u0422\u0438\u043f \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u0430:",
"OptionDaily": "\u0415\u0436\u0435\u0434\u043d\u0435\u0432\u043d\u043e",
@@ -435,7 +450,7 @@
"OptionMaxQualityTranscoding": "\u041a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e",
"OptionEnableDebugTranscodingLogging": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u044b\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u043f\u0435\u0440\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0438 \u0432 \u0416\u0443\u0440\u043d\u0430\u043b\u0435",
"OptionEnableDebugTranscodingLoggingHelp": "\u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u0431\u0443\u0434\u0443\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0444\u0430\u0439\u043b\u044b \u0416\u0443\u0440\u043d\u0430\u043b\u0430 \u043e\u0447\u0435\u043d\u044c \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043e\u0431\u044a\u0451\u043c\u0430, \u0430 \u044d\u0442\u043e \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0441\u0438\u043b\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0443\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043d\u0435\u043f\u043e\u043b\u0430\u0434\u043e\u043a.",
- "OptionUpscaling": "\u041a\u043b\u0438\u0435\u043d\u0442\u0430\u043c \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0437\u0430\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u044b\u0441\u043e\u043a\u043e\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0432\u0438\u0434\u0435\u043e",
+ "OptionUpscaling": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c \u0437\u0430\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u044b\u0441\u043e\u043a\u043e\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0432\u0438\u0434\u0435\u043e",
"OptionUpscalingHelp": "\u0412 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445, \u044d\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u0442 \u043a \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044e \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 \u0432\u0438\u0434\u0435\u043e, \u043d\u043e \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u0441\u044f \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u0430.",
"EditCollectionItemsHelp": "\u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0438\u043b\u0438 \u0438\u0437\u044b\u043c\u0438\u0442\u0435 \u043b\u044e\u0431\u044b\u0435 \u0444\u0438\u043b\u044c\u043c\u044b, \u0441\u0435\u0440\u0438\u0430\u043b\u044b, \u0430\u043b\u044c\u0431\u043e\u043c\u044b, \u043a\u043d\u0438\u0433\u0438 \u0438\u043b\u0438 \u0438\u0433\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0445\u043e\u0442\u0438\u0442\u0435 \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u043d\u0443\u0442\u0440\u0438 \u0434\u0430\u043d\u043d\u043e\u0439 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438.",
"HeaderAddTitles": "\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0439",
@@ -690,7 +705,7 @@
"LabelSupportedMediaTypes": "\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0435 \u0442\u0438\u043f\u044b \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445:",
"TabIdentification": "\u0420\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u043d\u0438\u0435",
"HeaderIdentification": "\u0420\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u043d\u0438\u0435",
- "TabDirectPlay": "\u041f\u0440\u044f\u043c\u043e\u0435 \u0432\u043e\u0441\u043f\u0440-\u0438\u0435",
+ "TabDirectPlay": "\u041f\u0440\u044f\u043c\u043e\u0435 \u0432\u043e\u0441\u043f\u0440.",
"TabContainers": "\u041a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b",
"TabCodecs": "\u041a\u043e\u0434\u0435\u043a\u0438",
"TabResponses": "\u041e\u0442\u043a\u043b\u0438\u043a\u0438",
@@ -944,7 +959,7 @@
"TabSort": "\u041f\u043e\u0440\u044f\u0434\u043e\u043a",
"TabFilter": "\u0424\u0438\u043b\u044c\u0442\u0440\u044b",
"ButtonView": "\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c",
- "LabelPageSize": "\u041c\u0430\u043a\u0441. \u0447\u0438\u0441\u043b\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432:",
+ "LabelPageSize": "\u041f\u0440\u0435\u0434\u0435\u043b \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432:",
"LabelPath": "\u041f\u0443\u0442\u044c:",
"LabelView": "\u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435:",
"TabUsers": "\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438",
@@ -1021,9 +1036,9 @@
"ItemAddedWithName": "{0} (\u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0443)",
"ItemRemovedWithName": "{0} (\u0438\u0437\u044a\u044f\u0442\u043e \u0438\u0437 \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438)",
"DeviceOnlineWithName": "{0} - \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e",
- "UserOnlineFromDevice": "{0} - \u043f\u043e\u0434\u043a\u043b-\u0438\u0435 \u0441 {1} \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e",
+ "UserOnlineFromDevice": "{0} - \u043f\u043e\u0434\u043a\u043b. \u0441 {1} \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e",
"DeviceOfflineWithName": "{0} - \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043f\u0440\u0435\u0440\u0432\u0430\u043d\u043e",
- "UserOfflineFromDevice": "{0} - \u043f\u043e\u0434\u043a\u043b-\u0438\u0435 \u0441 {1} \u043f\u0440\u0435\u0440\u0432\u0430\u043d\u043e",
+ "UserOfflineFromDevice": "{0} - \u043f\u043e\u0434\u043a\u043b. \u0441 {1} \u043f\u0440\u0435\u0440\u0432\u0430\u043d\u043e",
"SubtitlesDownloadedForItem": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u044b \u0434\u043b\u044f {0} \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u043b\u0438\u0441\u044c",
"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",
"LabelRunningTimeValue": "\u0412\u0440\u0435\u043c\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f: {0}",
@@ -1037,9 +1052,9 @@
"MessageApplicationUpdated": "Media Browser Server \u0431\u044b\u043b \u043e\u0431\u043d\u043e\u0432\u043b\u0451\u043d",
"AuthenticationSucceededWithUserName": "{0} - \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0443\u0441\u043f\u0435\u0448\u043d\u0430",
"FailedLoginAttemptWithUserName": "{0} - \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u0432\u0445\u043e\u0434\u0430 \u043d\u0435\u0443\u0434\u0430\u0447\u043d\u0430",
- "UserStartedPlayingItemWithValues": "{0} - \u0432\u043e\u0441\u043f\u0440-\u0438\u0435 \u00ab{1}\u00bb \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043e",
- "UserStoppedPlayingItemWithValues": "{0} - \u0432\u043e\u0441\u043f\u0440-\u0438\u0435 \u00ab{1}\u00bb \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e",
- "AppDeviceValues": "\u041f\u0440\u0438\u043b-\u0438\u0435: {0}, \u0423\u0441\u0442\u0440-\u0432\u043e: {1}",
+ "UserStartedPlayingItemWithValues": "{0} - \u0432\u043e\u0441\u043f\u0440. \u00ab{1}\u00bb \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043e",
+ "UserStoppedPlayingItemWithValues": "{0} - \u0432\u043e\u0441\u043f\u0440. \u00ab{1}\u00bb \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e",
+ "AppDeviceValues": "\u041f\u0440\u0438\u043b.: {0}, \u0423\u0441\u0442\u0440.: {1}",
"ProviderValue": "\u041f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a: {0}",
"LabelChannelDownloadSizeLimit": "\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u043e\u0433\u043e, \u0413\u0411:",
"LabelChannelDownloadSizeLimitHelpText": "\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u044c\u0442\u0435 \u0440\u0430\u0437\u043c\u0435\u0440 \u043f\u0430\u043f\u043a\u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u044b\u0445 \u043a\u0430\u043d\u0430\u043b\u043e\u0432.",
@@ -1191,8 +1206,8 @@
"LabelLimitIntrosToUnwatchedContent": "\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u043a \u043d\u0435\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u043e\u043c\u0443 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044e",
"LabelEnableIntroParentalControl": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435\u043c",
"LabelEnableIntroParentalControlHelp": "\u0422\u0440\u0435\u0439\u043b\u0435\u0440\u044b \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u043d\u043e\u0439 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0435\u0439 \u0440\u0430\u0432\u043d\u043e\u0439 \u0438\u043b\u0438 \u043c\u0435\u043d\u044c\u0448\u0435\u0439, \u0447\u0435\u043c \u043f\u0440\u043e\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u043c\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435.",
- "LabelTheseFeaturesRequireSupporterHelpAndTrailers": "\u0414\u0430\u043d\u043d\u044b\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0447\u043b\u0435\u043d\u0441\u0442\u0432\u043e \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430 \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043f\u043b\u0430\u0433\u0438\u043d\u0430 \u043a\u0430\u043d\u0430\u043b\u0430 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432.",
- "OptionTrailersFromMyMoviesHelp": "\u041f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432.",
+ "LabelTheseFeaturesRequireSupporterHelpAndTrailers": "\u0414\u0430\u043d\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0442\u0440\u0435\u0431\u0443\u044e\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0447\u043b\u0435\u043d\u0441\u0442\u0432\u0430 \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430 \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043f\u043b\u0430\u0433\u0438\u043d\u0430 \u043a\u0430\u043d\u0430\u043b\u0430 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432.",
+ "OptionTrailersFromMyMoviesHelp": "\u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432.",
"LabelCustomIntrosPath": "\u041f\u0443\u0442\u044c \u043a \u043d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c \u0437\u0430\u0441\u0442\u0430\u0432\u043a\u0430\u043c:",
"LabelCustomIntrosPathHelp": "\u041f\u0430\u043f\u043a\u0430, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0430\u044f \u0432\u0438\u0434\u0435\u043e\u0444\u0430\u0439\u043b\u044b. \u0412\u0438\u0434\u0435\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043e \u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432.",
"ValueSpecialEpisodeName": "\u0421\u043f\u0435\u0446\u044d\u043f\u0438\u0437\u043e\u0434 - {0}",
@@ -1200,7 +1215,7 @@
"OptionUpcomingDvdMovies": "\u041e\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u044b \u043a \u043d\u043e\u0432\u044b\u043c \u0438 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u043c \u0444\u0438\u043b\u044c\u043c\u0430\u043c \u043d\u0430 DVD \u0438 BluRay",
"OptionUpcomingStreamingMovies": "\u041e\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u044b \u043a \u043d\u043e\u0432\u044b\u043c \u0438 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u043c \u0444\u0438\u043b\u044c\u043c\u0430\u043c \u043d\u0430 Netflix",
"LabelDisplayTrailersWithinMovieSuggestions": "\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u044b \u0432 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u0445 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c\u044b\u0445 \u0444\u0438\u043b\u044c\u043c\u043e\u0432",
- "LabelDisplayTrailersWithinMovieSuggestionsHelp": "\u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043a\u0430\u043d\u0430\u043b\u0430 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432",
+ "LabelDisplayTrailersWithinMovieSuggestionsHelp": "\u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043a\u0430\u043d\u0430\u043b\u0430 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432.",
"CinemaModeConfigurationHelp2": "\u041e\u0431\u043e\u0441\u043e\u0431\u043b\u0435\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0431\u0443\u0434\u0443\u0442 \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u044b \u0432\u044b\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0440\u0435\u0436\u0438\u043c \u043a\u0438\u043d\u043e\u0442\u0435\u0430\u0442\u0440\u0430 \u0432 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u0445 \u0441\u0432\u043e\u0438\u0445 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a.",
"LabelEnableCinemaMode": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0440\u0435\u0436\u0438\u043c \u043a\u0438\u043d\u043e\u0442\u0435\u0430\u0442\u0440\u0430",
"HeaderCinemaMode": "\u0420\u0435\u0436\u0438\u043c \u043a\u0438\u043d\u043e\u0442\u0435\u0430\u0442\u0440\u0430",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "\u0421\u043a\u043b\u0435\u0439\u043a\u0430 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432",
"OptionPlayUnwatchedTrailersOnly": "\u0412\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0435 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u044b",
"HeaderTrailerReelHelp": "\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 \u0441\u043a\u043b\u0435\u0439\u043a\u0443 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u0434\u043e\u043b\u0433\u043e\u0438\u0433\u0440\u0430\u044e\u0449\u0438\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432.",
- "MessageNoTrailersFound": "\u0422\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e. \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 \u043f\u043b\u0430\u0433\u0438\u043d \u043a\u0430\u043d\u0430\u043b\u0430 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432 \u0434\u043b\u044f \u0438\u043c\u043f\u043e\u0440\u0442\u0430 \u0441\u043e\u0431\u0440\u0430\u043d\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432.",
+ "MessageNoTrailersFound": "\u0422\u0440\u0435\u0439\u043b\u0435\u0440\u044b \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b. \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 \u043a\u0430\u043d\u0430\u043b \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u0443\u0441\u0438\u043b\u0438\u0442\u044c \u0432\u0430\u0448\u0435 \u0432\u043f\u0435\u0447\u0430\u0442\u043b\u0435\u043d\u0438\u0435 \u043e\u0442 \u0444\u0438\u043b\u044c\u043c\u0430, \u043f\u0443\u0442\u0435\u043c \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0431\u0440\u0430\u043d\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432.",
"HeaderNewUsers": "\u041d\u043e\u0432\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438",
"ButtonSignUp": "\u0417\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f",
"ButtonForgotPassword": "\u0417\u0430\u0431\u044b\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c?",
@@ -1277,7 +1292,11 @@
"LabelBlockItemsWithTags": "\u0411\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0441 \u0442\u0435\u0433\u0430\u043c\u0438:",
"LabelTag": "\u0422\u0435\u0433:",
"LabelEnableSingleImageInDidlLimit": "\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0442\u044c \u0434\u043e \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0432\u043d\u0435\u0434\u0440\u0451\u043d\u043d\u043e\u0433\u043e \u0440\u0438\u0441\u0443\u043d\u043a\u0430",
- "LabelEnableSingleImageInDidlLimitHelp": "\u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e, \u0435\u0441\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0438\u0441\u0443\u043d\u043a\u043e\u0432 \u0432\u043d\u0435\u0434\u0440\u044f\u044e\u0442\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0438 Didl.",
+ "LabelEnableSingleImageInDidlLimitHelp": "\u041d\u0430 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u0445 \u043d\u0435 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e, \u0435\u0441\u043b\u0438 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u044b \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0438\u0441\u0443\u043d\u043a\u043e\u0432 \u0432\u043d\u0443\u0442\u0440\u0438 Didl.",
"TabActivity": "\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044f",
- "TitleSync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f"
+ "TitleSync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f",
+ "OptionAllowSyncContent": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044e \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438",
+ "NameSeasonUnknown": "\u0421\u0435\u0437\u043e\u043d \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d",
+ "NameSeasonNumber": "\u0421\u0435\u0437\u043e\u043d {0}",
+ "LabelNewUserNameHelp": "\u0418\u043c\u0435\u043d\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043c\u043e\u0433\u0443\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0431\u0443\u043a\u0432\u044b (a-z), \u0446\u0438\u0444\u0440\u044b (0-9), \u0434\u0435\u0444\u0438\u0441\u044b (-), \u043f\u043e\u0434\u0447\u0451\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u044f (_), \u0430\u043f\u043e\u0441\u0442\u0440\u043e\u0444\u044b (') \u0438 \u0442\u043e\u0447\u043a\u0438 (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json
index 09cd286b4..839c22ecf 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/server.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json
@@ -37,10 +37,21 @@
"ButtonOk": "Ok",
"ButtonCancel": "Cancel",
"ButtonNew": "New",
+ "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": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "Setup your media library",
"ButtonAddMediaFolder": "Add media folder",
"LabelFolderType": "Folder type:",
- "MediaFolderHelpPluginRequired": "* Requires the use of a plugin, e.g. GameBrowser or MB Bookshelf.",
"ReferToMediaLibraryWiki": "Refer to the media library wiki.",
"LabelCountry": "Country:",
"LabelLanguage": "Language:",
@@ -52,12 +63,16 @@
"TabPreferences": "Preferences",
"TabPassword": "Password",
"TabLibraryAccess": "Library Access",
+ "TabAccess": "Access",
"TabImage": "Image",
"TabProfile": "Profile",
"TabMetadata": "Metadata",
"TabImages": "Images",
"TabNotifications": "Notifications",
"TabCollectionTitles": "Titles",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons",
"LabelUnairedMissingEpisodesWithinSeasons": "Display unaired episodes within seasons",
"HeaderVideoPlaybackSettings": "Video Playback Settings",
@@ -366,8 +381,8 @@
"LabelMaxScreenshotsPerItem": "Maximum number of screenshots per item:",
"LabelMinBackdropDownloadWidth": "Minimum backdrop download width:",
"LabelMinScreenshotDownloadWidth": "Minimum screenshot download width:",
- "ButtonAddScheduledTaskTrigger": "Add Task Trigger",
- "HeaderAddScheduledTaskTrigger": "Add Task Trigger",
+ "ButtonAddScheduledTaskTrigger": "Add Trigger",
+ "HeaderAddScheduledTaskTrigger": "Add Trigger",
"ButtonAdd": "Add",
"LabelTriggerType": "Trigger Type:",
"OptionDaily": "Daily",
@@ -1262,7 +1277,7 @@
"HeaderTrailerReel": "Trailer Reel",
"OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
"HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
- "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "New Users",
"ButtonSignUp": "Sign up",
"ButtonForgotPassword": "Forgot password?",
@@ -1295,5 +1310,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
}
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/sv.json b/MediaBrowser.Server.Implementations/Localization/Server/sv.json
index b3831a097..3f3886ffe 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/sv.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/sv.json
@@ -37,10 +37,21 @@
"ButtonOk": "OK",
"ButtonCancel": "Avbryt",
"ButtonNew": "Nytillkommet",
+ "FolderTypeMixed": "Mixed content",
+ "FolderTypeMovies": "Filmer",
+ "FolderTypeMusic": "Musik",
+ "FolderTypeAdultVideos": "Inneh\u00e5ll f\u00f6r vuxna",
+ "FolderTypePhotos": "Foton",
+ "FolderTypeMusicVideos": "Musikvideor",
+ "FolderTypeHomeVideos": "Hemvideor",
+ "FolderTypeGames": "Spel",
+ "FolderTypeBooks": "B\u00f6cker",
+ "FolderTypeTvShows": "TV",
+ "FolderTypeInherit": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "Konfigurera mediabiblioteket",
"ButtonAddMediaFolder": "Skapa mediamapp",
"LabelFolderType": "Typ av mapp:",
- "MediaFolderHelpPluginRequired": "* Kr\u00e4ver att ett till\u00e4gg, t ex GameBrowser eller MB Bookshelf, \u00e4r installerat.",
"ReferToMediaLibraryWiki": "Se avsnittet om mediabibliotek i v\u00e5r Wiki.",
"LabelCountry": "Land:",
"LabelLanguage": "Spr\u00e5k:",
@@ -52,12 +63,16 @@
"TabPreferences": "Inst\u00e4llningar",
"TabPassword": "L\u00f6senord",
"TabLibraryAccess": "\u00c5tkomst till biblioteket",
+ "TabAccess": "Access",
"TabImage": "Bild",
"TabProfile": "Profil",
"TabMetadata": "Metadata",
"TabImages": "Bilder",
"TabNotifications": "Meddelanden",
"TabCollectionTitles": "Titlar",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "Visa saknade avsnitt i s\u00e4songer",
"LabelUnairedMissingEpisodesWithinSeasons": "Visa \u00e4nnu ej s\u00e4nda avsnitt i s\u00e4songer",
"HeaderVideoPlaybackSettings": "Inst\u00e4llningar f\u00f6r videouppspelning",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer Reel",
"OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
"HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
- "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "New Users",
"ButtonSignUp": "Sign up",
"ButtonForgotPassword": "Forgot password?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/tr.json b/MediaBrowser.Server.Implementations/Localization/Server/tr.json
index 51644f389..63f9e61db 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/tr.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/tr.json
@@ -37,10 +37,21 @@
"ButtonOk": "Tamam",
"ButtonCancel": "\u0130ptal",
"ButtonNew": "Yeni",
+ "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": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "Medya k\u00fct\u00fcphaneni kur",
"ButtonAddMediaFolder": "Yeni Media Klas\u00f6r\u00fc",
"LabelFolderType": "Klas\u00f6r T\u00fcr\u00fc:",
- "MediaFolderHelpPluginRequired": "* Requires the use of a plugin, e.g. GameBrowser or MB Bookshelf.",
"ReferToMediaLibraryWiki": "Refer to the media library wiki.",
"LabelCountry": "\u00dclke",
"LabelLanguage": "Dil",
@@ -52,12 +63,16 @@
"TabPreferences": "Tercihler",
"TabPassword": "\u015eifre",
"TabLibraryAccess": "K\u00fct\u00fcphane Eri\u015fim",
+ "TabAccess": "Access",
"TabImage": "Resim",
"TabProfile": "Profil",
"TabMetadata": "Metadata",
"TabImages": "Resimler",
"TabNotifications": "Notifications",
"TabCollectionTitles": "Titles",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "Sezondaki kay\u0131p b\u00f6l\u00fcmleri g\u00f6ster",
"LabelUnairedMissingEpisodesWithinSeasons": "Display unaired episodes within seasons",
"HeaderVideoPlaybackSettings": "Video Oynatma Ayarlar\u0131",
@@ -365,8 +380,8 @@
"LabelMaxScreenshotsPerItem": "Maximum number of screenshots per item:",
"LabelMinBackdropDownloadWidth": "Minimum backdrop download width:",
"LabelMinScreenshotDownloadWidth": "Minimum screenshot download width:",
- "ButtonAddScheduledTaskTrigger": "Add Task Trigger",
- "HeaderAddScheduledTaskTrigger": "Add Task Trigger",
+ "ButtonAddScheduledTaskTrigger": "Add Trigger",
+ "HeaderAddScheduledTaskTrigger": "Add Trigger",
"ButtonAdd": "Ekle",
"LabelTriggerType": "Trigger Type:",
"OptionDaily": "G\u00fcnl\u00fck",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer Reel",
"OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
"HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
- "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "New Users",
"ButtonSignUp": "Sign up",
"ButtonForgotPassword": "Forgot password?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/vi.json b/MediaBrowser.Server.Implementations/Localization/Server/vi.json
index 93a725d19..1197cda71 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/vi.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/vi.json
@@ -37,10 +37,21 @@
"ButtonOk": "Ok",
"ButtonCancel": "Tho\u00e1t",
"ButtonNew": "M\u1edbi",
+ "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": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "C\u00e0i \u0111\u1eb7t th\u01b0 vi\u1ec7n media c\u1ee7a b\u1ea1n",
"ButtonAddMediaFolder": "Th\u00eam m\u1ed9t th\u01b0 m\u1ee5c media",
"LabelFolderType": "Lo\u1ea1i th\u01b0 m\u1ee5c",
- "MediaFolderHelpPluginRequired": "* Requires the use of a plugin, e.g. GameBrowser or MB Bookshelf.",
"ReferToMediaLibraryWiki": "Tham kh\u1ea3o th\u01b0 vi\u1ec7n wiki media.",
"LabelCountry": "Qu\u1ed1c gia:",
"LabelLanguage": "Ng\u00f4n ng\u1eef",
@@ -52,12 +63,16 @@
"TabPreferences": "\u01afa th\u00edch",
"TabPassword": "M\u1eadt kh\u1ea9u",
"TabLibraryAccess": "Truy c\u1eadp th\u01b0 vi\u1ec7n",
+ "TabAccess": "Access",
"TabImage": "H\u00ecnh \u1ea3nh",
"TabProfile": "H\u1ed3 s\u01a1",
"TabMetadata": "Metadata",
"TabImages": "H\u00ecnh \u1ea3nh",
"TabNotifications": "Notifications",
"TabCollectionTitles": "Ti\u00eau \u0111\u1ec1",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons",
"LabelUnairedMissingEpisodesWithinSeasons": "Display unaired episodes within seasons",
"HeaderVideoPlaybackSettings": "C\u00e1c c\u00e0i \u0111\u1eb7t ph\u00e1t Video",
@@ -365,8 +380,8 @@
"LabelMaxScreenshotsPerItem": "Maximum number of screenshots per item:",
"LabelMinBackdropDownloadWidth": "Minimum backdrop download width:",
"LabelMinScreenshotDownloadWidth": "Minimum screenshot download width:",
- "ButtonAddScheduledTaskTrigger": "Add Task Trigger",
- "HeaderAddScheduledTaskTrigger": "Add Task Trigger",
+ "ButtonAddScheduledTaskTrigger": "Add Trigger",
+ "HeaderAddScheduledTaskTrigger": "Add Trigger",
"ButtonAdd": "Th\u00eam",
"LabelTriggerType": "Trigger Type:",
"OptionDaily": "Daily",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer Reel",
"OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
"HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
- "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "New Users",
"ButtonSignUp": "Sign up",
"ButtonForgotPassword": "Forgot password?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/zh_CN.json b/MediaBrowser.Server.Implementations/Localization/Server/zh_CN.json
index bfc16efb8..29f65fe2a 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/zh_CN.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/zh_CN.json
@@ -1,5 +1,5 @@
{
- "LabelExit": "\u79bb\u5f00",
+ "LabelExit": "\u9000\u51fa",
"LabelVisitCommunity": "\u8bbf\u95ee\u793e\u533a",
"LabelGithub": "Github",
"LabelSwagger": "Swagger",
@@ -7,40 +7,51 @@
"LabelApiDocumentation": "Api Documentation",
"LabelDeveloperResources": "Developer Resources",
"LabelBrowseLibrary": "\u6d4f\u89c8\u5a92\u4f53\u5e93",
- "LabelConfigureMediaBrowser": "\u914d\u7f6eMedia Browser",
+ "LabelConfigureMediaBrowser": "\u914d\u7f6e Media Browser",
"LabelOpenLibraryViewer": "\u6253\u5f00\u5a92\u4f53\u5e93\u6d4f\u89c8\u5668",
"LabelRestartServer": "\u91cd\u542f\u670d\u52a1\u5668",
"LabelShowLogWindow": "\u663e\u793a\u65e5\u5fd7\u7a97\u53e3",
"LabelPrevious": "\u4e0a\u4e00\u4e2a",
- "LabelFinish": "\u7ed3\u675f",
+ "LabelFinish": "\u5b8c\u6210",
"LabelNext": "\u4e0b\u4e00\u4e2a",
"LabelYoureDone": "\u5b8c\u6210\uff01",
- "WelcomeToMediaBrowser": "\u6b22\u8fce\u8fdb\u5165Media Browser\uff01",
+ "WelcomeToMediaBrowser": "\u6b22\u8fce\u4f7f\u7528 Media Browser\uff01",
"TitleMediaBrowser": "Media Browser",
- "ThisWizardWillGuideYou": "\u8be5\u5411\u5bfc\u5c06\u6307\u5bfc\u4f60\u5b8c\u6210\u5b89\u88c5\u8fc7\u7a0b\u3002\u9996\u5148\uff0c\u8bf7\u9009\u62e9\u4f60\u7684\u8bed\u8a00\u3002",
+ "ThisWizardWillGuideYou": "\u8be5\u5411\u5bfc\u5c06\u6307\u5bfc\u4f60\u5b8c\u6210\u5b89\u88c5\u8fc7\u7a0b\u3002\u9996\u5148\uff0c\u8bf7\u9009\u62e9\u4f60\u7684\u9996\u9009\u8bed\u8a00\u3002",
"TellUsAboutYourself": "\u8bf7\u4ecb\u7ecd\u4e00\u4e0b\u4f60\u81ea\u5df1",
"LabelYourFirstName": "\u4f60\u7684\u540d\u5b57\uff1a",
"MoreUsersCanBeAddedLater": "\u7a0d\u540e\u5728\u63a7\u5236\u53f0\u4e2d\u53ef\u4ee5\u6dfb\u52a0\u66f4\u591a\u7528\u6237\u3002",
- "UserProfilesIntro": "Media Browser\u652f\u6301\u591a\u4e2a\u7528\u6237\u8bbe\u5b9a\uff0c\u80fd\u4f7f\u6bcf\u4e2a\u7528\u6237\u90fd\u62e5\u6709\u81ea\u5df1\u4e13\u5c5e\u7684\u663e\u793a\u8bbe\u7f6e\uff0c\u64ad\u653e\u72b6\u6001\u548c\u5bb6\u957f\u63a7\u5236\u8bbe\u7f6e\u3002",
+ "UserProfilesIntro": "Media Browser \u652f\u6301\u591a\u4e2a\u7528\u6237\u8bbe\u5b9a\uff0c\u80fd\u4f7f\u6bcf\u4e2a\u7528\u6237\u90fd\u62e5\u6709\u81ea\u5df1\u4e13\u5c5e\u7684\u663e\u793a\u8bbe\u7f6e\uff0c\u64ad\u653e\u72b6\u6001\u548c\u5bb6\u957f\u63a7\u5236\u8bbe\u7f6e\u3002",
"LabelWindowsService": "Windows \u670d\u52a1",
"AWindowsServiceHasBeenInstalled": "Windows \u670d\u52a1\u5b89\u88c5\u5b8c\u6210",
- "WindowsServiceIntro1": "Media Browser\u670d\u52a1\u5668\u4f5c\u4e3a\u684c\u9762\u5e94\u7528\u7a0b\u5e8f\u901a\u5e38\u4ee5\u4e00\u4e2a\u6258\u76d8\u56fe\u6807\u8fd0\u884c\uff0c\u4f46\u5982\u679c\u4f60\u559c\u6b22\u5b83\u4f5c\u4e3a\u540e\u53f0\u670d\u52a1\u8fd0\u884c\uff0c\u5b83\u53ef\u4ee5\u4eceWindows\u63a7\u5236\u9762\u677f\u542f\u52a8\u3002",
+ "WindowsServiceIntro1": "Media Browser \u670d\u52a1\u5668\u901a\u5e38\u4ee5\u6258\u76d8\u56fe\u6807\u7684\u5f62\u5f0f\u4ee5\u684c\u9762\u5e94\u7528\u7a0b\u5e8f\u8fd0\u884c\uff0c\u4f46\u5982\u679c\u4f60\u559c\u6b22\u5b83\u4f5c\u4e3a\u540e\u53f0\u670d\u52a1\u8fd0\u884c\uff0c\u5b83\u53ef\u4ee5\u4ece Windows \u63a7\u5236\u9762\u677f\u542f\u52a8\u3002",
"WindowsServiceIntro2": "\u5982\u679c\u4f7f\u7528Windows\u670d\u52a1\uff0c\u8bf7\u6ce8\u610f\uff0c\u5b83\u4e0d\u80fd\u540c\u65f6\u4e3a\u6258\u76d8\u56fe\u6807\u8fd0\u884c\uff0c\u6240\u4ee5\u4f60\u9700\u8981\u9000\u51fa\u6258\u76d8\u4ee5\u8fd0\u884c\u670d\u52a1\u3002\u8be5\u670d\u52a1\u8fd8\u5c06\u9700\u8981\u7ba1\u7406\u5458\u6743\u9650\uff0c\u8be5\u6743\u9650\u53ef\u4ee5\u901a\u8fc7\u63a7\u5236\u9762\u677f\u914d\u7f6e\u3002\u8bf7\u6ce8\u610f\uff0c\u6b64\u65f6\u670d\u52a1\u65e0\u6cd5\u81ea\u52a8\u66f4\u65b0\uff0c\u6240\u4ee5\u65b0\u7684\u7248\u672c\u5c06\u9700\u8981\u624b\u52a8\u66f4\u65b0\u3002",
"WizardCompleted": "\u8fd9\u662f\u73b0\u5728\u6211\u4eec\u6240\u8981\u77e5\u9053\u7684\u3002Media Browser\u5df2\u7ecf\u5f00\u59cb\u6574\u5408\u4f60\u5a92\u4f53\u5e93\u4e2d\u7684\u4fe1\u606f\u3002\u4f60\u53ef\u4ee5\u7ee7\u7eed\u67e5\u770b\u6211\u4eec\u7684\u5176\u4ed6\u5e94\u7528\u7a0b\u5e8f\uff0c\u7136\u540e<b>\u5b8c\u6210<\/b>\u6765\u67e5\u770b <b>\u63a7\u5236\u53f0<\/b>.",
"LabelConfigureSettings": "\u914d\u7f6e\u8bbe\u7f6e",
- "LabelEnableVideoImageExtraction": "\u542f\u7528\u89c6\u9891\u56fe\u7247\u63d0\u53d6",
+ "LabelEnableVideoImageExtraction": "\u542f\u7528\u89c6\u9891\u622a\u56fe\u529f\u80fd",
"VideoImageExtractionHelp": "\u5bf9\u4e8e\u8fd8\u6ca1\u6709\u56fe\u7247\uff0c\u4ee5\u53ca\u6211\u4eec\u65e0\u6cd5\u627e\u5230\u7f51\u7edc\u56fe\u7247\u7684\u89c6\u9891\u3002\u8fd9\u4f1a\u989d\u5916\u589e\u52a0\u4e00\u4e9b\u521d\u59cb\u5316\u5a92\u4f53\u5e93\u7684\u626b\u63cf\u65f6\u95f4\uff0c\u4f46\u4f1a\u4f7f\u5a92\u4f53\u4ecb\u7ecd\u754c\u9762\u66f4\u52a0\u8d4f\u5fc3\u60a6\u76ee\u3002",
- "LabelEnableChapterImageExtractionForMovies": "\u63d0\u53d6\u7535\u5f71\u7ae0\u8282\u56fe\u7247",
+ "LabelEnableChapterImageExtractionForMovies": "\u622a\u53d6\u7535\u5f71\u7ae0\u8282\u56fe\u7247",
"LabelChapterImageExtractionForMoviesHelp": "\u4ece\u7ae0\u8282\u4e2d\u63d0\u53d6\u7684\u56fe\u7247\u5c06\u5141\u8bb8\u5ba2\u6237\u7aef\u663e\u793a\u56fe\u5f62\u9009\u62e9\u83dc\u5355\u3002\u8fd9\u4e2a\u8fc7\u7a0b\u53ef\u80fd\u4f1a\u5f88\u6162\uff0c \u66f4\u591a\u7684\u5360\u7528CPU\u8d44\u6e90\uff0c\u5e76\u4e14\u4f1a\u9700\u8981\u51e0\u4e2aGB\u7684\u786c\u76d8\u7a7a\u95f4\u3002\u5b83\u88ab\u9ed8\u8ba4\u8bbe\u7f6e\u4e8e\u6bcf\u665a\u51cc\u66684\u70b9\u8fd0\u884c\uff0c\u867d\u7136\u8fd9\u53ef\u4ee5\u5728\u8ba1\u5212\u4efb\u52a1\u4e2d\u914d\u7f6e\uff0c\u4f46\u6211\u4eec\u4e0d\u5efa\u8bae\u5728\u9ad8\u5cf0\u4f7f\u7528\u65f6\u95f4\u8fd0\u884c\u8be5\u4efb\u52a1\u3002",
"LabelEnableAutomaticPortMapping": "\u542f\u7528\u81ea\u52a8\u7aef\u53e3\u6620\u5c04",
"LabelEnableAutomaticPortMappingHelp": "UPNP\u5141\u8bb8\u81ea\u52a8\u8def\u7531\u5668\u914d\u7f6e\uff0c\u4ece\u800c\u66f4\u65b9\u4fbf\u7684\u8fdb\u884c\u8fdc\u7a0b\u8bbf\u95ee\u3002\u4f46\u8fd9\u53ef\u80fd\u4e0d\u9002\u7528\u4e8e\u67d0\u4e9b\u578b\u53f7\u7684\u8def\u7531\u5668\u3002",
"ButtonOk": "\u786e\u5b9a",
"ButtonCancel": "\u53d6\u6d88",
"ButtonNew": "\u65b0\u589e",
+ "FolderTypeMixed": "Mixed content",
+ "FolderTypeMovies": "\u7535\u5f71",
+ "FolderTypeMusic": "\u97f3\u4e50",
+ "FolderTypeAdultVideos": "\u6210\u4eba\u89c6\u9891",
+ "FolderTypePhotos": "\u56fe\u7247",
+ "FolderTypeMusicVideos": "\u97f3\u4e50\u89c6\u9891",
+ "FolderTypeHomeVideos": "\u5bb6\u5ead\u89c6\u9891",
+ "FolderTypeGames": "\u6e38\u620f",
+ "FolderTypeBooks": "\u4e66\u7c4d",
+ "FolderTypeTvShows": "TV",
+ "FolderTypeInherit": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "\u8bbe\u7f6e\u4f60\u7684\u5a92\u4f53\u5e93",
"ButtonAddMediaFolder": "\u6dfb\u52a0\u5a92\u4f53\u6587\u4ef6\u5939",
"LabelFolderType": "\u6587\u4ef6\u5939\u7c7b\u578b\uff1a",
- "MediaFolderHelpPluginRequired": "* \u9700\u8981\u4f7f\u7528\u4e00\u4e2a\u63d2\u4ef6\uff0c\u4f8b\u5982\uff1aGameBrowser \u6216\u8005 MB Bookshelf\u3002",
"ReferToMediaLibraryWiki": "\u8bf7\u53c2\u9605\u5a92\u4f53\u5e93\u7ef4\u57fa\u3002",
"LabelCountry": "\u56fd\u5bb6\uff1a",
"LabelLanguage": "\u8bed\u8a00\uff1a",
@@ -52,12 +63,16 @@
"TabPreferences": "\u504f\u597d",
"TabPassword": "\u5bc6\u7801",
"TabLibraryAccess": "\u5a92\u4f53\u5e93\u8bbf\u95ee\u6743\u9650",
+ "TabAccess": "Access",
"TabImage": "\u56fe\u7247",
"TabProfile": "\u4e2a\u4eba\u914d\u7f6e",
"TabMetadata": "\u5a92\u4f53\u8d44\u6599",
"TabImages": "\u56fe\u50cf",
"TabNotifications": "\u901a\u77e5",
"TabCollectionTitles": "\u6807\u9898",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "\u663e\u793a\u6bcf\u5b63\u91cc\u7f3a\u5c11\u7684\u5267\u96c6",
"LabelUnairedMissingEpisodesWithinSeasons": "\u663e\u793a\u6bcf\u5b63\u91cc\u672a\u53d1\u5e03\u7684\u5267\u96c6",
"HeaderVideoPlaybackSettings": "\u89c6\u9891\u56de\u653e\u8bbe\u7f6e",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer Reel",
"OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
"HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
- "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "New Users",
"ButtonSignUp": "Sign up",
"ButtonForgotPassword": "Forgot password?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json b/MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json
index 8d87c6897..4800c5491 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json
@@ -37,10 +37,21 @@
"ButtonOk": "OK",
"ButtonCancel": "\u53d6\u6d88",
"ButtonNew": "\u5275\u5efa",
+ "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": "Inherit",
+ "LabelContentType": "Content type:",
"HeaderSetupLibrary": "\u8a2d\u7f6e\u4f60\u7684\u5a92\u9ad4\u5eab",
"ButtonAddMediaFolder": "\u6dfb\u52a0\u5a92\u9ad4\u6587\u4ef6\u593e",
"LabelFolderType": "\u5a92\u9ad4\u6587\u4ef6\u593e\u985e\u578b\uff1a",
- "MediaFolderHelpPluginRequired": "*\u9700\u8981\u4f7f\u7528\u4e00\u500b\u63d2\u4ef6\uff0c\u4f8b\u5982GameBrowser\u6216MB Bookshelf\u3002",
"ReferToMediaLibraryWiki": "\u53c3\u7167\u5a92\u9ad4\u5eab\u7ef4\u57fa",
"LabelCountry": "\u570b\u5bb6\uff1a",
"LabelLanguage": "\u8a9e\u8a00\uff1a",
@@ -52,12 +63,16 @@
"TabPreferences": "\u504f\u597d",
"TabPassword": "\u5bc6\u78bc",
"TabLibraryAccess": "\u5a92\u9ad4\u5eab\u700f\u89bd\u6b0a\u9650",
+ "TabAccess": "Access",
"TabImage": "\u5716\u50cf",
"TabProfile": "\u914d\u7f6e",
"TabMetadata": "\u5a92\u9ad4\u8cc7\u6599",
"TabImages": "\u5716\u50cf",
"TabNotifications": "Notifications",
"TabCollectionTitles": "\u6a19\u984c",
+ "HeaderDeviceAccess": "Device Access",
+ "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
"LabelDisplayMissingEpisodesWithinSeasons": "\u986f\u793a\u7bc0\u76ee\u5b63\u5ea6\u5167\u7f3a\u5c11\u7684\u55ae\u5143",
"LabelUnairedMissingEpisodesWithinSeasons": "\u5728\u7bc0\u76ee\u5b63\u5ea6\u5167\u986f\u793a\u9084\u672a\u767c\u4f48\u7684\u55ae\u5143",
"HeaderVideoPlaybackSettings": "\u8996\u983b\u56de\u653e\u8a2d\u7f6e",
@@ -1246,7 +1261,7 @@
"HeaderTrailerReel": "Trailer Reel",
"OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
"HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
- "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"HeaderNewUsers": "New Users",
"ButtonSignUp": "Sign up",
"ButtonForgotPassword": "Forgot password?",
@@ -1279,5 +1294,9 @@
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
- "TitleSync": "Sync"
+ "TitleSync": "Sync",
+ "OptionAllowSyncContent": "Allow syncing media to devices",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index ed014fff7..f9f482b96 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -51,7 +51,7 @@
</Reference>
<Reference Include="MediaBrowser.Naming, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\MediaBrowser.Naming.1.0.0.18\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
+ <HintPath>..\packages\MediaBrowser.Naming.1.0.0.24\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
</Reference>
<Reference Include="Mono.Nat, Version=1.2.21.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
@@ -183,6 +183,7 @@
<Compile Include="Library\LocalTrailerPostScanTask.cs" />
<Compile Include="Library\MusicManager.cs" />
<Compile Include="Library\PathExtensions.cs" />
+ <Compile Include="Library\Resolvers\SpecialFolderResolver.cs" />
<Compile Include="Library\Resolvers\BaseVideoResolver.cs" />
<Compile Include="Library\Resolvers\PhotoAlbumResolver.cs" />
<Compile Include="Library\Resolvers\PhotoResolver.cs" />
diff --git a/MediaBrowser.Server.Implementations/News/NewsService.cs b/MediaBrowser.Server.Implementations/News/NewsService.cs
index 9eeadfab7..684363d01 100644
--- a/MediaBrowser.Server.Implementations/News/NewsService.cs
+++ b/MediaBrowser.Server.Implementations/News/NewsService.cs
@@ -26,6 +26,14 @@ namespace MediaBrowser.Server.Implementations.News
{
return GetProductNewsInternal(query);
}
+ catch (DirectoryNotFoundException)
+ {
+ // No biggie
+ return new QueryResult<NewsItem>
+ {
+ Items = new NewsItem[] { }
+ };
+ }
catch (FileNotFoundException)
{
// No biggie
diff --git a/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs b/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs
index 3f8b61a45..e74225887 100644
--- a/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs
+++ b/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs
@@ -78,7 +78,7 @@ namespace MediaBrowser.Server.Implementations.Notifications
switch (request.SendToUserMode.Value)
{
case SendToUserType.Admins:
- return _userManager.Users.Where(i => i.Configuration.IsAdministrator)
+ return _userManager.Users.Where(i => i.Policy.IsAdministrator)
.Select(i => i.Id.ToString("N"));
case SendToUserType.All:
return _userManager.Users.Select(i => i.Id.ToString("N"));
diff --git a/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs b/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs
index 3c3d7740a..9f75d522c 100644
--- a/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs
+++ b/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs
@@ -1,5 +1,5 @@
using MediaBrowser.Common.Events;
-using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Serialization;
diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
index 1f294c325..d9ec9b7e4 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
@@ -68,12 +68,6 @@ namespace MediaBrowser.Server.Implementations.Session
private readonly IDeviceManager _deviceManager;
/// <summary>
- /// Gets or sets the configuration manager.
- /// </summary>
- /// <value>The configuration manager.</value>
- private readonly IServerConfigurationManager _configurationManager;
-
- /// <summary>
/// The _active connections
/// </summary>
private readonly ConcurrentDictionary<string, SessionInfo> _activeConnections =
@@ -105,18 +99,9 @@ namespace MediaBrowser.Server.Implementations.Session
private readonly SemaphoreSlim _sessionLock = new SemaphoreSlim(1, 1);
- /// <summary>
- /// Initializes a new instance of the <see cref="SessionManager" /> class.
- /// </summary>
- /// <param name="userDataRepository">The user data repository.</param>
- /// <param name="configurationManager">The configuration manager.</param>
- /// <param name="logger">The logger.</param>
- /// <param name="userRepository">The user repository.</param>
- /// <param name="libraryManager">The library manager.</param>
- public SessionManager(IUserDataManager userDataRepository, IServerConfigurationManager configurationManager, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor, IItemRepository itemRepo, IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IHttpClient httpClient, IAuthenticationRepository authRepo, IDeviceManager deviceManager)
+ public SessionManager(IUserDataManager userDataRepository, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor, IItemRepository itemRepo, IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IHttpClient httpClient, IAuthenticationRepository authRepo, IDeviceManager deviceManager)
{
_userDataRepository = userDataRepository;
- _configurationManager = configurationManager;
_logger = logger;
_userRepository = userRepository;
_libraryManager = libraryManager;
@@ -689,7 +674,7 @@ namespace MediaBrowser.Server.Implementations.Session
if (positionTicks.HasValue)
{
- UpdatePlayState(item, data, positionTicks.Value);
+ _userDataRepository.UpdatePlayState(item, data, positionTicks.Value);
await _userDataRepository.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackProgress, CancellationToken.None).ConfigureAwait(false);
}
@@ -779,7 +764,7 @@ namespace MediaBrowser.Server.Implementations.Session
if (positionTicks.HasValue)
{
- playedToCompletion = UpdatePlayState(item, data, positionTicks.Value);
+ playedToCompletion = _userDataRepository.UpdatePlayState(item, data, positionTicks.Value);
}
else
{
@@ -796,65 +781,6 @@ namespace MediaBrowser.Server.Implementations.Session
}
/// <summary>
- /// Updates playstate position for an item but does not save
- /// </summary>
- /// <param name="item">The item</param>
- /// <param name="data">User data for the item</param>
- /// <param name="positionTicks">The current playback position</param>
- private bool UpdatePlayState(BaseItem item, UserItemData data, long positionTicks)
- {
- var playedToCompletion = false;
-
- var hasRuntime = item.RunTimeTicks.HasValue && item.RunTimeTicks > 0;
-
- // If a position has been reported, and if we know the duration
- if (positionTicks > 0 && hasRuntime)
- {
- var pctIn = Decimal.Divide(positionTicks, item.RunTimeTicks.Value) * 100;
-
- // Don't track in very beginning
- if (pctIn < _configurationManager.Configuration.MinResumePct)
- {
- positionTicks = 0;
- }
-
- // If we're at the end, assume completed
- else if (pctIn > _configurationManager.Configuration.MaxResumePct || positionTicks >= item.RunTimeTicks.Value)
- {
- positionTicks = 0;
- data.Played = playedToCompletion = true;
- }
-
- else
- {
- // Enforce MinResumeDuration
- var durationSeconds = TimeSpan.FromTicks(item.RunTimeTicks.Value).TotalSeconds;
-
- if (durationSeconds < _configurationManager.Configuration.MinResumeDurationSeconds)
- {
- positionTicks = 0;
- data.Played = playedToCompletion = true;
- }
- }
- }
- else if (!hasRuntime)
- {
- // If we don't know the runtime we'll just have to assume it was fully played
- data.Played = playedToCompletion = true;
- positionTicks = 0;
- }
-
- if (item is Audio)
- {
- positionTicks = 0;
- }
-
- data.PlaybackPositionTicks = positionTicks;
-
- return playedToCompletion;
- }
-
- /// <summary>
/// Gets the session.
/// </summary>
/// <param name="sessionId">The session identifier.</param>
@@ -1265,6 +1191,14 @@ namespace MediaBrowser.Server.Implementations.Session
var user = _userManager.Users
.FirstOrDefault(i => string.Equals(request.Username, i.Name, StringComparison.OrdinalIgnoreCase));
+ if (user != null && !string.IsNullOrWhiteSpace(request.DeviceId))
+ {
+ if (!_deviceManager.CanAccessDevice(user.Id.ToString("N"), request.DeviceId))
+ {
+ throw new UnauthorizedAccessException("User is not allowed access from this device.");
+ }
+ }
+
var result = await _userManager.AuthenticateUser(request.Username, request.PasswordSha1, request.PasswordMd5, request.RemoteEndPoint).ConfigureAwait(false);
if (!result)
diff --git a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs
index ed590a1f2..36a7fcbd8 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs
@@ -1,4 +1,5 @@
using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
diff --git a/MediaBrowser.Server.Implementations/Session/WebSocketController.cs b/MediaBrowser.Server.Implementations/Session/WebSocketController.cs
index 0756aa1ec..7d1057397 100644
--- a/MediaBrowser.Server.Implementations/Session/WebSocketController.cs
+++ b/MediaBrowser.Server.Implementations/Session/WebSocketController.cs
@@ -1,4 +1,4 @@
-using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
@@ -73,17 +73,6 @@ namespace MediaBrowser.Server.Implementations.Session
_logger.ErrorException("Error reporting session ended.", ex);
}
}
- else
- {
- var capabilities = new ClientCapabilities
- {
- PlayableMediaTypes = Session.PlayableMediaTypes,
- SupportedCommands = Session.SupportedCommands,
- SupportsMediaControl = SupportsMediaControl
- };
-
- _sessionManager.ReportCapabilities(Session.Id, capabilities);
- }
}
private IWebSocketConnection GetActiveSocket()
diff --git a/MediaBrowser.Server.Implementations/Sync/AppSyncProvider.cs b/MediaBrowser.Server.Implementations/Sync/AppSyncProvider.cs
index 94eed50f6..deef503ea 100644
--- a/MediaBrowser.Server.Implementations/Sync/AppSyncProvider.cs
+++ b/MediaBrowser.Server.Implementations/Sync/AppSyncProvider.cs
@@ -8,7 +8,7 @@ using System.Linq;
namespace MediaBrowser.Server.Implementations.Sync
{
- public class AppSyncProvider : ISyncProvider
+ public class AppSyncProvider : ISyncProvider, IHasUniqueTargetIds
{
private readonly IDeviceManager _deviceManager;
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
index 6dda869ee..6f3e926c0 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
@@ -2,10 +2,13 @@
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Sync;
+using MediaBrowser.Controller.TV;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
+using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Session;
using MediaBrowser.Model.Sync;
using MoreLinq;
@@ -24,19 +27,16 @@ namespace MediaBrowser.Server.Implementations.Sync
private readonly ISyncManager _syncManager;
private readonly ILogger _logger;
private readonly IUserManager _userManager;
+ private readonly ITVSeriesManager _tvSeriesManager;
- public SyncJobProcessor(ILibraryManager libraryManager, ISyncRepository syncRepo, ISyncManager syncManager, ILogger logger, IUserManager userManager)
+ public SyncJobProcessor(ILibraryManager libraryManager, ISyncRepository syncRepo, ISyncManager syncManager, ILogger logger, IUserManager userManager, ITVSeriesManager tvSeriesManager)
{
_libraryManager = libraryManager;
_syncRepo = syncRepo;
_syncManager = syncManager;
_logger = logger;
_userManager = userManager;
- }
-
- public void ProcessJobItem(SyncJob job, SyncJobItem jobItem, SyncTarget target)
- {
-
+ _tvSeriesManager = tvSeriesManager;
}
public async Task EnsureJobItems(SyncJob job)
@@ -48,7 +48,7 @@ namespace MediaBrowser.Server.Implementations.Sync
throw new InvalidOperationException("Cannot proceed with sync because user no longer exists.");
}
- var items = GetItemsForSync(job.RequestedItemIds, user, job.UnwatchedOnly)
+ var items = (await GetItemsForSync(job.Category, job.ParentId, job.RequestedItemIds, user, job.UnwatchedOnly).ConfigureAwait(false))
.ToList();
var jobItems = _syncRepo.GetJobItems(new SyncJobItemQuery
@@ -128,7 +128,7 @@ namespace MediaBrowser.Server.Implementations.Sync
foreach (var item in jobItems)
{
- if (item.Status == SyncJobItemStatus.Failed || item.Status == SyncJobItemStatus.Completed)
+ if (item.Status == SyncJobItemStatus.Failed || item.Status == SyncJobItemStatus.Synced || item.Status == SyncJobItemStatus.RemovedFromDevice)
{
pct += 100;
}
@@ -171,10 +171,11 @@ namespace MediaBrowser.Server.Implementations.Sync
return _syncRepo.Update(job);
}
- public IEnumerable<BaseItem> GetItemsForSync(IEnumerable<string> itemIds, User user, bool unwatchedOnly)
+ public async Task<IEnumerable<BaseItem>> GetItemsForSync(SyncCategory? category, string parentId, IEnumerable<string> itemIds, User user, bool unwatchedOnly)
{
- var items = itemIds
- .SelectMany(i => GetItemsForSync(i, user))
+ var items = category.HasValue ?
+ await GetItemsForSync(category.Value, parentId, user).ConfigureAwait(false) :
+ itemIds.SelectMany(i => GetItemsForSync(i, user))
.Where(_syncManager.SupportsSync);
if (unwatchedOnly)
@@ -198,6 +199,54 @@ namespace MediaBrowser.Server.Implementations.Sync
return items.DistinctBy(i => i.Id);
}
+ private async Task<IEnumerable<BaseItem>> GetItemsForSync(SyncCategory category, string parentId, User user)
+ {
+ var parent = string.IsNullOrWhiteSpace(parentId)
+ ? user.RootFolder
+ : (Folder)_libraryManager.GetItemById(parentId);
+
+ InternalItemsQuery query;
+
+ switch (category)
+ {
+ case SyncCategory.Latest:
+ query = new InternalItemsQuery
+ {
+ IsFolder = false,
+ SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName },
+ SortOrder = SortOrder.Descending,
+ Recursive = true
+ };
+ break;
+ case SyncCategory.Resume:
+ query = new InternalItemsQuery
+ {
+ IsFolder = false,
+ SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName },
+ SortOrder = SortOrder.Descending,
+ Recursive = true,
+ IsResumable = true,
+ MediaTypes = new[] { MediaType.Video }
+ };
+ break;
+
+ case SyncCategory.NextUp:
+ return _tvSeriesManager.GetNextUp(new NextUpQuery
+ {
+ ParentId = parentId,
+ UserId = user.Id.ToString("N")
+ }).Items;
+
+ default:
+ throw new ArgumentException("Unrecognized category: " + category);
+ }
+
+ query.User = user;
+
+ var result = await parent.GetItems(query).ConfigureAwait(false);
+ return result.Items;
+ }
+
private IEnumerable<BaseItem> GetItemsForSync(string id, User user)
{
var item = _libraryManager.GetItemById(id);
@@ -263,7 +312,7 @@ namespace MediaBrowser.Server.Implementations.Sync
var result = _syncRepo.GetJobItems(new SyncJobItemQuery
{
- IsCompleted = false
+ Status = SyncJobItemStatus.Queued
});
var jobItems = result.Items;
@@ -316,35 +365,26 @@ namespace MediaBrowser.Server.Implementations.Sync
var video = item as Video;
if (video != null)
{
- jobItem.OutputPath = await Sync(jobItem, video, deviceProfile, cancellationToken).ConfigureAwait(false);
+ await Sync(jobItem, video, deviceProfile, cancellationToken).ConfigureAwait(false);
}
else if (item is Audio)
{
- jobItem.OutputPath = await Sync(jobItem, (Audio)item, deviceProfile, cancellationToken).ConfigureAwait(false);
+ await Sync(jobItem, (Audio)item, deviceProfile, cancellationToken).ConfigureAwait(false);
}
else if (item is Photo)
{
- jobItem.OutputPath = await Sync(jobItem, (Photo)item, deviceProfile, cancellationToken).ConfigureAwait(false);
- }
-
- else if (item is Game)
- {
- jobItem.OutputPath = await Sync(jobItem, (Game)item, deviceProfile, cancellationToken).ConfigureAwait(false);
+ await Sync(jobItem, (Photo)item, deviceProfile, cancellationToken).ConfigureAwait(false);
}
- else if (item is Book)
+ else
{
- jobItem.OutputPath = await Sync(jobItem, (Book)item, deviceProfile, cancellationToken).ConfigureAwait(false);
+ await SyncGeneric(jobItem, item, deviceProfile, cancellationToken).ConfigureAwait(false);
}
-
- jobItem.Progress = 50;
- jobItem.Status = SyncJobItemStatus.Transferring;
- await _syncRepo.Update(jobItem).ConfigureAwait(false);
}
- private async Task<string> Sync(SyncJobItem jobItem, Video item, DeviceProfile profile, CancellationToken cancellationToken)
+ private async Task Sync(SyncJobItem jobItem, Video item, DeviceProfile profile, CancellationToken cancellationToken)
{
var options = new VideoOptions
{
@@ -358,24 +398,34 @@ namespace MediaBrowser.Server.Implementations.Sync
var streamInfo = new StreamBuilder().BuildVideoItem(options);
var mediaSource = streamInfo.MediaSource;
- if (streamInfo.PlayMethod != PlayMethod.Transcode)
+ jobItem.MediaSourceId = streamInfo.MediaSourceId;
+
+ if (streamInfo.PlayMethod == PlayMethod.Transcode)
+ {
+ await _syncRepo.Update(jobItem).ConfigureAwait(false);
+ }
+ else
{
if (mediaSource.Protocol == MediaProtocol.File)
{
- return mediaSource.Path;
+ jobItem.OutputPath = mediaSource.Path;
}
if (mediaSource.Protocol == MediaProtocol.Http)
{
- return await DownloadFile(jobItem, mediaSource, cancellationToken).ConfigureAwait(false);
+ jobItem.OutputPath = await DownloadFile(jobItem, mediaSource, cancellationToken).ConfigureAwait(false);
}
throw new InvalidOperationException(string.Format("Cannot direct stream {0} protocol", mediaSource.Protocol));
}
// TODO: Transcode
- return mediaSource.Path;
+ jobItem.OutputPath = mediaSource.Path;
+
+ jobItem.Progress = 50;
+ jobItem.Status = SyncJobItemStatus.Transferring;
+ await _syncRepo.Update(jobItem).ConfigureAwait(false);
}
- private async Task<string> Sync(SyncJobItem jobItem, Audio item, DeviceProfile profile, CancellationToken cancellationToken)
+ private async Task Sync(SyncJobItem jobItem, Audio item, DeviceProfile profile, CancellationToken cancellationToken)
{
var options = new AudioOptions
{
@@ -389,36 +439,49 @@ namespace MediaBrowser.Server.Implementations.Sync
var streamInfo = new StreamBuilder().BuildAudioItem(options);
var mediaSource = streamInfo.MediaSource;
- if (streamInfo.PlayMethod != PlayMethod.Transcode)
+ jobItem.MediaSourceId = streamInfo.MediaSourceId;
+
+ if (streamInfo.PlayMethod == PlayMethod.Transcode)
+ {
+ await _syncRepo.Update(jobItem).ConfigureAwait(false);
+ }
+ else
{
if (mediaSource.Protocol == MediaProtocol.File)
{
- return mediaSource.Path;
+ jobItem.OutputPath = mediaSource.Path;
}
if (mediaSource.Protocol == MediaProtocol.Http)
{
- return await DownloadFile(jobItem, mediaSource, cancellationToken).ConfigureAwait(false);
+ jobItem.OutputPath = await DownloadFile(jobItem, mediaSource, cancellationToken).ConfigureAwait(false);
}
throw new InvalidOperationException(string.Format("Cannot direct stream {0} protocol", mediaSource.Protocol));
}
// TODO: Transcode
- return mediaSource.Path;
- }
+ jobItem.OutputPath = mediaSource.Path;
- private async Task<string> Sync(SyncJobItem jobItem, Photo item, DeviceProfile profile, CancellationToken cancellationToken)
- {
- return item.Path;
+ jobItem.Progress = 50;
+ jobItem.Status = SyncJobItemStatus.Transferring;
+ await _syncRepo.Update(jobItem).ConfigureAwait(false);
}
- private async Task<string> Sync(SyncJobItem jobItem, Game item, DeviceProfile profile, CancellationToken cancellationToken)
+ private async Task Sync(SyncJobItem jobItem, Photo item, DeviceProfile profile, CancellationToken cancellationToken)
{
- return item.Path;
+ jobItem.OutputPath = item.Path;
+
+ jobItem.Progress = 50;
+ jobItem.Status = SyncJobItemStatus.Transferring;
+ await _syncRepo.Update(jobItem).ConfigureAwait(false);
}
- private async Task<string> Sync(SyncJobItem jobItem, Book item, DeviceProfile profile, CancellationToken cancellationToken)
+ private async Task SyncGeneric(SyncJobItem jobItem, BaseItem item, DeviceProfile profile, CancellationToken cancellationToken)
{
- return item.Path;
+ jobItem.OutputPath = item.Path;
+
+ jobItem.Progress = 50;
+ jobItem.Status = SyncJobItemStatus.Transferring;
+ await _syncRepo.Update(jobItem).ConfigureAwait(false);
}
private async Task<string> DownloadFile(SyncJobItem jobItem, MediaSourceInfo mediaSource, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs
index 664ec4038..9cb697c81 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs
@@ -1,18 +1,26 @@
-using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common;
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Drawing;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Sync;
+using MediaBrowser.Controller.TV;
using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Sync;
+using MediaBrowser.Model.Users;
using MoreLinq;
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Threading.Tasks;
@@ -25,16 +33,22 @@ namespace MediaBrowser.Server.Implementations.Sync
private readonly IImageProcessor _imageProcessor;
private readonly ILogger _logger;
private readonly IUserManager _userManager;
+ private readonly Func<IDtoService> _dtoService;
+ private readonly IApplicationHost _appHost;
+ private readonly ITVSeriesManager _tvSeriesManager;
private ISyncProvider[] _providers = { };
- public SyncManager(ILibraryManager libraryManager, ISyncRepository repo, IImageProcessor imageProcessor, ILogger logger, IUserManager userManager)
+ public SyncManager(ILibraryManager libraryManager, ISyncRepository repo, IImageProcessor imageProcessor, ILogger logger, IUserManager userManager, Func<IDtoService> dtoService, IApplicationHost appHost, ITVSeriesManager tvSeriesManager)
{
_libraryManager = libraryManager;
_repo = repo;
_imageProcessor = imageProcessor;
_logger = logger;
_userManager = userManager;
+ _dtoService = dtoService;
+ _appHost = appHost;
+ _tvSeriesManager = tvSeriesManager;
}
public void AddParts(IEnumerable<ISyncProvider> providers)
@@ -44,12 +58,12 @@ namespace MediaBrowser.Server.Implementations.Sync
public async Task<SyncJobCreationResult> CreateJob(SyncJobRequest request)
{
- var processor = new SyncJobProcessor(_libraryManager, _repo, this, _logger, _userManager);
+ var processor = new SyncJobProcessor(_libraryManager, _repo, this, _logger, _userManager, _tvSeriesManager);
var user = _userManager.GetUserById(request.UserId);
- var items = processor
- .GetItemsForSync(request.ItemIds, user, request.UnwatchedOnly)
+ var items = (await processor
+ .GetItemsForSync(request.Category, request.ParentId, request.ItemIds, user, request.UnwatchedOnly).ConfigureAwait(false))
.ToList();
if (items.Any(i => !SupportsSync(i)))
@@ -57,9 +71,16 @@ namespace MediaBrowser.Server.Implementations.Sync
throw new ArgumentException("Item does not support sync.");
}
- if (string.IsNullOrWhiteSpace(request.Name) && request.ItemIds.Count == 1)
+ if (string.IsNullOrWhiteSpace(request.Name))
{
- request.Name = GetDefaultName(_libraryManager.GetItemById(request.ItemIds[0]));
+ if (request.Category.HasValue)
+ {
+ request.Name = request.Category.Value.ToString();
+ }
+ else if (request.ItemIds.Count == 1)
+ {
+ request.Name = GetDefaultName(_libraryManager.GetItemById(request.ItemIds[0]));
+ }
}
if (string.IsNullOrWhiteSpace(request.Name))
@@ -68,7 +89,12 @@ namespace MediaBrowser.Server.Implementations.Sync
}
var target = GetSyncTargets(request.UserId)
- .First(i => string.Equals(request.TargetId, i.Id));
+ .FirstOrDefault(i => string.Equals(request.TargetId, i.Id));
+
+ if (target == null)
+ {
+ throw new ArgumentException("Sync target not found.");
+ }
var jobId = Guid.NewGuid().ToString("N");
@@ -80,7 +106,7 @@ namespace MediaBrowser.Server.Implementations.Sync
UserId = request.UserId,
UnwatchedOnly = request.UnwatchedOnly,
ItemLimit = request.ItemLimit,
- RequestedItemIds = request.ItemIds,
+ RequestedItemIds = request.ItemIds ?? new List<string> { },
DateCreated = DateTime.UtcNow,
DateLastModified = DateTime.UtcNow,
SyncNewContent = request.SyncNewContent,
@@ -172,17 +198,23 @@ namespace MediaBrowser.Server.Implementations.Sync
private IEnumerable<SyncTarget> GetSyncTargets(ISyncProvider provider, string userId)
{
- var providerId = GetSyncProviderId(provider);
-
return provider.GetSyncTargets().Select(i => new SyncTarget
{
Name = i.Name,
- Id = GetSyncTargetId(providerId, i)
+ Id = GetSyncTargetId(provider, i)
});
}
- private string GetSyncTargetId(string providerId, SyncTarget target)
+ private string GetSyncTargetId(ISyncProvider provider, SyncTarget target)
{
+ var hasUniqueId = provider as IHasUniqueTargetIds;
+
+ if (hasUniqueId != null)
+ {
+ return target.Id;
+ }
+
+ var providerId = GetSyncProviderId(provider);
return (providerId + "-" + target.Id).GetMD5().ToString("N");
}
@@ -239,10 +271,21 @@ namespace MediaBrowser.Server.Implementations.Sync
}
}
+ if (item is LiveTvChannel || item is IChannelItem || item is ILiveTvRecording)
+ {
+ return false;
+ }
+
+ // It would be nice to support these later
+ if (item is Game || item is Book)
+ {
+ return false;
+ }
+
return true;
}
- return item.LocationType == LocationType.FileSystem || item is Season;
+ return item.LocationType == LocationType.FileSystem || item is Season || item is ILiveTvRecording;
}
private string GetDefaultName(BaseItem item)
@@ -270,12 +313,12 @@ namespace MediaBrowser.Server.Implementations.Sync
{
var jobItem = _repo.GetJobItem(id);
- jobItem.Status = SyncJobItemStatus.Completed;
+ jobItem.Status = SyncJobItemStatus.Synced;
jobItem.Progress = 100;
await _repo.Update(jobItem).ConfigureAwait(false);
- var processor = new SyncJobProcessor(_libraryManager, _repo, this, _logger, _userManager);
+ var processor = new SyncJobProcessor(_libraryManager, _repo, this, _logger, _userManager, _tvSeriesManager);
await processor.UpdateJobStatus(jobItem.JobId).ConfigureAwait(false);
}
@@ -289,5 +332,93 @@ namespace MediaBrowser.Server.Implementations.Sync
{
return _repo.GetJobItems(query);
}
+
+ private SyncedItem GetJobItemInfo(SyncJobItem jobItem)
+ {
+ var job = _repo.GetJob(jobItem.JobId);
+
+ var libraryItem = _libraryManager.GetItemById(jobItem.ItemId);
+
+ var syncedItem = new SyncedItem
+ {
+ SyncJobId = jobItem.JobId,
+ SyncJobItemId = jobItem.Id,
+ ServerId = _appHost.SystemId,
+ UserId = job.UserId
+ };
+
+ var dtoOptions = new DtoOptions();
+
+ // Remove some bloat
+ dtoOptions.Fields.Remove(ItemFields.MediaStreams);
+ dtoOptions.Fields.Remove(ItemFields.IndexOptions);
+ dtoOptions.Fields.Remove(ItemFields.MediaSourceCount);
+ dtoOptions.Fields.Remove(ItemFields.OriginalPrimaryImageAspectRatio);
+ dtoOptions.Fields.Remove(ItemFields.Path);
+ dtoOptions.Fields.Remove(ItemFields.SeriesGenres);
+ dtoOptions.Fields.Remove(ItemFields.Settings);
+ dtoOptions.Fields.Remove(ItemFields.SyncInfo);
+
+ syncedItem.Item = _dtoService().GetBaseItemDto(libraryItem, dtoOptions);
+
+ // TODO: this should be the media source of the transcoded output
+ syncedItem.Item.MediaSources = syncedItem.Item.MediaSources
+ .Where(i => string.Equals(i.Id, jobItem.MediaSourceId))
+ .ToList();
+
+ var mediaSource = syncedItem.Item.MediaSources
+ .FirstOrDefault(i => string.Equals(i.Id, jobItem.MediaSourceId));
+
+ // This will be null for items that are not audio/video
+ if (mediaSource == null)
+ {
+ syncedItem.OriginalFileName = Path.GetFileName(libraryItem.Path);
+ }
+ else
+ {
+ syncedItem.OriginalFileName = Path.GetFileName(mediaSource.Path);
+ }
+
+ return syncedItem;
+ }
+
+ public Task ReportOfflineAction(UserAction action)
+ {
+ return Task.FromResult(true);
+ }
+
+ public List<SyncedItem> GetReadySyncItems(string targetId)
+ {
+ var jobItemResult = GetJobItems(new SyncJobItemQuery
+ {
+ TargetId = targetId,
+ Status = SyncJobItemStatus.Transferring
+ });
+
+ return jobItemResult.Items.Select(GetJobItemInfo)
+ .ToList();
+ }
+
+ public async Task<SyncDataResponse> SyncData(SyncDataRequest request)
+ {
+ var jobItemResult = GetJobItems(new SyncJobItemQuery
+ {
+ TargetId = request.TargetId,
+ Status = SyncJobItemStatus.Synced
+ });
+
+ foreach (var jobItem in jobItemResult.Items)
+ {
+ if (!request.LocalItemIds.Contains(jobItem.ItemId, StringComparer.OrdinalIgnoreCase))
+ {
+ jobItem.Status = SyncJobItemStatus.RemovedFromDevice;
+ await _repo.Update(jobItem).ConfigureAwait(false);
+ }
+ }
+
+ var response = new SyncDataResponse();
+
+ return response;
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs b/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs
index 7825b9e9a..a10e9a7e6 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs
@@ -24,6 +24,7 @@ namespace MediaBrowser.Server.Implementations.Sync
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private IDbCommand _deleteJobCommand;
+ private IDbCommand _deleteJobItemsCommand;
private IDbCommand _saveJobCommand;
private IDbCommand _saveJobItemCommand;
@@ -35,7 +36,7 @@ namespace MediaBrowser.Server.Implementations.Sync
public async Task Initialize()
{
- var dbFile = Path.Combine(_appPaths.DataPath, "sync6.db");
+ var dbFile = Path.Combine(_appPaths.DataPath, "sync9.db");
_connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false);
@@ -44,7 +45,7 @@ namespace MediaBrowser.Server.Implementations.Sync
"create table if not exists SyncJobs (Id GUID PRIMARY KEY, TargetId TEXT NOT NULL, Name TEXT NOT NULL, Quality TEXT NOT NULL, Status TEXT NOT NULL, Progress FLOAT, UserId TEXT NOT NULL, ItemIds TEXT NOT NULL, Category TEXT, ParentId TEXT, UnwatchedOnly BIT, ItemLimit INT, SyncNewContent BIT, DateCreated DateTime, DateLastModified DateTime, ItemCount int)",
"create index if not exists idx_SyncJobs on SyncJobs(Id)",
- "create table if not exists SyncJobItems (Id GUID PRIMARY KEY, ItemId TEXT, JobId TEXT, OutputPath TEXT, Status TEXT, TargetId TEXT, DateCreated DateTime, Progress FLOAT)",
+ "create table if not exists SyncJobItems (Id GUID PRIMARY KEY, ItemId TEXT, MediaSourceId TEXT, JobId TEXT, OutputPath TEXT, Status TEXT, TargetId TEXT, DateCreated DateTime, Progress FLOAT)",
"create index if not exists idx_SyncJobItems on SyncJobs(Id)",
//pragmas
@@ -61,9 +62,13 @@ namespace MediaBrowser.Server.Implementations.Sync
private void PrepareStatements()
{
_deleteJobCommand = _connection.CreateCommand();
- _deleteJobCommand.CommandText = "delete from SyncJobs where Id=@Id; delete from SyncJobItems where JobId=@Id";
+ _deleteJobCommand.CommandText = "delete from SyncJobs where Id=@Id";
_deleteJobCommand.Parameters.Add(_deleteJobCommand, "@Id");
+ _deleteJobItemsCommand = _connection.CreateCommand();
+ _deleteJobItemsCommand.CommandText = "delete from SyncJobItems where JobId=@JobId";
+ _deleteJobItemsCommand.Parameters.Add(_deleteJobItemsCommand, "@JobId");
+
_saveJobCommand = _connection.CreateCommand();
_saveJobCommand.CommandText = "replace into SyncJobs (Id, TargetId, Name, Quality, Status, Progress, UserId, ItemIds, Category, ParentId, UnwatchedOnly, ItemLimit, SyncNewContent, DateCreated, DateLastModified, ItemCount) values (@Id, @TargetId, @Name, @Quality, @Status, @Progress, @UserId, @ItemIds, @Category, @ParentId, @UnwatchedOnly, @ItemLimit, @SyncNewContent, @DateCreated, @DateLastModified, @ItemCount)";
@@ -85,10 +90,11 @@ namespace MediaBrowser.Server.Implementations.Sync
_saveJobCommand.Parameters.Add(_saveJobCommand, "@ItemCount");
_saveJobItemCommand = _connection.CreateCommand();
- _saveJobItemCommand.CommandText = "replace into SyncJobItems (Id, ItemId, JobId, OutputPath, Status, TargetId, DateCreated, Progress) values (@Id, @ItemId, @JobId, @OutputPath, @Status, @TargetId, @DateCreated, @Progress)";
+ _saveJobItemCommand.CommandText = "replace into SyncJobItems (Id, ItemId, MediaSourceId, JobId, OutputPath, Status, TargetId, DateCreated, Progress) values (@Id, @ItemId, @MediaSourceId, @JobId, @OutputPath, @Status, @TargetId, @DateCreated, @Progress)";
_saveJobItemCommand.Parameters.Add(_saveJobCommand, "@Id");
_saveJobItemCommand.Parameters.Add(_saveJobCommand, "@ItemId");
+ _saveJobItemCommand.Parameters.Add(_saveJobCommand, "@MediaSourceId");
_saveJobItemCommand.Parameters.Add(_saveJobCommand, "@JobId");
_saveJobItemCommand.Parameters.Add(_saveJobCommand, "@OutputPath");
_saveJobItemCommand.Parameters.Add(_saveJobCommand, "@Status");
@@ -98,7 +104,7 @@ namespace MediaBrowser.Server.Implementations.Sync
}
private const string BaseJobSelectText = "select Id, TargetId, Name, Quality, Status, Progress, UserId, ItemIds, Category, ParentId, UnwatchedOnly, ItemLimit, SyncNewContent, DateCreated, DateLastModified, ItemCount from SyncJobs";
- private const string BaseJobItemSelectText = "select Id, ItemId, JobId, OutputPath, Status, TargetId, DateCreated, Progress from SyncJobItems";
+ private const string BaseJobItemSelectText = "select Id, ItemId, MediaSourceId, JobId, OutputPath, Status, TargetId, DateCreated, Progress from SyncJobItems";
public SyncJob GetJob(string id)
{
@@ -113,7 +119,7 @@ namespace MediaBrowser.Server.Implementations.Sync
{
throw new ArgumentNullException("id");
}
-
+
using (var cmd = _connection.CreateCommand())
{
cmd.CommandText = BaseJobSelectText + " where Id=@Id";
@@ -163,7 +169,7 @@ namespace MediaBrowser.Server.Implementations.Sync
if (!reader.IsDBNull(7))
{
- info.RequestedItemIds = reader.GetString(7).Split(',').ToList();
+ info.RequestedItemIds = reader.GetString(7).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
}
if (!reader.IsDBNull(8))
@@ -221,7 +227,7 @@ namespace MediaBrowser.Server.Implementations.Sync
_saveJobCommand.GetParameter(index++).Value = job.TargetId;
_saveJobCommand.GetParameter(index++).Value = job.Name;
_saveJobCommand.GetParameter(index++).Value = job.Quality;
- _saveJobCommand.GetParameter(index++).Value = job.Status;
+ _saveJobCommand.GetParameter(index++).Value = job.Status.ToString();
_saveJobCommand.GetParameter(index++).Value = job.Progress;
_saveJobCommand.GetParameter(index++).Value = job.UserId;
_saveJobCommand.GetParameter(index++).Value = string.Join(",", job.RequestedItemIds.ToArray());
@@ -289,11 +295,14 @@ namespace MediaBrowser.Server.Implementations.Sync
var index = 0;
_deleteJobCommand.GetParameter(index++).Value = new Guid(id);
-
_deleteJobCommand.Transaction = transaction;
-
_deleteJobCommand.ExecuteNonQuery();
+ index = 0;
+ _deleteJobItemsCommand.GetParameter(index++).Value = id;
+ _deleteJobItemsCommand.Transaction = transaction;
+ _deleteJobItemsCommand.ExecuteNonQuery();
+
transaction.Commit();
}
catch (OperationCanceledException)
@@ -457,25 +466,13 @@ namespace MediaBrowser.Server.Implementations.Sync
whereClauses.Add("TargetId=@TargetId");
cmd.Parameters.Add(cmd, "@TargetId", DbType.String).Value = query.TargetId;
}
+
if (query.Status.HasValue)
{
whereClauses.Add("Status=@Status");
cmd.Parameters.Add(cmd, "@Status", DbType.String).Value = query.Status.Value.ToString();
}
- if (query.IsCompleted.HasValue)
- {
- if (query.IsCompleted.Value)
- {
- whereClauses.Add("Status=@Status");
- }
- else
- {
- whereClauses.Add("Status<>@Status");
- }
- cmd.Parameters.Add(cmd, "@Status", DbType.String).Value = SyncJobStatus.Completed.ToString();
- }
-
var whereTextWithoutPaging = whereClauses.Count == 0 ?
string.Empty :
" where " + string.Join(" AND ", whereClauses.ToArray());
@@ -549,9 +546,10 @@ namespace MediaBrowser.Server.Implementations.Sync
_saveJobItemCommand.GetParameter(index++).Value = new Guid(jobItem.Id);
_saveJobItemCommand.GetParameter(index++).Value = jobItem.ItemId;
+ _saveJobItemCommand.GetParameter(index++).Value = jobItem.MediaSourceId;
_saveJobItemCommand.GetParameter(index++).Value = jobItem.JobId;
_saveJobItemCommand.GetParameter(index++).Value = jobItem.OutputPath;
- _saveJobItemCommand.GetParameter(index++).Value = jobItem.Status;
+ _saveJobItemCommand.GetParameter(index++).Value = jobItem.Status.ToString();
_saveJobItemCommand.GetParameter(index++).Value = jobItem.TargetId;
_saveJobItemCommand.GetParameter(index++).Value = jobItem.DateCreated;
_saveJobItemCommand.GetParameter(index++).Value = jobItem.Progress;
@@ -598,29 +596,35 @@ namespace MediaBrowser.Server.Implementations.Sync
var info = new SyncJobItem
{
Id = reader.GetGuid(0).ToString("N"),
- ItemId = reader.GetString(1),
- JobId = reader.GetString(2)
+ ItemId = reader.GetString(1)
};
- if (!reader.IsDBNull(3))
+ if (!reader.IsDBNull(2))
{
- info.OutputPath = reader.GetString(3);
+ info.MediaSourceId = reader.GetString(2);
}
+ info.JobId = reader.GetString(3);
+
if (!reader.IsDBNull(4))
{
- info.Status = (SyncJobItemStatus)Enum.Parse(typeof(SyncJobItemStatus), reader.GetString(4), true);
+ info.OutputPath = reader.GetString(4);
}
- info.TargetId = reader.GetString(5);
+ if (!reader.IsDBNull(5))
+ {
+ info.Status = (SyncJobItemStatus)Enum.Parse(typeof(SyncJobItemStatus), reader.GetString(5), true);
+ }
- info.DateCreated = reader.GetDateTime(6);
+ info.TargetId = reader.GetString(6);
- if (!reader.IsDBNull(7))
+ info.DateCreated = reader.GetDateTime(7);
+
+ if (!reader.IsDBNull(8))
{
- info.Progress = reader.GetDouble(7);
+ info.Progress = reader.GetDouble(8);
}
-
+
return info;
}
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs b/MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs
index df03ab6f7..e7e30b857 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs
@@ -1,6 +1,7 @@
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Sync;
+using MediaBrowser.Controller.TV;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
@@ -16,19 +17,21 @@ namespace MediaBrowser.Server.Implementations.Sync
private readonly ISyncManager _syncManager;
private readonly ILogger _logger;
private readonly IUserManager _userManager;
+ private readonly ITVSeriesManager _tvSeriesManager;
- public SyncScheduledTask(ILibraryManager libraryManager, ISyncRepository syncRepo, ISyncManager syncManager, ILogger logger, IUserManager userManager)
+ public SyncScheduledTask(ILibraryManager libraryManager, ISyncRepository syncRepo, ISyncManager syncManager, ILogger logger, IUserManager userManager, ITVSeriesManager tvSeriesManager)
{
_libraryManager = libraryManager;
_syncRepo = syncRepo;
_syncManager = syncManager;
_logger = logger;
_userManager = userManager;
+ _tvSeriesManager = tvSeriesManager;
}
public string Name
{
- get { return "Sync"; }
+ get { return "Sync preparation"; }
}
public string Description
@@ -46,7 +49,7 @@ namespace MediaBrowser.Server.Implementations.Sync
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
{
- return new SyncJobProcessor(_libraryManager, _syncRepo, _syncManager, _logger, _userManager).Sync(progress,
+ return new SyncJobProcessor(_libraryManager, _syncRepo, _syncManager, _logger, _userManager, _tvSeriesManager).Sync(progress,
cancellationToken);
}
@@ -61,7 +64,7 @@ namespace MediaBrowser.Server.Implementations.Sync
public bool IsHidden
{
- get { return true; }
+ get { return false; }
}
public bool IsEnabled
diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config
index 0c79ba387..239bca405 100644
--- a/MediaBrowser.Server.Implementations/packages.config
+++ b/MediaBrowser.Server.Implementations/packages.config
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="MediaBrowser.Naming" version="1.0.0.18" targetFramework="net45" />
+ <package id="MediaBrowser.Naming" version="1.0.0.24" targetFramework="net45" />
<package id="Mono.Nat" version="1.2.21.0" targetFramework="net45" />
<package id="morelinq" version="1.1.0" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.Server.Mac/Native/BaseMonoApp.cs b/MediaBrowser.Server.Mac/Native/BaseMonoApp.cs
index a2c860413..576b5b75f 100644
--- a/MediaBrowser.Server.Mac/Native/BaseMonoApp.cs
+++ b/MediaBrowser.Server.Mac/Native/BaseMonoApp.cs
@@ -67,7 +67,7 @@ namespace MediaBrowser.Server.Mac
return list;
}
- public void AuthorizeServer(int httpServerPort, string httpServerUrlPrefix, int udpPort, string tempDirectory)
+ public void AuthorizeServer(int udpPort, int httpServerPort, string tempDirectory)
{
}
diff --git a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
index c53654e4f..e780f447f 100644
--- a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
+++ b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
@@ -131,10 +131,6 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
- <None Include="..\ThirdParty\libgdiplus\osx\libgdiplus.dylib">
- <Link>libgdiplus.dylib</Link>
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </None>
<None Include="..\ThirdParty\libwebp\osx\libwebp.5.dylib">
<Link>libwebp\osx\libwebp.5.dylib</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
diff --git a/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs b/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs
index 39d2d52d7..7f61570a4 100644
--- a/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs
+++ b/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs
@@ -83,7 +83,7 @@ namespace MediaBrowser.Server.Mono.Native
return list;
}
- public void AuthorizeServer(int httpServerPort, string httpServerUrlPrefix, int udpPort, string tempDirectory)
+ public void AuthorizeServer(int udpPort, int httpServerPort, string tempDirectory)
{
}
diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
index eca600b33..ed5441336 100644
--- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
+++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
@@ -224,7 +224,7 @@ namespace MediaBrowser.Server.Startup.Common
private readonly StartupOptions _startupOptions;
private readonly string _remotePackageName;
- private readonly bool _supportsNativeWebSocket;
+ private bool _supportsNativeWebSocket;
internal INativeApp NativeApp { get; set; }
@@ -238,12 +238,12 @@ namespace MediaBrowser.Server.Startup.Common
/// <param name="remotePackageName">Name of the remote package.</param>
/// <param name="supportsNativeWebSocket">if set to <c>true</c> [supports native web socket].</param>
/// <param name="nativeApp">The native application.</param>
- public ApplicationHost(ServerApplicationPaths applicationPaths,
- ILogManager logManager,
- StartupOptions options,
+ public ApplicationHost(ServerApplicationPaths applicationPaths,
+ ILogManager logManager,
+ StartupOptions options,
IFileSystem fileSystem,
- string remotePackageName,
- bool supportsNativeWebSocket,
+ string remotePackageName,
+ bool supportsNativeWebSocket,
INativeApp nativeApp)
: base(applicationPaths, logManager, fileSystem)
{
@@ -353,17 +353,18 @@ namespace MediaBrowser.Server.Startup.Common
public override async Task Init(IProgress<double> progress)
{
- PerformVersionMigration();
+ PerformPreInitMigrations();
await base.Init(progress).ConfigureAwait(false);
+
+ PerformPostInitMigrations();
}
- private void PerformVersionMigration()
+ private void PerformPreInitMigrations()
{
var migrations = new List<IVersionMigration>
{
new MigrateUserFolders(ApplicationPaths),
- new PlaylistImages(ServerConfigurationManager),
new RenameXbmcOptions(ServerConfigurationManager),
new RenameXmlOptions(ServerConfigurationManager),
new DeprecatePlugins(ApplicationPaths),
@@ -376,6 +377,19 @@ namespace MediaBrowser.Server.Startup.Common
}
}
+ private void PerformPostInitMigrations()
+ {
+ var migrations = new List<IVersionMigration>
+ {
+ new MigrateTranscodingPath(ServerConfigurationManager)
+ };
+
+ foreach (var task in migrations)
+ {
+ task.Run();
+ }
+ }
+
/// <summary>
/// Registers resources that classes will depend on
/// </summary>
@@ -384,7 +398,7 @@ namespace MediaBrowser.Server.Startup.Common
{
await base.RegisterResources(progress).ConfigureAwait(false);
- RegisterSingleInstance<IHttpResultFactory>(new HttpResultFactory(LogManager, FileSystemManager, JsonSerializer));
+ RegisterSingleInstance<IHttpResultFactory>(new HttpResultFactory(LogManager, FileSystemManager, JsonSerializer));
RegisterSingleInstance<IServerApplicationHost>(this);
RegisterSingleInstance<IServerApplicationPaths>(ApplicationPaths);
@@ -396,10 +410,10 @@ namespace MediaBrowser.Server.Startup.Common
RegisterSingleInstance<IBlurayExaminer>(() => new BdInfoExaminer());
- UserDataManager = new UserDataManager(LogManager);
+ UserDataManager = new UserDataManager(LogManager, ServerConfigurationManager);
RegisterSingleInstance(UserDataManager);
- UserRepository = await GetUserRepository().ConfigureAwait(false);
+ UserRepository = await GetUserRepository().ConfigureAwait(false);
RegisterSingleInstance(UserRepository);
DisplayPreferencesRepository = new SqliteDisplayPreferencesRepository(ApplicationPaths, JsonSerializer, LogManager);
@@ -420,7 +434,7 @@ namespace MediaBrowser.Server.Startup.Common
SyncRepository = await GetSyncRepository().ConfigureAwait(false);
RegisterSingleInstance(SyncRepository);
- UserManager = new UserManager(LogManager.GetLogger("UserManager"), ServerConfigurationManager, UserRepository, XmlSerializer, NetworkManager, () => ImageProcessor, () => DtoService, () => ConnectManager, this);
+ UserManager = new UserManager(LogManager.GetLogger("UserManager"), ServerConfigurationManager, UserRepository, XmlSerializer, NetworkManager, () => ImageProcessor, () => DtoService, () => ConnectManager, this, JsonSerializer);
RegisterSingleInstance(UserManager);
LibraryManager = new LibraryManager(Logger, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager);
@@ -440,7 +454,19 @@ namespace MediaBrowser.Server.Startup.Common
RegisterSingleInstance<ISearchEngine>(() => new SearchEngine(LogManager, LibraryManager, UserManager));
- HttpServer = ServerFactory.CreateServer(this, LogManager, "Media Browser", WebApplicationName, "dashboard/index.html", _supportsNativeWebSocket);
+ if (IsFirstRun)
+ {
+ ServerConfigurationManager.Configuration.EnableWin8HttpListener = false;
+ ServerConfigurationManager.SaveConfiguration();
+ _supportsNativeWebSocket = false;
+ }
+
+ if (!ServerConfigurationManager.Configuration.EnableWin8HttpListener)
+ {
+ _supportsNativeWebSocket = false;
+ }
+
+ HttpServer = ServerFactory.CreateServer(this, LogManager, "Media Browser", WebApplicationName, "dashboard/index.html", _supportsNativeWebSocket);
RegisterSingleInstance(HttpServer, false);
progress.Report(10);
@@ -456,7 +482,10 @@ namespace MediaBrowser.Server.Startup.Common
ImageProcessor = new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, MediaEncoder);
RegisterSingleInstance(ImageProcessor);
- SyncManager = new SyncManager(LibraryManager, SyncRepository, ImageProcessor, LogManager.GetLogger("SyncManager"), UserManager);
+ TVSeriesManager = new TVSeriesManager(UserManager, UserDataManager, LibraryManager);
+ RegisterSingleInstance(TVSeriesManager);
+
+ SyncManager = new SyncManager(LibraryManager, SyncRepository, ImageProcessor, LogManager.GetLogger("SyncManager"), UserManager, () => DtoService, this, TVSeriesManager);
RegisterSingleInstance(SyncManager);
DtoService = new DtoService(Logger, LibraryManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager, () => ChannelManager, SyncManager, this);
@@ -471,7 +500,7 @@ namespace MediaBrowser.Server.Startup.Common
DeviceManager = new DeviceManager(new DeviceRepository(ApplicationPaths, JsonSerializer, Logger), UserManager, FileSystemManager, LibraryMonitor, ConfigurationManager, LogManager.GetLogger("DeviceManager"));
RegisterSingleInstance(DeviceManager);
- SessionManager = new SessionManager(UserDataManager, ServerConfigurationManager, Logger, UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, ItemRepository, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager);
+ SessionManager = new SessionManager(UserDataManager, Logger, UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, ItemRepository, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager);
RegisterSingleInstance(SessionManager);
var newsService = new Implementations.News.NewsService(ApplicationPaths, JsonSerializer);
@@ -485,9 +514,6 @@ namespace MediaBrowser.Server.Startup.Common
ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, Logger, ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager, HttpClient);
RegisterSingleInstance(ChannelManager);
- TVSeriesManager = new TVSeriesManager(UserManager, UserDataManager, LibraryManager);
- RegisterSingleInstance(TVSeriesManager);
-
var appThemeManager = new AppThemeManager(ApplicationPaths, FileSystemManager, JsonSerializer, Logger);
RegisterSingleInstance<IAppThemeManager>(appThemeManager);
@@ -532,14 +558,14 @@ namespace MediaBrowser.Server.Startup.Common
var authContext = new AuthorizationContext(AuthenticationRepository);
RegisterSingleInstance<IAuthorizationContext>(authContext);
RegisterSingleInstance<ISessionContext>(new SessionContext(UserManager, authContext, SessionManager));
- RegisterSingleInstance<IAuthService>(new AuthService(UserManager, authContext, ServerConfigurationManager, ConnectManager, SessionManager));
+ RegisterSingleInstance<IAuthService>(new AuthService(UserManager, authContext, ServerConfigurationManager, ConnectManager, SessionManager, DeviceManager));
- RegisterSingleInstance<ISubtitleEncoder>(new SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer));
+ RegisterSingleInstance<ISubtitleEncoder>(new SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer));
await ConfigureDisplayPreferencesRepositories().ConfigureAwait(false);
await ConfigureItemRepositories().ConfigureAwait(false);
await ConfigureUserDataRepositories().ConfigureAwait(false);
- await ConfigureNotificationsRepository().ConfigureAwait(false);
+ await ConfigureNotificationsRepository().ConfigureAwait(false);
progress.Report(100);
SetStaticProperties();
@@ -721,7 +747,7 @@ namespace MediaBrowser.Server.Startup.Common
ServerManager.AddWebSocketListeners(GetExports<IWebSocketListener>(false));
- StartServer(true);
+ StartServer();
LibraryManager.AddParts(GetExports<IResolverIgnoreRule>(),
GetExports<IVirtualFolderCreator>(),
@@ -759,8 +785,7 @@ namespace MediaBrowser.Server.Startup.Common
/// <summary>
/// Starts the server.
/// </summary>
- /// <param name="retryOnFailure">if set to <c>true</c> [retry on failure].</param>
- private void StartServer(bool retryOnFailure)
+ private void StartServer()
{
try
{
@@ -770,16 +795,7 @@ namespace MediaBrowser.Server.Startup.Common
{
Logger.ErrorException("Error starting http server", ex);
- if (retryOnFailure)
- {
- RegisterServerWithAdministratorAccess();
-
- StartServer(false);
- }
- else
- {
- throw;
- }
+ throw;
}
}
@@ -1056,9 +1072,8 @@ namespace MediaBrowser.Server.Startup.Common
try
{
NativeApp.AuthorizeServer(
- ServerConfigurationManager.Configuration.HttpServerPortNumber,
- HttpServerUrlPrefixes.First(),
UdpServerEntryPoint.PortNumber,
+ ServerConfigurationManager.Configuration.HttpServerPortNumber,
ConfigurationManager.CommonApplicationPaths.TempDirectory);
}
catch (Exception ex)
diff --git a/MediaBrowser.Server.Startup.Common/INativeApp.cs b/MediaBrowser.Server.Startup.Common/INativeApp.cs
index 5042e1cea..4abea57fb 100644
--- a/MediaBrowser.Server.Startup.Common/INativeApp.cs
+++ b/MediaBrowser.Server.Startup.Common/INativeApp.cs
@@ -16,11 +16,10 @@ namespace MediaBrowser.Server.Startup.Common
/// <summary>
/// Authorizes the server.
/// </summary>
- /// <param name="httpServerPort">The HTTP server port.</param>
- /// <param name="httpServerUrlPrefix">The HTTP server URL prefix.</param>
/// <param name="udpPort">The UDP port.</param>
+ /// <param name="httpServerPort">The HTTP server port.</param>
/// <param name="tempDirectory">The temporary directory.</param>
- void AuthorizeServer(int httpServerPort, string httpServerUrlPrefix, int udpPort, string tempDirectory);
+ void AuthorizeServer(int udpPort, int httpServerPort, string tempDirectory);
/// <summary>
/// Gets the environment.
diff --git a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj
index b133f78e7..38e07fde4 100644
--- a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj
+++ b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj
@@ -66,8 +66,8 @@
<Compile Include="Migrations\DeleteDlnaProfiles.cs" />
<Compile Include="Migrations\DeprecatePlugins.cs" />
<Compile Include="Migrations\IVersionMigration.cs" />
+ <Compile Include="Migrations\MigrateTranscodingPath.cs" />
<Compile Include="Migrations\MigrateUserFolders.cs" />
- <Compile Include="Migrations\PlaylistImages.cs" />
<Compile Include="Migrations\RenameXbmcOptions.cs" />
<Compile Include="Migrations\RenameXmlOptions.cs" />
<Compile Include="NativeEnvironment.cs" />
diff --git a/MediaBrowser.Server.Startup.Common/Migrations/MigrateTranscodingPath.cs b/MediaBrowser.Server.Startup.Common/Migrations/MigrateTranscodingPath.cs
new file mode 100644
index 000000000..88f60841d
--- /dev/null
+++ b/MediaBrowser.Server.Startup.Common/Migrations/MigrateTranscodingPath.cs
@@ -0,0 +1,30 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Model.Configuration;
+
+namespace MediaBrowser.Server.Startup.Common.Migrations
+{
+ public class MigrateTranscodingPath : IVersionMigration
+ {
+ private readonly IServerConfigurationManager _config;
+
+ public MigrateTranscodingPath(IServerConfigurationManager config)
+ {
+ _config = config;
+ }
+
+ public void Run()
+ {
+ if (!string.IsNullOrWhiteSpace(_config.Configuration.TranscodingTempPath))
+ {
+ var newConfig = _config.GetConfiguration<EncodingOptions>("encoding");
+
+ newConfig.TranscodingTempPath = _config.Configuration.TranscodingTempPath;
+ _config.SaveConfiguration("encoding", newConfig);
+
+ _config.Configuration.TranscodingTempPath = null;
+ _config.SaveConfiguration();
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Startup.Common/Migrations/PlaylistImages.cs b/MediaBrowser.Server.Startup.Common/Migrations/PlaylistImages.cs
deleted file mode 100644
index f6ddf5847..000000000
--- a/MediaBrowser.Server.Startup.Common/Migrations/PlaylistImages.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using System.IO;
-using System.Linq;
-
-namespace MediaBrowser.Server.Startup.Common.Migrations
-{
- public class PlaylistImages : IVersionMigration
- {
- private readonly IServerConfigurationManager _config;
-
- public PlaylistImages(IServerConfigurationManager config)
- {
- _config = config;
- }
-
- public void Run()
- {
- if (!_config.Configuration.PlaylistImagesDeleted)
- {
- DeletePlaylistImages();
- _config.Configuration.PlaylistImagesDeleted = true;
- _config.SaveConfiguration();
- }
- }
-
- private void DeletePlaylistImages()
- {
- try
- {
- var path = Path.Combine(_config.ApplicationPaths.DataPath, "playlists");
-
- var files = Directory.GetFiles(path, "*", SearchOption.AllDirectories)
- .Where(i => BaseItem.SupportedImageExtensions.Contains(Path.GetExtension(i) ?? string.Empty))
- .ToList();
-
- foreach (var file in files)
- {
- try
- {
- File.Delete(file);
- }
- catch (IOException)
- {
-
- }
- }
- }
- catch (IOException)
- {
-
- }
- }
- }
-}
diff --git a/MediaBrowser.Server.Startup.Common/Migrations/RenameXmlOptions.cs b/MediaBrowser.Server.Startup.Common/Migrations/RenameXmlOptions.cs
index a955b57ea..be8ae2f81 100644
--- a/MediaBrowser.Server.Startup.Common/Migrations/RenameXmlOptions.cs
+++ b/MediaBrowser.Server.Startup.Common/Migrations/RenameXmlOptions.cs
@@ -42,9 +42,9 @@ namespace MediaBrowser.Server.Startup.Common.Migrations
{
for (var i = 0; i < options.Length; i++)
{
- if (string.Equals(options[i], "Media Browser Xml", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(options[i], "Media Browser Legacy Xml", StringComparison.OrdinalIgnoreCase))
{
- options[i] = "Media Browser Legacy Xml";
+ options[i] = "Media Browser Xml";
changed = true;
}
}
diff --git a/MediaBrowser.ServerApplication/Native/RegisterServer.bat b/MediaBrowser.ServerApplication/Native/RegisterServer.bat
index 350412344..3346ecb31 100644
--- a/MediaBrowser.ServerApplication/Native/RegisterServer.bat
+++ b/MediaBrowser.ServerApplication/Native/RegisterServer.bat
@@ -1,21 +1,15 @@
-rem %1 = http server port
-rem %2 = http server url
-rem %3 = udp server port
+rem %1 = udp server port
+rem %2 = http server port
if [%1]==[] GOTO DONE
-netsh advfirewall firewall delete rule name="Port %1" protocol=TCP localport=%1
-netsh advfirewall firewall add rule name="Port %1" dir=in action=allow protocol=TCP localport=%1
+netsh advfirewall firewall delete rule name="Port %1" protocol=UDP localport=%1
+netsh advfirewall firewall add rule name="Port %1" dir=in action=allow protocol=UDP localport=%1
if [%2]==[] GOTO DONE
-netsh http del urlacl url="%2" user="NT AUTHORITY\Authenticated Users"
-netsh http add urlacl url="%2" user="NT AUTHORITY\Authenticated Users"
-
-if [%3]==[] GOTO DONE
-
-netsh advfirewall firewall delete rule name="Port %3" protocol=UDP localport=%3
-netsh advfirewall firewall add rule name="Port %3" dir=in action=allow protocol=UDP localport=%3
+netsh advfirewall firewall delete rule name="Port %2" protocol=TCP localport=%2
+netsh advfirewall firewall add rule name="Port %2" dir=in action=allow protocol=TCP localport=%2
:DONE
diff --git a/MediaBrowser.ServerApplication/Native/ServerAuthorization.cs b/MediaBrowser.ServerApplication/Native/ServerAuthorization.cs
index e5989db3b..d9063aa58 100644
--- a/MediaBrowser.ServerApplication/Native/ServerAuthorization.cs
+++ b/MediaBrowser.ServerApplication/Native/ServerAuthorization.cs
@@ -13,11 +13,10 @@ namespace MediaBrowser.ServerApplication.Native
/// <summary>
/// Authorizes the server.
/// </summary>
- /// <param name="httpServerPort">The HTTP server port.</param>
- /// <param name="httpServerUrlPrefix">The HTTP server URL prefix.</param>
/// <param name="udpPort">The UDP port.</param>
+ /// <param name="httpServerPort">The HTTP server port.</param>
/// <param name="tempDirectory">The temp directory.</param>
- public static void AuthorizeServer(int httpServerPort, string httpServerUrlPrefix, int udpPort, string tempDirectory)
+ public static void AuthorizeServer(int udpPort, int httpServerPort, string tempDirectory)
{
Directory.CreateDirectory(tempDirectory);
@@ -37,9 +36,7 @@ namespace MediaBrowser.ServerApplication.Native
{
FileName = tmpFile,
- Arguments = string.Format("{0} {1} {2}", httpServerPort,
- httpServerUrlPrefix,
- udpPort),
+ Arguments = string.Format("{0} {1}", udpPort, httpServerPort),
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
diff --git a/MediaBrowser.ServerApplication/Native/WindowsApp.cs b/MediaBrowser.ServerApplication/Native/WindowsApp.cs
index 9a37c268c..0970d6537 100644
--- a/MediaBrowser.ServerApplication/Native/WindowsApp.cs
+++ b/MediaBrowser.ServerApplication/Native/WindowsApp.cs
@@ -21,9 +21,9 @@ namespace MediaBrowser.ServerApplication.Native
return list;
}
- public void AuthorizeServer(int httpServerPort, string httpServerUrlPrefix, int udpPort, string tempDirectory)
+ public void AuthorizeServer(int httpServerPort, int udpPort, string tempDirectory)
{
- ServerAuthorization.AuthorizeServer(httpServerPort, httpServerUrlPrefix, udpPort, tempDirectory);
+ ServerAuthorization.AuthorizeServer(udpPort, httpServerPort, tempDirectory);
}
public NativeEnvironment Environment
diff --git a/MediaBrowser.Tests/MediaBrowser.Tests.csproj b/MediaBrowser.Tests/MediaBrowser.Tests.csproj
index f93a2612a..e9cec61d6 100644
--- a/MediaBrowser.Tests/MediaBrowser.Tests.csproj
+++ b/MediaBrowser.Tests/MediaBrowser.Tests.csproj
@@ -53,7 +53,6 @@
<Compile Include="MediaEncoding\Subtitles\AssParserTests.cs" />
<Compile Include="MediaEncoding\Subtitles\SrtParserTests.cs" />
<Compile Include="MediaEncoding\Subtitles\VttWriterTest.cs" />
- <Compile Include="Resolvers\TvUtilTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
diff --git a/MediaBrowser.Tests/Resolvers/TvUtilTests.cs b/MediaBrowser.Tests/Resolvers/TvUtilTests.cs
deleted file mode 100644
index ec9356dad..000000000
--- a/MediaBrowser.Tests/Resolvers/TvUtilTests.cs
+++ /dev/null
@@ -1,246 +0,0 @@
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Server.Implementations.Library.Resolvers.TV;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-namespace MediaBrowser.Tests.Resolvers
-{
- [TestClass]
- public class TvUtilTests
- {
- [TestMethod]
- public void TestGetEpisodeNumberFromFile()
- {
- Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 02\S02E03 blah.avi", true));
-
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\01x02 blah.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\S01x02 blah.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\S01E02 blah.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\S01xE02 blah.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\seriesname 01x02 blah.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\seriesname S01x02 blah.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\seriesname S01E02 blah.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\seriesname S01xE02 blah.avi", true));
- Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2\Elementary - 02x03 - 02x04 - 02x15 - Ep Name.ext", true));
- Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2\02x03 - 02x04 - 02x15 - Ep Name.ext", true));
- Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2\02x03-04-15 - Ep Name.ext", true));
- Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2\Elementary - 02x03-04-15 - Ep Name.ext", true));
- Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 02\02x03-E15 - Ep Name.ext", true));
- Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 02\Elementary - 02x03-E15 - Ep Name.ext", true));
- Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 02\02x03 - x04 - x15 - Ep Name.ext", true));
- Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 02\Elementary - 02x03 - x04 - x15 - Ep Name.ext", true));
- Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 02\02x03x04x15 - Ep Name.ext", true));
- Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 02\Elementary - 02x03x04x15 - Ep Name.ext", true));
- Assert.AreEqual(23, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\Elementary - S01E23-E24-E26 - The Woman.mp4", true));
- Assert.AreEqual(23, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\S01E23-E24-E26 - The Woman.mp4", true));
- Assert.AreEqual(9, SeriesResolver.GetEpisodeNumberFromFile(@"Season 25\The Simpsons.S25E09.Steal this episode.mp4", true));
- Assert.AreEqual(8, SeriesResolver.GetEpisodeNumberFromFile(@"The Simpsons\The Simpsons.S25E08.Steal this episode.mp4", false));
- Assert.AreEqual(136, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2\[HorribleSubs] Hunter X Hunter - 136 [720p].mkv",true));
-
- //Four Digits seasons
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\2009x02 blah.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\S2009x02 blah.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\S2009E02 blah.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\S2009xE02 blah.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\seriesname 2009x02 blah.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\seriesname S2009x02 blah.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\seriesname S2009E02 blah.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\seriesname S2009xE02 blah.avi", true));
- Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\Elementary - 2009x03 - 2009x04 - 2009x15 - Ep Name.ext", true));
- Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\2009x03 - 2009x04 - 2009x15 - Ep Name.ext", true));
- Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\2009x03-04-15 - Ep Name.ext", true));
- Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\Elementary - 2009x03-04-15 - Ep Name.ext", true));
- Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\2009x03-E15 - Ep Name.ext", true));
- Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\Elementary - 2009x03-E15 - Ep Name.ext", true));
- Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\2009x03 - x04 - x15 - Ep Name.ext", true));
- Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\Elementary - 2009x03 - x04 - x15 - Ep Name.ext", true));
- Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\2009x03x04x15 - Ep Name.ext", true));
- Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\Elementary - 2009x03x04x15 - Ep Name.ext", true));
- Assert.AreEqual(23, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\Elementary - S2009E23-E24-E26 - The Woman.mp4", true));
- Assert.AreEqual(23, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\S2009E23-E24-E26 - The Woman.mp4", true));
-
- //Without season number
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\02 - blah.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2\02 - blah 14 blah.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\02 - blah-02 a.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2\02.avi", true));
-
- //Without seasons
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"The Simpsons\02.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"The Simpsons\02 - Ep Name.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"The Simpsons\02-Ep Name.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"The Simpsons\02.EpName.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"The Simpsons\The Simpsons - 02.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"The Simpsons\The Simpsons - 02 - Ep Name.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"The Simpsons\The Simpsons - 02 Ep Name.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"The Simpsons\The Simpsons 5 - 02 - Ep Name.avi", true));
- Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"The Simpsons\The Simpsons 5 - 02 Ep Name.avi", true));
- }
-
- [TestMethod]
- public void TestGetEndingEpisodeNumberFromFile()
- {
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\4x01 20 Hours in America (1).mkv"));
-
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\01x02 blah.avi"));
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\S01x02 blah.avi"));
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\S01E02 blah.avi"));
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\S01xE02 blah.avi"));
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\seriesname 01x02 blah.avi"));
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\seriesname S01x02 blah.avi"));
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\seriesname S01E02 blah.avi"));
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\seriesname S01xE02 blah.avi"));
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2\02x03 - 04 Ep Name.ext"));
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2\My show name 02x03 - 04 Ep Name.ext"));
- Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2\Elementary - 02x03 - 02x04 - 02x15 - Ep Name.ext"));
- Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2\02x03 - 02x04 - 02x15 - Ep Name.ext"));
- Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2\02x03-04-15 - Ep Name.ext"));
- Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2\Elementary - 02x03-04-15 - Ep Name.ext"));
- Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 02\02x03-E15 - Ep Name.ext"));
- Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 02\Elementary - 02x03-E15 - Ep Name.ext"));
- Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 02\02x03 - x04 - x15 - Ep Name.ext"));
- Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 02\Elementary - 02x03 - x04 - x15 - Ep Name.ext"));
- Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 02\02x03x04x15 - Ep Name.ext"));
- Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 02\Elementary - 02x03x04x15 - Ep Name.ext"));
- Assert.AreEqual(26, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\Elementary - S01E23-E24-E26 - The Woman.mp4"));
- Assert.AreEqual(26, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\S01E23-E24-E26 - The Woman.mp4"));
-
-
- //Four Digits seasons
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\2009x02 blah.avi"));
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\S2009x02 blah.avi"));
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\S2009E02 blah.avi"));
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\S2009xE02 blah.avi"));
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\seriesname 2009x02 blah.avi"));
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\seriesname S2009x02 blah.avi"));
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\seriesname S2009E02 blah.avi"));
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\seriesname S2009xE02 blah.avi"));
- Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\Elementary - 2009x03 - 2009x04 - 2009x15 - Ep Name.ext"));
- Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\2009x03 - 2009x04 - 2009x15 - Ep Name.ext"));
- Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\2009x03-04-15 - Ep Name.ext"));
- Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\Elementary - 2009x03-04-15 - Ep Name.ext"));
- Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\2009x03-E15 - Ep Name.ext"));
- Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\Elementary - 2009x03-E15 - Ep Name.ext"));
- Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\2009x03 - x04 - x15 - Ep Name.ext"));
- Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\Elementary - 2009x03 - x04 - x15 - Ep Name.ext"));
- Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\2009x03x04x15 - Ep Name.ext"));
- Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\Elementary - 2009x03x04x15 - Ep Name.ext"));
- Assert.AreEqual(26, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\Elementary - S2009E23-E24-E26 - The Woman.mp4"));
- Assert.AreEqual(26, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\S2009E23-E24-E26 - The Woman.mp4"));
-
- //Without season number
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\02 - blah.avi"));
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2\02 - blah 14 blah.avi"));
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\02 - blah-02 a.avi"));
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2\02.avi"));
-
- Assert.AreEqual(3, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\02-03 - blah.avi"));
- Assert.AreEqual(4, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2\02-04 - blah 14 blah.avi"));
- Assert.AreEqual(5, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\02-05 - blah-02 a.avi"));
- Assert.AreEqual(4, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2\02-04.avi"));
- Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2\[HorribleSubs] Hunter X Hunter - 136 [720p].mkv"));
-
- }
-
- [TestMethod]
- public void TestGetSeasonNumberFromPath() {
-
- Assert.AreEqual(02, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"\Show\Season 02\S02E03 blah.avi"));
-
- Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 1"));
- Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 1"));
- Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 1"));
- Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 1"));
- Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 1"));
- Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 1"));
- Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 1"));
- Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 1"));
- Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2"));
- Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2"));
- Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2"));
- Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2"));
- Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 02"));
- Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 02"));
- Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 02"));
- Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 02"));
- Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 02"));
- Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 02"));
- Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 1"));
- Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 1"));
-
- Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Seinfeld\S02"));
-
- Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Seinfeld\2"));
-
- //Four Digits seasons
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009"));
- }
-
- [TestMethod]
- public void TestGetSeasonNumberFromEpisodeFile()
- {
- Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 1\01x02 blah.avi"));
- Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 1\S01x02 blah.avi"));
- Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 1\S01E02 blah.avi"));
- Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 1\S01xE02 blah.avi"));
- Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 1\seriesname 01x02 blah.avi"));
- Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 1\seriesname S01x02 blah.avi"));
- Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 1\seriesname S01E02 blah.avi"));
- Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 1\seriesname S01xE02 blah.avi"));
- Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2\Elementary - 02x03 - 02x04 - 02x15 - Ep Name.ext"));
- Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2\02x03 - 02x04 - 02x15 - Ep Name.ext"));
- Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2\02x03-04-15 - Ep Name.ext"));
- Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2\Elementary - 02x03-04-15 - Ep Name.ext"));
- Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 02\02x03-E15 - Ep Name.ext"));
- Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 02\Elementary - 02x03-E15 - Ep Name.ext"));
- Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 02\02x03 - x04 - x15 - Ep Name.ext"));
- Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 02\Elementary - 02x03 - x04 - x15 - Ep Name.ext"));
- Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 02\02x03x04x15 - Ep Name.ext"));
- Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 02\Elementary - 02x03x04x15 - Ep Name.ext"));
- Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 1\Elementary - S01E23-E24-E26 - The Woman.mp4"));
- Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 1\S01E23-E24-E26 - The Woman.mp4"));
-
- //Four Digits seasons
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\2009x02 blah.avi"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\S2009x02 blah.avi"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\S2009E02 blah.avi"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\S2009xE02 blah.avi"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\seriesname 2009x02 blah.avi"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\seriesname S2009x02 blah.avi"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\seriesname S2009E02 blah.avi"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\seriesname S2009xE02 blah.avi"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\Elementary - 2009x03 - 2009x04 - 2009x15 - Ep Name.ext"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\2009x03 - 2009x04 - 2009x15 - Ep Name.ext"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\2009x03-04-15 - Ep Name.ext"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\Elementary - 2009x03-04-15 - Ep Name.ext"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\2009x03-E15 - Ep Name.ext"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\Elementary - 2009x03-E15 - Ep Name.ext"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\2009x03 - x04 - x15 - Ep Name.ext"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\Elementary - 2009x03 - x04 - x15 - Ep Name.ext"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\2009x03x04x15 - Ep Name.ext"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\Elementary - 2009x03x04x15 - Ep Name.ext"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\Elementary - S2009E23-E24-E26 - The Woman.mp4"));
- Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\S2009E23-E24-E26 - The Woman.mp4"));
- Assert.AreEqual(25, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 25\The Simpsons.S25E09.Steal this episode.mp4"));
- Assert.AreEqual(25, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"The Simpsons\The Simpsons.S25E09.Steal this episode.mp4"));
- }
- }
-}
diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs
index eb44f6d35..6e3439079 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardService.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs
@@ -8,6 +8,7 @@ using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Net;
using MediaBrowser.Model.Serialization;
using ServiceStack;
using ServiceStack.Web;
diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
index b3a1bf84a..d727dda6e 100644
--- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs
+++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
@@ -197,6 +197,8 @@ namespace MediaBrowser.WebDashboard.Api
{
"thirdparty/jquerymobile-1.4.5/jquery.mobile-1.4.5.min.css",
"thirdparty/swipebox-master/css/swipebox.min.css" + versionString,
+ "thirdparty/fontawesome/css/font-awesome.min.css" + versionString,
+ "thirdparty/jstree3.0.8/themes/default/style.min.css",
"css/all.css" + versionString
};
@@ -219,7 +221,7 @@ namespace MediaBrowser.WebDashboard.Api
var files = new[]
{
"scripts/all.js" + versionString,
- "thirdparty/jstree1.0/jquery.jstree.min.js",
+ "thirdparty/jstree3.0.8/jstree.min.js",
"thirdparty/swipebox-master/js/jquery.swipebox.min.js" + versionString
};
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index d8e6561ab..dc552c518 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -210,9 +210,6 @@
<Content Include="dashboard-ui\css\images\favicon.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\css\images\headersearch.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\css\images\icons\ellipsis-v.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -228,9 +225,6 @@
<Content Include="dashboard-ui\css\images\items\folders\report.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\css\images\items\folders\settings.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\css\images\icons\audiocd.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -594,9 +588,6 @@
<Content Include="dashboard-ui\css\images\rotten.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\css\images\currentuserdefaultwhite.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\css\images\items\detail\person.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -963,625 +954,19 @@
<Content Include="dashboard-ui\thirdparty\cast_sender.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\thirdparty\jquery-2.1.1.min.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquery.unveil-custom.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\ajax-loader.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\action-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\action-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\alert-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\alert-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-d-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-d-l-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-d-l-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-d-r-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-d-r-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-d-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-l-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-l-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-r-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-r-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-u-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-u-l-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-u-l-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-u-r-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-u-r-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-u-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\audio-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\audio-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\back-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\back-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\bars-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\bars-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\bullets-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\bullets-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\calendar-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\calendar-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\camera-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\camera-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\carat-d-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\carat-d-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\carat-l-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\carat-l-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\carat-r-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\carat-r-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\carat-u-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\carat-u-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\check-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\check-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\clock-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\clock-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\cloud-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\cloud-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\comment-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\comment-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\delete-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\delete-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\edit-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\edit-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\eye-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\eye-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\forbidden-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\forbidden-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\forward-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\forward-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\gear-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\gear-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\grid-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\grid-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\heart-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\heart-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\home-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\home-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\info-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\info-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\location-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\location-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\lock-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\lock-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\mail-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\mail-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\minus-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\minus-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\navigation-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\navigation-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\phone-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\phone-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\plus-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\plus-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\power-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\power-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\recycle-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\recycle-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\refresh-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\refresh-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\search-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\search-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\shop-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\shop-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\star-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\star-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\tag-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\tag-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\user-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\user-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\video-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\video-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\action-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\action-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\alert-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\alert-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-d-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-d-l-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-d-l-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-d-r-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-d-r-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-d-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-l-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-l-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-r-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-r-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-u-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-u-l-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-u-l-white.svg">
+ <Content Include="dashboard-ui\thirdparty\fontawesome\css\font-awesome.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-u-r-black.svg">
+ <Content Include="dashboard-ui\thirdparty\fontawesome\css\font-awesome.min.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-u-r-white.svg">
+ <Content Include="dashboard-ui\thirdparty\fontawesome\fonts\fontawesome-webfont.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-u-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\audio-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\audio-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\back-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\back-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\bars-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\bars-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\bullets-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\bullets-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\calendar-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\calendar-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\camera-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\camera-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\carat-d-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\carat-d-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\carat-l-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\carat-l-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\carat-r-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\carat-r-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\carat-u-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\carat-u-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\check-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\check-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\clock-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\clock-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\cloud-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\cloud-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\comment-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\comment-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\delete-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\delete-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\edit-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\edit-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\eye-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\eye-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\forbidden-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\forbidden-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\forward-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\forward-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\gear-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\gear-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\grid-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\grid-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\heart-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\heart-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\home-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\home-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\info-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\info-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\location-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\location-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\lock-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\lock-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\mail-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\mail-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\minus-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\minus-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\navigation-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\navigation-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\phone-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\phone-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\plus-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\plus-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\power-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\power-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\recycle-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\recycle-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\refresh-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\refresh-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\search-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\search-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\shop-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\shop-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\star-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\star-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\tag-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\tag-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\user-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\user-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\video-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\video-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\jquery.mobile-1.4.3.min.css">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\jquery.mobile-1.4.3.min.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\jquery.mobile-1.4.4.min.css">
+ <Content Include="dashboard-ui\thirdparty\jquery-2.1.1.min.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\jquery.mobile-1.4.4.min.js">
+ <Content Include="dashboard-ui\thirdparty\jquery.unveil-custom.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\ajax-loader.gif">
@@ -2193,15 +1578,48 @@
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile-1.4.5.min.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\jquery.jstree.min.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\livetvsuggested.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\thirdparty\apiclient\md5.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\jstree.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\jstree.min.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\themes\default-dark\32px.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\themes\default-dark\40px.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\themes\default-dark\style.css">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\themes\default-dark\style.min.css">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\themes\default-dark\throbber.gif">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\themes\default\32px.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\themes\default\40px.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\themes\default\style.css">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\themes\default\style.min.css">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\themes\default\throbber.gif">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\thirdparty\swipebox-master\css\swipebox.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -2438,78 +1856,6 @@
<Content Include="dashboard-ui\scripts\tvstudios.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\jquery.jstree.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\apple\bg.jpg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\apple\d.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\apple\dot_for_ie.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\apple\style.css">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\apple\throbber.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\classic\d.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\classic\d.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\classic\dot_for_ie.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\classic\style.css">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\classic\throbber.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\default-rtl\d.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\default-rtl\d.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\default-rtl\dots.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\default-rtl\style.css">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\default-rtl\throbber.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\default\d.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\default\d.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\default\style.css">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\default\throbber.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\mb3\d.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\mb3\d.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\mb3\style.css">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\mb3\throbber.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\tvgenres.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -2917,10 +2263,16 @@
<None Include="dashboard-ui\css\fonts\RobotoThin.woff">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
- <None Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\jquery.mobile-1.4.3.min.map">
+ <None Include="dashboard-ui\thirdparty\fontawesome\fonts\fontawesome-webfont.eot">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </None>
+ <None Include="dashboard-ui\thirdparty\fontawesome\fonts\fontawesome-webfont.ttf">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </None>
+ <None Include="dashboard-ui\thirdparty\fontawesome\fonts\fontawesome-webfont.woff">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
- <None Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\jquery.mobile-1.4.4.min.map">
+ <None Include="dashboard-ui\thirdparty\fontawesome\fonts\FontAwesome.otf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile-1.4.5.min.map">
diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
index 86e92530f..0f1d53ea6 100644
--- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
@@ -257,6 +257,10 @@ namespace MediaBrowser.XbmcMetadata.Savers
{
}
+ catch (DirectoryNotFoundException)
+ {
+
+ }
writer.WriteEndElement();
diff --git a/MediaBrowser.sln b/MediaBrowser.sln
index 22c2fdc24..c081917fb 100644
--- a/MediaBrowser.sln
+++ b/MediaBrowser.sln
@@ -7,7 +7,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{F0E0E6
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8C5D6ABC-D277-407B-8061-3AA04251D539}"
ProjectSection(SolutionItems) = preProject
+ Performance1.psess = Performance1.psess
Performance19.psess = Performance19.psess
+ Performance2.psess = Performance2.psess
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget (2)", ".nuget (2)", "{E60FB157-87E2-4A41-8B04-27EA49B63B4D}"
@@ -516,4 +518,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(Performance) = preSolution
+ HasPerformanceSessions = true
+ EndGlobalSection
EndGlobal
diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec
index 3ecc9f9a9..8cf12a57b 100644
--- a/Nuget/MediaBrowser.Common.Internal.nuspec
+++ b/Nuget/MediaBrowser.Common.Internal.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common.Internal</id>
- <version>3.0.521</version>
+ <version>3.0.538</version>
<title>MediaBrowser.Common.Internal</title>
<authors>Luke</authors>
<owners>ebr,Luke,scottisafool</owners>
@@ -12,10 +12,9 @@
<description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
<copyright>Copyright © Media Browser 2013</copyright>
<dependencies>
- <dependency id="MediaBrowser.Common" version="3.0.521" />
+ <dependency id="MediaBrowser.Common" version="3.0.538" />
<dependency id="NLog" version="3.1.0.0" />
<dependency id="SimpleInjector" version="2.6.1" />
- <dependency id="sharpcompress" version="0.10.2" />
</dependencies>
</metadata>
<files>
diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec
index da3e29b2a..baec056c0 100644
--- a/Nuget/MediaBrowser.Common.nuspec
+++ b/Nuget/MediaBrowser.Common.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common</id>
- <version>3.0.521</version>
+ <version>3.0.538</version>
<title>MediaBrowser.Common</title>
<authors>Media Browser Team</authors>
<owners>ebr,Luke,scottisafool</owners>
diff --git a/Nuget/MediaBrowser.Model.Signed.nuspec b/Nuget/MediaBrowser.Model.Signed.nuspec
index b0fe2b2c4..3b09f2380 100644
--- a/Nuget/MediaBrowser.Model.Signed.nuspec
+++ b/Nuget/MediaBrowser.Model.Signed.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Model.Signed</id>
- <version>3.0.521</version>
+ <version>3.0.538</version>
<title>MediaBrowser.Model - Signed Edition</title>
<authors>Media Browser Team</authors>
<owners>ebr,Luke,scottisafool</owners>
diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec
index 57d224fd4..7cdbdf319 100644
--- a/Nuget/MediaBrowser.Server.Core.nuspec
+++ b/Nuget/MediaBrowser.Server.Core.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>MediaBrowser.Server.Core</id>
- <version>3.0.521</version>
+ <version>3.0.538</version>
<title>Media Browser.Server.Core</title>
<authors>Media Browser Team</authors>
<owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
<description>Contains core components required to build plugins for Media Browser Server.</description>
<copyright>Copyright © Media Browser 2013</copyright>
<dependencies>
- <dependency id="MediaBrowser.Common" version="3.0.521" />
+ <dependency id="MediaBrowser.Common" version="3.0.538" />
</dependencies>
</metadata>
<files>
diff --git a/SharedVersion.cs b/SharedVersion.cs
index d323dc7bc..ac09f77b3 100644
--- a/SharedVersion.cs
+++ b/SharedVersion.cs
@@ -1,4 +1,4 @@
using System.Reflection;
-//[assembly: AssemblyVersion("3.0.*")]
-[assembly: AssemblyVersion("3.0.5464.40000")]
+[assembly: AssemblyVersion("3.0.*")]
+//[assembly: AssemblyVersion("3.0.5464.40000")]