aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Emby.Drawing/Common/ImageHeader.cs (renamed from MediaBrowser.Server.Implementations/Drawing/ImageHeader.cs)2
-rw-r--r--Emby.Drawing/Emby.Drawing.csproj98
-rw-r--r--Emby.Drawing/GDI/DynamicImageHelpers.cs138
-rw-r--r--Emby.Drawing/GDI/GDIImageEncoder.cs254
-rw-r--r--Emby.Drawing/GDI/ImageExtensions.cs217
-rw-r--r--Emby.Drawing/GDI/PercentPlayedDrawer.cs34
-rw-r--r--Emby.Drawing/GDI/PlayedIndicatorDrawer.cs32
-rw-r--r--Emby.Drawing/GDI/UnplayedCountIndicator.cs50
-rw-r--r--Emby.Drawing/IImageEncoder.cs53
-rw-r--r--Emby.Drawing/ImageMagick/ImageMagickEncoder.cs229
-rw-r--r--Emby.Drawing/ImageMagick/PercentPlayedDrawer.cs (renamed from MediaBrowser.Server.Implementations/Drawing/PercentPlayedDrawer.cs)2
-rw-r--r--Emby.Drawing/ImageMagick/PlayedIndicatorDrawer.cs (renamed from MediaBrowser.Server.Implementations/Drawing/PlayedIndicatorDrawer.cs)2
-rw-r--r--Emby.Drawing/ImageMagick/StripCollageBuilder.cs (renamed from MediaBrowser.Server.Implementations/UserViews/StripCollageBuilder.cs)307
-rw-r--r--Emby.Drawing/ImageMagick/UnplayedCountIndicator.cs (renamed from MediaBrowser.Server.Implementations/Drawing/UnplayedCountIndicator.cs)2
-rw-r--r--Emby.Drawing/ImageProcessor.cs (renamed from MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs)186
-rw-r--r--Emby.Drawing/Properties/AssemblyInfo.cs31
-rw-r--r--Emby.Drawing/packages.config4
-rw-r--r--MediaBrowser.Api/ApiEntryPoint.cs244
-rw-r--r--MediaBrowser.Api/BaseApiService.cs10
-rw-r--r--MediaBrowser.Api/FilterService.cs2
-rw-r--r--MediaBrowser.Api/Images/ImageService.cs28
-rw-r--r--MediaBrowser.Api/LiveTv/LiveTvService.cs19
-rw-r--r--MediaBrowser.Api/MediaBrowser.Api.csproj1
-rw-r--r--MediaBrowser.Api/Movies/MoviesService.cs4
-rw-r--r--MediaBrowser.Api/Music/AlbumsService.cs4
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs18
-rw-r--r--MediaBrowser.Api/Playback/Hls/BaseHlsService.cs16
-rw-r--r--MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs39
-rw-r--r--MediaBrowser.Api/Playback/Hls/VideoHlsService.cs2
-rw-r--r--MediaBrowser.Api/Playback/MediaInfoService.cs51
-rw-r--r--MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs7
-rw-r--r--MediaBrowser.Api/Playback/Progressive/VideoService.cs1
-rw-r--r--MediaBrowser.Api/Playback/TranscodingThrottler.cs4
-rw-r--r--MediaBrowser.Api/Session/SessionsService.cs4
-rw-r--r--MediaBrowser.Api/SimilarItemsHelper.cs2
-rw-r--r--MediaBrowser.Api/Subtitles/SubtitleService.cs4
-rw-r--r--MediaBrowser.Api/Sync/SyncService.cs30
-rw-r--r--MediaBrowser.Api/UserLibrary/ArtistsService.cs4
-rw-r--r--MediaBrowser.Api/UserLibrary/GameGenresService.cs2
-rw-r--r--MediaBrowser.Api/UserLibrary/GenresService.cs2
-rw-r--r--MediaBrowser.Api/UserLibrary/MusicGenresService.cs2
-rw-r--r--MediaBrowser.Api/UserLibrary/PersonsService.cs2
-rw-r--r--MediaBrowser.Api/UserLibrary/PlaystateService.cs52
-rw-r--r--MediaBrowser.Api/UserLibrary/StudiosService.cs2
-rw-r--r--MediaBrowser.Api/UserLibrary/UserLibraryService.cs45
-rw-r--r--MediaBrowser.Api/UserLibrary/UserViewsService.cs121
-rw-r--r--MediaBrowser.Common.Implementations/BaseApplicationHost.cs13
-rw-r--r--MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs12
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs17
-rw-r--r--MediaBrowser.Controller/Channels/Channel.cs16
-rw-r--r--MediaBrowser.Controller/Channels/ChannelAudioItem.cs8
-rw-r--r--MediaBrowser.Controller/Channels/ChannelFolderItem.cs5
-rw-r--r--MediaBrowser.Controller/Channels/ChannelVideoItem.cs12
-rw-r--r--MediaBrowser.Controller/Connect/IConnectManager.cs7
-rw-r--r--MediaBrowser.Controller/Drawing/IImageProcessor.cs12
-rw-r--r--MediaBrowser.Controller/Drawing/ImageCollageOptions.cs32
-rw-r--r--MediaBrowser.Controller/Dto/IDtoService.cs8
-rw-r--r--MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs7
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs85
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs38
-rw-r--r--MediaBrowser.Controller/Entities/ICollectionFolder.cs5
-rw-r--r--MediaBrowser.Controller/Entities/IHasImages.cs8
-rw-r--r--MediaBrowser.Controller/Entities/ItemImageInfo.cs6
-rw-r--r--MediaBrowser.Controller/Entities/Movies/BoxSet.cs18
-rw-r--r--MediaBrowser.Controller/Entities/PhotoAlbum.cs36
-rw-r--r--MediaBrowser.Controller/Entities/UserViewBuilder.cs113
-rw-r--r--MediaBrowser.Controller/IO/ThrottledStream.cs (renamed from MediaBrowser.Server.Implementations/HttpServer/ThrottledStream.cs)2
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs2
-rw-r--r--MediaBrowser.Controller/Library/IMediaSourceManager.cs16
-rw-r--r--MediaBrowser.Controller/Library/NameExtensions.cs79
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvManager.cs11
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvService.cs7
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs10
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj9
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs2
-rw-r--r--MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs8
-rw-r--r--MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs290
-rw-r--r--MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs25
-rw-r--r--MediaBrowser.Controller/Persistence/IItemRepository.cs9
-rw-r--r--MediaBrowser.Controller/Providers/IImageEnhancer.cs3
-rw-r--r--MediaBrowser.Controller/Providers/IProviderManager.cs13
-rw-r--r--MediaBrowser.Controller/Providers/MetadataStatus.cs40
-rw-r--r--MediaBrowser.Controller/Sync/IHasDynamicAccess.cs4
-rw-r--r--MediaBrowser.Controller/Sync/IRemoteSyncProvider.cs10
-rw-r--r--MediaBrowser.Controller/Sync/IServerSyncProvider.cs34
-rw-r--r--MediaBrowser.Controller/Sync/ISyncDataProvider.cs18
-rw-r--r--MediaBrowser.Controller/Sync/ISyncManager.cs22
-rw-r--r--MediaBrowser.Controller/Sync/SyncedFileInfo.cs5
-rw-r--r--MediaBrowser.Controller/packages.config1
-rw-r--r--MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs10
-rw-r--r--MediaBrowser.Dlna/Didl/DidlBuilder.cs53
-rw-r--r--MediaBrowser.Dlna/MediaBrowser.Dlna.csproj5
-rw-r--r--MediaBrowser.Dlna/PlayTo/PlayToController.cs8
-rw-r--r--MediaBrowser.Dlna/PlayTo/PlayToManager.cs2
-rw-r--r--MediaBrowser.Dlna/Profiles/DishHopperJoeyProfile.cs2
-rw-r--r--MediaBrowser.Dlna/Profiles/PopcornHourProfile.cs23
-rw-r--r--MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs44
-rw-r--r--MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs44
-rw-r--r--MediaBrowser.Dlna/Profiles/WindowsMediaCenterProfile.cs274
-rw-r--r--MediaBrowser.Dlna/Profiles/XboxOneProfile.cs98
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Dish Hopper-Joey.xml4
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Popcorn Hour.xml9
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml14
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml14
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml26
-rw-r--r--MediaBrowser.Dlna/Ssdp/SsdpHandler.cs12
-rw-r--r--MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs7
-rw-r--r--MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs5
-rw-r--r--MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs2
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs19
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs9
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs431
-rw-r--r--MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj11
-rw-r--r--MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs (renamed from MediaBrowser.Providers/MediaInfo/FFProbeHelpers.cs)2
-rw-r--r--MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs (renamed from MediaBrowser.Controller/MediaEncoding/InternalMediaInfoResult.cs)6
-rw-r--r--MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs887
-rw-r--r--MediaBrowser.MediaEncoding/Probing/whitelist.txt (renamed from MediaBrowser.Providers/MediaInfo/whitelist.txt)0
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs2
-rw-r--r--MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj12
-rw-r--r--MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj12
-rw-r--r--MediaBrowser.Model/ApiClient/IApiClient.cs9
-rw-r--r--MediaBrowser.Model/ApiClient/ServerCredentials.cs15
-rw-r--r--MediaBrowser.Model/Configuration/EncodingOptions.cs2
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs1
-rw-r--r--MediaBrowser.Model/Configuration/UserConfiguration.cs2
-rw-r--r--MediaBrowser.Model/Dlna/StreamBuilder.cs67
-rw-r--r--MediaBrowser.Model/Dlna/StreamInfo.cs19
-rw-r--r--MediaBrowser.Model/Dto/BaseItemDto.cs80
-rw-r--r--MediaBrowser.Model/Dto/BaseItemPerson.cs4
-rw-r--r--MediaBrowser.Model/Dto/IHasSyncInfo.cs13
-rw-r--r--MediaBrowser.Model/Dto/ItemLayout.cs72
-rw-r--r--MediaBrowser.Model/Dto/UserItemDataDto.cs6
-rw-r--r--MediaBrowser.Model/Entities/CollectionType.cs1
-rw-r--r--MediaBrowser.Model/Entities/MediaInfo.cs26
-rw-r--r--MediaBrowser.Model/Entities/MediaStream.cs5
-rw-r--r--MediaBrowser.Model/LiveTv/LiveTvTunerInfoDto.cs6
-rw-r--r--MediaBrowser.Model/LiveTv/RecordingInfoDto.cs24
-rw-r--r--MediaBrowser.Model/MediaBrowser.Model.csproj4
-rw-r--r--MediaBrowser.Model/MediaInfo/MediaInfo.cs66
-rw-r--r--MediaBrowser.Model/Querying/ItemFields.cs5
-rw-r--r--MediaBrowser.Model/Session/ClientCapabilities.cs5
-rw-r--r--MediaBrowser.Model/Sync/LocalItem.cs5
-rw-r--r--MediaBrowser.Model/Sync/SyncOptions.cs8
-rw-r--r--MediaBrowser.Model/Sync/SyncQualityOption.cs5
-rw-r--r--MediaBrowser.Model/Users/UserPolicy.cs20
-rw-r--r--MediaBrowser.Mono.sln11
-rw-r--r--MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs6
-rw-r--r--MediaBrowser.Providers/FolderImages/DefaultImageProvider.cs153
-rw-r--r--MediaBrowser.Providers/Manager/ItemImageProvider.cs38
-rw-r--r--MediaBrowser.Providers/Manager/MetadataService.cs7
-rw-r--r--MediaBrowser.Providers/Manager/ProviderManager.cs7
-rw-r--r--MediaBrowser.Providers/MediaBrowser.Providers.csproj9
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs350
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs326
-rw-r--r--MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs6
-rw-r--r--MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs2
-rw-r--r--MediaBrowser.Providers/Movies/MovieMetadataService.cs4
-rw-r--r--MediaBrowser.Providers/Music/ArtistMetadataService.cs2
-rw-r--r--MediaBrowser.Providers/TV/SeriesMetadataService.cs4
-rw-r--r--MediaBrowser.Providers/TV/TvdbSeriesProvider.cs32
-rw-r--r--MediaBrowser.Server.Implementations/Channels/ChannelManager.cs11
-rw-r--r--MediaBrowser.Server.Implementations/Collections/CollectionImageProvider.cs3
-rw-r--r--MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Connect/ConnectManager.cs14
-rw-r--r--MediaBrowser.Server.Implementations/Dto/DtoService.cs86
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs9
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs52
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs9
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs40
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs15
-rw-r--r--MediaBrowser.Server.Implementations/Library/LibraryManager.cs40
-rw-r--r--MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs51
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs13
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs18
-rw-r--r--MediaBrowser.Server.Implementations/Library/SearchEngine.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Library/UserViewManager.cs111
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs2
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs5
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs151
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs94
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs8
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/bg_BG.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/da.json45
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/de.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/el.json107
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/es.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json15
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/fi.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json13
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/he.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/hr.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/hu.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/it.json91
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json6
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json25
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json31
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json13
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json25
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json47
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/sl_SI.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/uk.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/zh_CN.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/ar.json47
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/bg_BG.json43
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/ca.json47
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/cs.json43
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/da.json83
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/de.json45
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/el.json493
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/en_GB.json43
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/en_US.json47
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/es.json47
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/es_MX.json49
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/fi.json47
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/fr.json51
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/he.json43
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/hr.json43
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/it.json359
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/kk.json77
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/ko.json47
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/ms.json47
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/nb.json75
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/nl.json43
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/pl.json47
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json53
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json83
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/ru.json107
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/server.json44
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/sl_SI.json47
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/sv.json43
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/tr.json43
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/uk.json47
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/vi.json47
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/zh_CN.json43
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json43
-rw-r--r--MediaBrowser.Server.Implementations/Localization/cultures.json1
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj25
-rw-r--r--MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs3
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs34
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs65
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs14
-rw-r--r--MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs119
-rw-r--r--MediaBrowser.Server.Implementations/Photos/DynamicImageHelpers.cs132
-rw-r--r--MediaBrowser.Server.Implementations/Photos/PhotoAlbumImageProvider.cs25
-rw-r--r--MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Playlists/PlaylistImageProvider.cs3
-rw-r--r--MediaBrowser.Server.Implementations/Session/SessionManager.cs7
-rw-r--r--MediaBrowser.Server.Implementations/Sync/AppSyncProvider.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs26
-rw-r--r--MediaBrowser.Server.Implementations/Sync/MediaSync.cs86
-rw-r--r--MediaBrowser.Server.Implementations/Sync/MultiProviderSync.cs9
-rw-r--r--MediaBrowser.Server.Implementations/Sync/ServerSyncScheduledTask.cs9
-rw-r--r--MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs44
-rw-r--r--MediaBrowser.Server.Implementations/Sync/SyncManager.cs265
-rw-r--r--MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs9
-rw-r--r--MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs133
-rw-r--r--MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs67
-rw-r--r--MediaBrowser.Server.Implementations/packages.config6
-rw-r--r--MediaBrowser.Server.Mac.sln32
-rw-r--r--MediaBrowser.Server.Mac.userprefs31
-rw-r--r--MediaBrowser.Server.Mac/Emby.Server.Mac.csproj (renamed from MediaBrowser.Server.Mac/MediaBrowser.Server.Mac.csproj)81
-rw-r--r--MediaBrowser.Server.Mac/ImageMagickSharp.dll.config3
-rw-r--r--MediaBrowser.Server.Mac/Imazen.WebP.dll.config3
-rw-r--r--MediaBrowser.Server.Mac/Info.plist6
-rw-r--r--MediaBrowser.Server.Mac/Main.cs4
-rw-r--r--MediaBrowser.Server.Startup.Common/ApplicationHost.cs29
-rw-r--r--MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj4
-rw-r--r--MediaBrowser.ServerApplication/MainStartup.cs1
-rw-r--r--MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj2
-rw-r--r--MediaBrowser.ServerApplication/ServerNotifyIcon.cs7
-rw-r--r--MediaBrowser.ServerApplication/packages.config2
-rw-r--r--MediaBrowser.WebDashboard/Api/PackageCreator.cs2
-rw-r--r--MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj20
-rw-r--r--MediaBrowser.WebDashboard/packages.config2
-rw-r--r--MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs4
-rw-r--r--MediaBrowser.sln23
-rw-r--r--Nuget/MediaBrowser.Common.Internal.nuspec4
-rw-r--r--Nuget/MediaBrowser.Common.nuspec2
-rw-r--r--Nuget/MediaBrowser.Model.Signed.nuspec2
-rw-r--r--Nuget/MediaBrowser.Server.Core.nuspec5
-rw-r--r--OpenSubtitlesHandler/XML-RPC/XmlRpcGenerator.cs6
-rw-r--r--README.md16
-rw-r--r--SharedVersion.cs2
300 files changed, 8090 insertions, 4080 deletions
diff --git a/MediaBrowser.Server.Implementations/Drawing/ImageHeader.cs b/Emby.Drawing/Common/ImageHeader.cs
index 7117482c8..b66bd71ea 100644
--- a/MediaBrowser.Server.Implementations/Drawing/ImageHeader.cs
+++ b/Emby.Drawing/Common/ImageHeader.cs
@@ -6,7 +6,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
-namespace MediaBrowser.Server.Implementations.Drawing
+namespace Emby.Drawing.Common
{
/// <summary>
/// Taken from http://stackoverflow.com/questions/111345/getting-image-dimensions-without-reading-the-entire-file/111349
diff --git a/Emby.Drawing/Emby.Drawing.csproj b/Emby.Drawing/Emby.Drawing.csproj
new file mode 100644
index 000000000..f278e1e29
--- /dev/null
+++ b/Emby.Drawing/Emby.Drawing.csproj
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{08FFF49B-F175-4807-A2B5-73B0EBD9F716}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Emby.Drawing</RootNamespace>
+ <AssemblyName>Emby.Drawing</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
+ <RestorePackages>true</RestorePackages>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="ImageMagickSharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\ImageMagickSharp.1.0.0.15\lib\net45\ImageMagickSharp.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\SharedVersion.cs">
+ <Link>Properties\SharedVersion.cs</Link>
+ </Compile>
+ <Compile Include="GDI\DynamicImageHelpers.cs" />
+ <Compile Include="GDI\GDIImageEncoder.cs" />
+ <Compile Include="GDI\ImageExtensions.cs" />
+ <Compile Include="GDI\PercentPlayedDrawer.cs" />
+ <Compile Include="GDI\PlayedIndicatorDrawer.cs" />
+ <Compile Include="GDI\UnplayedCountIndicator.cs" />
+ <Compile Include="IImageEncoder.cs" />
+ <Compile Include="Common\ImageHeader.cs" />
+ <Compile Include="ImageMagick\ImageMagickEncoder.cs" />
+ <Compile Include="ImageMagick\StripCollageBuilder.cs" />
+ <Compile Include="ImageProcessor.cs" />
+ <Compile Include="ImageMagick\PercentPlayedDrawer.cs" />
+ <Compile Include="ImageMagick\PlayedIndicatorDrawer.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="ImageMagick\UnplayedCountIndicator.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="ImageMagick\fonts\MontserratLight.otf" />
+ <EmbeddedResource Include="ImageMagick\fonts\robotoregular.ttf" />
+ <EmbeddedResource Include="ImageMagick\fonts\webdings.ttf" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
+ <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
+ <Name>MediaBrowser.Common</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
+ <Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
+ <Name>MediaBrowser.Controller</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
+ <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
+ <Name>MediaBrowser.Model</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="packages.config" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/Emby.Drawing/GDI/DynamicImageHelpers.cs b/Emby.Drawing/GDI/DynamicImageHelpers.cs
new file mode 100644
index 000000000..c49007c5f
--- /dev/null
+++ b/Emby.Drawing/GDI/DynamicImageHelpers.cs
@@ -0,0 +1,138 @@
+using Emby.Drawing.ImageMagick;
+using MediaBrowser.Common.IO;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Linq;
+
+namespace Emby.Drawing.GDI
+{
+ public static class DynamicImageHelpers
+ {
+ public static void CreateThumbCollage(List<string> files,
+ IFileSystem fileSystem,
+ string file,
+ int width,
+ int height)
+ {
+ const int numStrips = 4;
+ files = StripCollageBuilder.ProjectPaths(files, numStrips).ToList();
+
+ const int rows = 1;
+ int cols = numStrips;
+
+ int cellWidth = 2 * (width / 3);
+ int cellHeight = height;
+ var index = 0;
+
+ using (var img = new Bitmap(width, height, PixelFormat.Format32bppPArgb))
+ {
+ using (var graphics = Graphics.FromImage(img))
+ {
+ graphics.CompositingQuality = CompositingQuality.HighQuality;
+ graphics.SmoothingMode = SmoothingMode.HighQuality;
+ graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
+ graphics.CompositingMode = CompositingMode.SourceCopy;
+
+ for (var row = 0; row < rows; row++)
+ {
+ for (var col = 0; col < cols; col++)
+ {
+ var x = col * (cellWidth / 2);
+ var y = row * cellHeight;
+
+ if (files.Count > index)
+ {
+ using (var fileStream = fileSystem.GetFileStream(files[index], FileMode.Open, FileAccess.Read, FileShare.Read, true))
+ {
+ using (var memoryStream = new MemoryStream())
+ {
+ fileStream.CopyTo(memoryStream);
+
+ memoryStream.Position = 0;
+
+ using (var imgtemp = Image.FromStream(memoryStream, true, false))
+ {
+ graphics.DrawImage(imgtemp, x, y, cellWidth, cellHeight);
+ }
+ }
+ }
+ }
+
+ index++;
+ }
+ }
+ img.Save(file);
+ }
+ }
+ }
+
+ public static void CreateSquareCollage(List<string> files,
+ IFileSystem fileSystem,
+ string file,
+ int width,
+ int height)
+ {
+ files = StripCollageBuilder.ProjectPaths(files, 4).ToList();
+
+ const int rows = 2;
+ const int cols = 2;
+
+ int singleSize = width / 2;
+ var index = 0;
+
+ using (var img = new Bitmap(width, height, PixelFormat.Format32bppPArgb))
+ {
+ using (var graphics = Graphics.FromImage(img))
+ {
+ graphics.CompositingQuality = CompositingQuality.HighQuality;
+ graphics.SmoothingMode = SmoothingMode.HighQuality;
+ graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
+ graphics.CompositingMode = CompositingMode.SourceCopy;
+
+ for (var row = 0; row < rows; row++)
+ {
+ for (var col = 0; col < cols; col++)
+ {
+ var x = col * singleSize;
+ var y = row * singleSize;
+
+ using (var fileStream = fileSystem.GetFileStream(files[index], FileMode.Open, FileAccess.Read, FileShare.Read, true))
+ {
+ using (var memoryStream = new MemoryStream())
+ {
+ fileStream.CopyTo(memoryStream);
+
+ memoryStream.Position = 0;
+
+ using (var imgtemp = Image.FromStream(memoryStream, true, false))
+ {
+ graphics.DrawImage(imgtemp, x, y, singleSize, singleSize);
+ }
+ }
+ }
+
+ index++;
+ }
+ }
+ img.Save(file);
+ }
+ }
+ }
+
+ private static Stream GetStream(Image image)
+ {
+ var ms = new MemoryStream();
+
+ image.Save(ms, ImageFormat.Png);
+
+ ms.Position = 0;
+
+ return ms;
+ }
+ }
+}
diff --git a/Emby.Drawing/GDI/GDIImageEncoder.cs b/Emby.Drawing/GDI/GDIImageEncoder.cs
new file mode 100644
index 000000000..d968b8b5f
--- /dev/null
+++ b/Emby.Drawing/GDI/GDIImageEncoder.cs
@@ -0,0 +1,254 @@
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Drawing;
+using MediaBrowser.Model.Drawing;
+using MediaBrowser.Model.Logging;
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Linq;
+using ImageFormat = MediaBrowser.Model.Drawing.ImageFormat;
+
+namespace Emby.Drawing.GDI
+{
+ public class GDIImageEncoder : IImageEncoder
+ {
+ private readonly IFileSystem _fileSystem;
+ private readonly ILogger _logger;
+
+ public GDIImageEncoder(IFileSystem fileSystem, ILogger logger)
+ {
+ _fileSystem = fileSystem;
+ _logger = logger;
+ }
+
+ public string[] SupportedInputFormats
+ {
+ get
+ {
+ return new[]
+ {
+ "png",
+ "jpeg",
+ "jpg",
+ "gif",
+ "bmp"
+ };
+ }
+ }
+
+ public ImageFormat[] SupportedOutputFormats
+ {
+ get
+ {
+ return new[] { ImageFormat.Gif, ImageFormat.Jpg, ImageFormat.Png };
+ }
+ }
+
+ public ImageSize GetImageSize(string path)
+ {
+ using (var image = Image.FromFile(path))
+ {
+ return new ImageSize
+ {
+ Width = image.Width,
+ Height = image.Height
+ };
+ }
+ }
+
+ public void CropWhiteSpace(string inputPath, string outputPath)
+ {
+ using (var image = (Bitmap)Image.FromFile(inputPath))
+ {
+ using (var croppedImage = image.CropWhitespace())
+ {
+ Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
+
+ using (var outputStream = _fileSystem.GetFileStream(outputPath, FileMode.Create, FileAccess.Write, FileShare.Read, false))
+ {
+ croppedImage.Save(System.Drawing.Imaging.ImageFormat.Png, outputStream, 100);
+ }
+ }
+ }
+ }
+
+ public void EncodeImage(string inputPath, string cacheFilePath, int width, int height, int quality, ImageProcessingOptions options)
+ {
+ var hasPostProcessing = !string.IsNullOrEmpty(options.BackgroundColor) || options.UnplayedCount.HasValue || options.AddPlayedIndicator || options.PercentPlayed > 0;
+
+ using (var originalImage = Image.FromFile(inputPath))
+ {
+ var newWidth = Convert.ToInt32(width);
+ var newHeight = Convert.ToInt32(height);
+
+ var selectedOutputFormat = options.OutputFormat;
+
+ // Graphics.FromImage will throw an exception if the PixelFormat is Indexed, so we need to handle that here
+ // Also, Webp only supports Format32bppArgb and Format32bppRgb
+ var pixelFormat = selectedOutputFormat == ImageFormat.Webp
+ ? PixelFormat.Format32bppArgb
+ : PixelFormat.Format32bppPArgb;
+
+ using (var thumbnail = new Bitmap(newWidth, newHeight, pixelFormat))
+ {
+ // Mono throw an exeception if assign 0 to SetResolution
+ if (originalImage.HorizontalResolution > 0 && originalImage.VerticalResolution > 0)
+ {
+ // Preserve the original resolution
+ thumbnail.SetResolution(originalImage.HorizontalResolution, originalImage.VerticalResolution);
+ }
+
+ using (var thumbnailGraph = Graphics.FromImage(thumbnail))
+ {
+ thumbnailGraph.CompositingQuality = CompositingQuality.HighQuality;
+ thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality;
+ thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ thumbnailGraph.PixelOffsetMode = PixelOffsetMode.HighQuality;
+ thumbnailGraph.CompositingMode = !hasPostProcessing ?
+ CompositingMode.SourceCopy :
+ CompositingMode.SourceOver;
+
+ SetBackgroundColor(thumbnailGraph, options);
+
+ thumbnailGraph.DrawImage(originalImage, 0, 0, newWidth, newHeight);
+
+ DrawIndicator(thumbnailGraph, newWidth, newHeight, options);
+
+ var outputFormat = GetOutputFormat(originalImage, selectedOutputFormat);
+
+ Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
+
+ // Save to the cache location
+ using (var cacheFileStream = _fileSystem.GetFileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, false))
+ {
+ // Save to the memory stream
+ thumbnail.Save(outputFormat, cacheFileStream, quality);
+ }
+ }
+ }
+
+ }
+ }
+
+ /// <summary>
+ /// Sets the color of the background.
+ /// </summary>
+ /// <param name="graphics">The graphics.</param>
+ /// <param name="options">The options.</param>
+ private void SetBackgroundColor(Graphics graphics, ImageProcessingOptions options)
+ {
+ var color = options.BackgroundColor;
+
+ if (!string.IsNullOrEmpty(color))
+ {
+ Color drawingColor;
+
+ try
+ {
+ drawingColor = ColorTranslator.FromHtml(color);
+ }
+ catch
+ {
+ drawingColor = ColorTranslator.FromHtml("#" + color);
+ }
+
+ graphics.Clear(drawingColor);
+ }
+ }
+
+ /// <summary>
+ /// Draws the indicator.
+ /// </summary>
+ /// <param name="graphics">The graphics.</param>
+ /// <param name="imageWidth">Width of the image.</param>
+ /// <param name="imageHeight">Height of the image.</param>
+ /// <param name="options">The options.</param>
+ private void DrawIndicator(Graphics graphics, int imageWidth, int imageHeight, ImageProcessingOptions options)
+ {
+ if (!options.AddPlayedIndicator && !options.UnplayedCount.HasValue && options.PercentPlayed.Equals(0))
+ {
+ return;
+ }
+
+ try
+ {
+ if (options.AddPlayedIndicator)
+ {
+ var currentImageSize = new Size(imageWidth, imageHeight);
+
+ new PlayedIndicatorDrawer().DrawPlayedIndicator(graphics, currentImageSize);
+ }
+ else if (options.UnplayedCount.HasValue)
+ {
+ var currentImageSize = new Size(imageWidth, imageHeight);
+
+ new UnplayedCountIndicator().DrawUnplayedCountIndicator(graphics, currentImageSize, options.UnplayedCount.Value);
+ }
+
+ if (options.PercentPlayed > 0)
+ {
+ var currentImageSize = new Size(imageWidth, imageHeight);
+
+ new PercentPlayedDrawer().Process(graphics, currentImageSize, options.PercentPlayed);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error drawing indicator overlay", ex);
+ }
+ }
+
+ /// <summary>
+ /// Gets the output format.
+ /// </summary>
+ /// <param name="image">The image.</param>
+ /// <param name="outputFormat">The output format.</param>
+ /// <returns>ImageFormat.</returns>
+ private System.Drawing.Imaging.ImageFormat GetOutputFormat(Image image, ImageFormat outputFormat)
+ {
+ switch (outputFormat)
+ {
+ case ImageFormat.Bmp:
+ return System.Drawing.Imaging.ImageFormat.Bmp;
+ case ImageFormat.Gif:
+ return System.Drawing.Imaging.ImageFormat.Gif;
+ case ImageFormat.Jpg:
+ return System.Drawing.Imaging.ImageFormat.Jpeg;
+ case ImageFormat.Png:
+ return System.Drawing.Imaging.ImageFormat.Png;
+ default:
+ return image.RawFormat;
+ }
+ }
+
+ public void CreateImageCollage(ImageCollageOptions options)
+ {
+ double ratio = options.Width;
+ ratio /= options.Height;
+
+ if (ratio >= 1.4)
+ {
+ DynamicImageHelpers.CreateThumbCollage(options.InputPaths.ToList(), _fileSystem, options.OutputPath, options.Width, options.Height);
+ }
+ else if (ratio >= .9)
+ {
+ DynamicImageHelpers.CreateSquareCollage(options.InputPaths.ToList(), _fileSystem, options.OutputPath, options.Width, options.Height);
+ }
+ else
+ {
+ DynamicImageHelpers.CreateSquareCollage(options.InputPaths.ToList(), _fileSystem, options.OutputPath, options.Width, options.Width);
+ }
+ }
+
+ public void Dispose()
+ {
+ }
+
+ public string Name
+ {
+ get { return "GDI"; }
+ }
+ }
+}
diff --git a/Emby.Drawing/GDI/ImageExtensions.cs b/Emby.Drawing/GDI/ImageExtensions.cs
new file mode 100644
index 000000000..6af5a8688
--- /dev/null
+++ b/Emby.Drawing/GDI/ImageExtensions.cs
@@ -0,0 +1,217 @@
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Drawing.Imaging;
+using System.IO;
+
+namespace Emby.Drawing.GDI
+{
+ public static class ImageExtensions
+ {
+ /// <summary>
+ /// Saves the image.
+ /// </summary>
+ /// <param name="outputFormat">The output format.</param>
+ /// <param name="image">The image.</param>
+ /// <param name="toStream">To stream.</param>
+ /// <param name="quality">The quality.</param>
+ public static void Save(this Image image, ImageFormat outputFormat, Stream toStream, int quality)
+ {
+ // Use special save methods for jpeg and png that will result in a much higher quality image
+ // All other formats use the generic Image.Save
+ if (ImageFormat.Jpeg.Equals(outputFormat))
+ {
+ SaveAsJpeg(image, toStream, quality);
+ }
+ else if (ImageFormat.Png.Equals(outputFormat))
+ {
+ image.Save(toStream, ImageFormat.Png);
+ }
+ else
+ {
+ image.Save(toStream, outputFormat);
+ }
+ }
+
+ /// <summary>
+ /// Saves the JPEG.
+ /// </summary>
+ /// <param name="image">The image.</param>
+ /// <param name="target">The target.</param>
+ /// <param name="quality">The quality.</param>
+ public static void SaveAsJpeg(this Image image, Stream target, int quality)
+ {
+ using (var encoderParameters = new EncoderParameters(1))
+ {
+ encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, quality);
+ image.Save(target, GetImageCodecInfo("image/jpeg"), encoderParameters);
+ }
+ }
+
+ private static readonly ImageCodecInfo[] Encoders = ImageCodecInfo.GetImageEncoders();
+
+ /// <summary>
+ /// Gets the image codec info.
+ /// </summary>
+ /// <param name="mimeType">Type of the MIME.</param>
+ /// <returns>ImageCodecInfo.</returns>
+ private static ImageCodecInfo GetImageCodecInfo(string mimeType)
+ {
+ foreach (var encoder in Encoders)
+ {
+ if (string.Equals(encoder.MimeType, mimeType, StringComparison.OrdinalIgnoreCase))
+ {
+ return encoder;
+ }
+ }
+
+ return Encoders.Length == 0 ? null : Encoders[0];
+ }
+
+ /// <summary>
+ /// Crops an image by removing whitespace and transparency from the edges
+ /// </summary>
+ /// <param name="bmp">The BMP.</param>
+ /// <returns>Bitmap.</returns>
+ /// <exception cref="System.Exception"></exception>
+ public static Bitmap CropWhitespace(this Bitmap bmp)
+ {
+ var width = bmp.Width;
+ var height = bmp.Height;
+
+ var topmost = 0;
+ for (int row = 0; row < height; ++row)
+ {
+ if (IsAllWhiteRow(bmp, row, width))
+ topmost = row;
+ else break;
+ }
+
+ int bottommost = 0;
+ for (int row = height - 1; row >= 0; --row)
+ {
+ if (IsAllWhiteRow(bmp, row, width))
+ bottommost = row;
+ else break;
+ }
+
+ int leftmost = 0, rightmost = 0;
+ for (int col = 0; col < width; ++col)
+ {
+ if (IsAllWhiteColumn(bmp, col, height))
+ leftmost = col;
+ else
+ break;
+ }
+
+ for (int col = width - 1; col >= 0; --col)
+ {
+ if (IsAllWhiteColumn(bmp, col, height))
+ rightmost = col;
+ else
+ break;
+ }
+
+ if (rightmost == 0) rightmost = width; // As reached left
+ if (bottommost == 0) bottommost = height; // As reached top.
+
+ var croppedWidth = rightmost - leftmost;
+ var croppedHeight = bottommost - topmost;
+
+ if (croppedWidth == 0) // No border on left or right
+ {
+ leftmost = 0;
+ croppedWidth = width;
+ }
+
+ if (croppedHeight == 0) // No border on top or bottom
+ {
+ topmost = 0;
+ croppedHeight = height;
+ }
+
+ // Graphics.FromImage will throw an exception if the PixelFormat is Indexed, so we need to handle that here
+ var thumbnail = new Bitmap(croppedWidth, croppedHeight, PixelFormat.Format32bppPArgb);
+
+ // Preserve the original resolution
+ TrySetResolution(thumbnail, bmp.HorizontalResolution, bmp.VerticalResolution);
+
+ using (var thumbnailGraph = Graphics.FromImage(thumbnail))
+ {
+ thumbnailGraph.CompositingQuality = CompositingQuality.HighQuality;
+ thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality;
+ thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ thumbnailGraph.PixelOffsetMode = PixelOffsetMode.HighQuality;
+ thumbnailGraph.CompositingMode = CompositingMode.SourceCopy;
+
+ thumbnailGraph.DrawImage(bmp,
+ new RectangleF(0, 0, croppedWidth, croppedHeight),
+ new RectangleF(leftmost, topmost, croppedWidth, croppedHeight),
+ GraphicsUnit.Pixel);
+ }
+ return thumbnail;
+ }
+
+ /// <summary>
+ /// Tries the set resolution.
+ /// </summary>
+ /// <param name="bmp">The BMP.</param>
+ /// <param name="x">The x.</param>
+ /// <param name="y">The y.</param>
+ private static void TrySetResolution(Bitmap bmp, float x, float y)
+ {
+ if (x > 0 && y > 0)
+ {
+ bmp.SetResolution(x, y);
+ }
+ }
+
+ /// <summary>
+ /// Determines whether or not a row of pixels is all whitespace
+ /// </summary>
+ /// <param name="bmp">The BMP.</param>
+ /// <param name="row">The row.</param>
+ /// <param name="width">The width.</param>
+ /// <returns><c>true</c> if [is all white row] [the specified BMP]; otherwise, <c>false</c>.</returns>
+ private static bool IsAllWhiteRow(Bitmap bmp, int row, int width)
+ {
+ for (var i = 0; i < width; ++i)
+ {
+ if (!IsWhiteSpace(bmp.GetPixel(i, row)))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /// <summary>
+ /// Determines whether or not a column of pixels is all whitespace
+ /// </summary>
+ /// <param name="bmp">The BMP.</param>
+ /// <param name="col">The col.</param>
+ /// <param name="height">The height.</param>
+ /// <returns><c>true</c> if [is all white column] [the specified BMP]; otherwise, <c>false</c>.</returns>
+ private static bool IsAllWhiteColumn(Bitmap bmp, int col, int height)
+ {
+ for (var i = 0; i < height; ++i)
+ {
+ if (!IsWhiteSpace(bmp.GetPixel(col, i)))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /// <summary>
+ /// Determines if a color is whitespace
+ /// </summary>
+ /// <param name="color">The color.</param>
+ /// <returns><c>true</c> if [is white space] [the specified color]; otherwise, <c>false</c>.</returns>
+ private static bool IsWhiteSpace(Color color)
+ {
+ return (color.R == 255 && color.G == 255 && color.B == 255) || color.A == 0;
+ }
+ }
+}
diff --git a/Emby.Drawing/GDI/PercentPlayedDrawer.cs b/Emby.Drawing/GDI/PercentPlayedDrawer.cs
new file mode 100644
index 000000000..c7afda60e
--- /dev/null
+++ b/Emby.Drawing/GDI/PercentPlayedDrawer.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Drawing;
+
+namespace Emby.Drawing.GDI
+{
+ public class PercentPlayedDrawer
+ {
+ private const int IndicatorHeight = 8;
+
+ public void Process(Graphics graphics, Size imageSize, double percent)
+ {
+ var y = imageSize.Height - IndicatorHeight;
+
+ using (var backdroundBrush = new SolidBrush(Color.FromArgb(225, 0, 0, 0)))
+ {
+ const int innerX = 0;
+ var innerY = y;
+ var innerWidth = imageSize.Width;
+ var innerHeight = imageSize.Height;
+
+ graphics.FillRectangle(backdroundBrush, innerX, innerY, innerWidth, innerHeight);
+
+ using (var foregroundBrush = new SolidBrush(Color.FromArgb(82, 181, 75)))
+ {
+ double foregroundWidth = innerWidth;
+ foregroundWidth *= percent;
+ foregroundWidth /= 100;
+
+ graphics.FillRectangle(foregroundBrush, innerX, innerY, Convert.ToInt32(Math.Round(foregroundWidth)), innerHeight);
+ }
+ }
+ }
+ }
+}
diff --git a/Emby.Drawing/GDI/PlayedIndicatorDrawer.cs b/Emby.Drawing/GDI/PlayedIndicatorDrawer.cs
new file mode 100644
index 000000000..4428e4cba
--- /dev/null
+++ b/Emby.Drawing/GDI/PlayedIndicatorDrawer.cs
@@ -0,0 +1,32 @@
+using System.Drawing;
+
+namespace Emby.Drawing.GDI
+{
+ public class PlayedIndicatorDrawer
+ {
+ private const int IndicatorHeight = 40;
+ public const int IndicatorWidth = 40;
+ private const int FontSize = 40;
+ private const int OffsetFromTopRightCorner = 10;
+
+ public void DrawPlayedIndicator(Graphics graphics, Size imageSize)
+ {
+ var x = imageSize.Width - IndicatorWidth - OffsetFromTopRightCorner;
+
+ using (var backdroundBrush = new SolidBrush(Color.FromArgb(225, 82, 181, 75)))
+ {
+ graphics.FillEllipse(backdroundBrush, x, OffsetFromTopRightCorner, IndicatorWidth, IndicatorHeight);
+
+ x = imageSize.Width - 45 - OffsetFromTopRightCorner;
+
+ using (var font = new Font("Webdings", FontSize, FontStyle.Regular, GraphicsUnit.Pixel))
+ {
+ using (var fontBrush = new SolidBrush(Color.White))
+ {
+ graphics.DrawString("a", font, fontBrush, x, OffsetFromTopRightCorner - 2);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/Emby.Drawing/GDI/UnplayedCountIndicator.cs b/Emby.Drawing/GDI/UnplayedCountIndicator.cs
new file mode 100644
index 000000000..6420abb27
--- /dev/null
+++ b/Emby.Drawing/GDI/UnplayedCountIndicator.cs
@@ -0,0 +1,50 @@
+using System.Drawing;
+
+namespace Emby.Drawing.GDI
+{
+ public class UnplayedCountIndicator
+ {
+ private const int IndicatorHeight = 41;
+ public const int IndicatorWidth = 41;
+ private const int OffsetFromTopRightCorner = 10;
+
+ public void DrawUnplayedCountIndicator(Graphics graphics, Size imageSize, int count)
+ {
+ var x = imageSize.Width - IndicatorWidth - OffsetFromTopRightCorner;
+
+ using (var backdroundBrush = new SolidBrush(Color.FromArgb(225, 82, 181, 75)))
+ {
+ graphics.FillEllipse(backdroundBrush, x, OffsetFromTopRightCorner, IndicatorWidth, IndicatorHeight);
+
+ var text = count.ToString();
+
+ x = imageSize.Width - IndicatorWidth - OffsetFromTopRightCorner;
+ var y = OffsetFromTopRightCorner + 6;
+ var fontSize = 24;
+
+ if (text.Length == 1)
+ {
+ x += 10;
+ }
+ else if (text.Length == 2)
+ {
+ x += 3;
+ }
+ else if (text.Length == 3)
+ {
+ x += 1;
+ y += 1;
+ fontSize = 20;
+ }
+
+ using (var font = new Font("Sans-Serif", fontSize, FontStyle.Regular, GraphicsUnit.Pixel))
+ {
+ using (var fontBrush = new SolidBrush(Color.White))
+ {
+ graphics.DrawString(text, font, fontBrush, x, y);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/Emby.Drawing/IImageEncoder.cs b/Emby.Drawing/IImageEncoder.cs
new file mode 100644
index 000000000..29261dbdb
--- /dev/null
+++ b/Emby.Drawing/IImageEncoder.cs
@@ -0,0 +1,53 @@
+using MediaBrowser.Controller.Drawing;
+using MediaBrowser.Model.Drawing;
+using System;
+
+namespace Emby.Drawing
+{
+ public interface IImageEncoder : IDisposable
+ {
+ /// <summary>
+ /// Gets the supported input formats.
+ /// </summary>
+ /// <value>The supported input formats.</value>
+ string[] SupportedInputFormats { get; }
+ /// <summary>
+ /// Gets the supported output formats.
+ /// </summary>
+ /// <value>The supported output formats.</value>
+ ImageFormat[] SupportedOutputFormats { get; }
+ /// <summary>
+ /// Gets the size of the image.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>ImageSize.</returns>
+ ImageSize GetImageSize(string path);
+ /// <summary>
+ /// Crops the white space.
+ /// </summary>
+ /// <param name="inputPath">The input path.</param>
+ /// <param name="outputPath">The output path.</param>
+ void CropWhiteSpace(string inputPath, string outputPath);
+ /// <summary>
+ /// Encodes the image.
+ /// </summary>
+ /// <param name="inputPath">The input path.</param>
+ /// <param name="outputPath">The output path.</param>
+ /// <param name="width">The width.</param>
+ /// <param name="height">The height.</param>
+ /// <param name="quality">The quality.</param>
+ /// <param name="options">The options.</param>
+ void EncodeImage(string inputPath, string outputPath, int width, int height, int quality, ImageProcessingOptions options);
+
+ /// <summary>
+ /// Creates the image collage.
+ /// </summary>
+ /// <param name="options">The options.</param>
+ void CreateImageCollage(ImageCollageOptions options);
+ /// <summary>
+ /// Gets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ string Name { get; }
+ }
+}
diff --git a/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs b/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs
new file mode 100644
index 000000000..3d6cdd03d
--- /dev/null
+++ b/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs
@@ -0,0 +1,229 @@
+using ImageMagickSharp;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Controller.Drawing;
+using MediaBrowser.Model.Drawing;
+using MediaBrowser.Model.Logging;
+using System;
+using System.IO;
+
+namespace Emby.Drawing.ImageMagick
+{
+ public class ImageMagickEncoder : IImageEncoder
+ {
+ private readonly ILogger _logger;
+ private readonly IApplicationPaths _appPaths;
+
+ public ImageMagickEncoder(ILogger logger, IApplicationPaths appPaths)
+ {
+ _logger = logger;
+ _appPaths = appPaths;
+
+ LogImageMagickVersion();
+ }
+
+ public string[] SupportedInputFormats
+ {
+ get
+ {
+ // Some common file name extensions for RAW picture files include: .cr2, .crw, .dng, .nef, .orf, .rw2, .pef, .arw, .sr2, .srf, and .tif.
+ return new[]
+ {
+ "tiff",
+ "jpeg",
+ "jpg",
+ "png",
+ "aiff",
+ "cr2",
+ "crw",
+ "dng",
+ "nef",
+ "orf",
+ "pef",
+ "arw",
+ "webp",
+ "gif",
+ "bmp"
+ };
+ }
+ }
+
+ public ImageFormat[] SupportedOutputFormats
+ {
+ get
+ {
+ if (_webpAvailable)
+ {
+ return new[] { ImageFormat.Webp, ImageFormat.Gif, ImageFormat.Jpg, ImageFormat.Png };
+ }
+ return new[] { ImageFormat.Gif, ImageFormat.Jpg, ImageFormat.Png };
+ }
+ }
+
+ private void LogImageMagickVersion()
+ {
+ _logger.Info("ImageMagick version: " + Wand.VersionString);
+ TestWebp();
+ }
+
+ private bool _webpAvailable = true;
+ private void TestWebp()
+ {
+ try
+ {
+ var tmpPath = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid() + ".webp");
+ Directory.CreateDirectory(Path.GetDirectoryName(tmpPath));
+
+ using (var wand = new MagickWand(1, 1, new PixelWand("none", 1)))
+ {
+ wand.SaveImage(tmpPath);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error loading webp: ", ex);
+ _webpAvailable = false;
+ }
+ }
+
+ public void CropWhiteSpace(string inputPath, string outputPath)
+ {
+ CheckDisposed();
+
+ using (var wand = new MagickWand(inputPath))
+ {
+ wand.CurrentImage.TrimImage(10);
+ wand.SaveImage(outputPath);
+ }
+ }
+
+ public ImageSize GetImageSize(string path)
+ {
+ CheckDisposed();
+
+ using (var wand = new MagickWand())
+ {
+ wand.PingImage(path);
+ var img = wand.CurrentImage;
+
+ return new ImageSize
+ {
+ Width = img.Width,
+ Height = img.Height
+ };
+ }
+ }
+
+ public void EncodeImage(string inputPath, string outputPath, int width, int height, int quality, ImageProcessingOptions options)
+ {
+ if (string.IsNullOrWhiteSpace(options.BackgroundColor))
+ {
+ using (var originalImage = new MagickWand(inputPath))
+ {
+ originalImage.CurrentImage.ResizeImage(width, height);
+
+ DrawIndicator(originalImage, width, height, options);
+
+ originalImage.CurrentImage.CompressionQuality = quality;
+
+ originalImage.SaveImage(outputPath);
+ }
+ }
+ else
+ {
+ using (var wand = new MagickWand(width, height, options.BackgroundColor))
+ {
+ using (var originalImage = new MagickWand(inputPath))
+ {
+ originalImage.CurrentImage.ResizeImage(width, height);
+
+ wand.CurrentImage.CompositeImage(originalImage, CompositeOperator.OverCompositeOp, 0, 0);
+ DrawIndicator(wand, width, height, options);
+
+ wand.CurrentImage.CompressionQuality = quality;
+
+ wand.SaveImage(outputPath);
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Draws the indicator.
+ /// </summary>
+ /// <param name="wand">The wand.</param>
+ /// <param name="imageWidth">Width of the image.</param>
+ /// <param name="imageHeight">Height of the image.</param>
+ /// <param name="options">The options.</param>
+ private void DrawIndicator(MagickWand wand, int imageWidth, int imageHeight, ImageProcessingOptions options)
+ {
+ if (!options.AddPlayedIndicator && !options.UnplayedCount.HasValue && options.PercentPlayed.Equals(0))
+ {
+ return;
+ }
+
+ try
+ {
+ if (options.AddPlayedIndicator)
+ {
+ var currentImageSize = new ImageSize(imageWidth, imageHeight);
+
+ new PlayedIndicatorDrawer(_appPaths).DrawPlayedIndicator(wand, currentImageSize);
+ }
+ else if (options.UnplayedCount.HasValue)
+ {
+ var currentImageSize = new ImageSize(imageWidth, imageHeight);
+
+ new UnplayedCountIndicator(_appPaths).DrawUnplayedCountIndicator(wand, currentImageSize, options.UnplayedCount.Value);
+ }
+
+ if (options.PercentPlayed > 0)
+ {
+ new PercentPlayedDrawer().Process(wand, options.PercentPlayed);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error drawing indicator overlay", ex);
+ }
+ }
+
+ public void CreateImageCollage(ImageCollageOptions options)
+ {
+ double ratio = options.Width;
+ ratio /= options.Height;
+
+ if (ratio >= 1.4)
+ {
+ new StripCollageBuilder(_appPaths).BuildThumbCollage(options.InputPaths, options.OutputPath, options.Width, options.Height, options.Text);
+ }
+ else if (ratio >= .9)
+ {
+ new StripCollageBuilder(_appPaths).BuildSquareCollage(options.InputPaths, options.OutputPath, options.Width, options.Height, options.Text);
+ }
+ else
+ {
+ new StripCollageBuilder(_appPaths).BuildPosterCollage(options.InputPaths, options.OutputPath, options.Width, options.Height, options.Text);
+ }
+ }
+
+ public string Name
+ {
+ get { return "ImageMagick"; }
+ }
+
+ private bool _disposed;
+ public void Dispose()
+ {
+ _disposed = true;
+ Wand.CloseEnvironment();
+ }
+
+ private void CheckDisposed()
+ {
+ if (_disposed)
+ {
+ throw new ObjectDisposedException(GetType().Name);
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Drawing/PercentPlayedDrawer.cs b/Emby.Drawing/ImageMagick/PercentPlayedDrawer.cs
index 20c2ab93b..90f9d5609 100644
--- a/MediaBrowser.Server.Implementations/Drawing/PercentPlayedDrawer.cs
+++ b/Emby.Drawing/ImageMagick/PercentPlayedDrawer.cs
@@ -1,7 +1,7 @@
using ImageMagickSharp;
using System;
-namespace MediaBrowser.Server.Implementations.Drawing
+namespace Emby.Drawing.ImageMagick
{
public class PercentPlayedDrawer
{
diff --git a/MediaBrowser.Server.Implementations/Drawing/PlayedIndicatorDrawer.cs b/Emby.Drawing/ImageMagick/PlayedIndicatorDrawer.cs
index 359065cc2..5eeb15771 100644
--- a/MediaBrowser.Server.Implementations/Drawing/PlayedIndicatorDrawer.cs
+++ b/Emby.Drawing/ImageMagick/PlayedIndicatorDrawer.cs
@@ -4,7 +4,7 @@ using MediaBrowser.Model.Drawing;
using System;
using System.IO;
-namespace MediaBrowser.Server.Implementations.Drawing
+namespace Emby.Drawing.ImageMagick
{
public class PlayedIndicatorDrawer
{
diff --git a/MediaBrowser.Server.Implementations/UserViews/StripCollageBuilder.cs b/Emby.Drawing/ImageMagick/StripCollageBuilder.cs
index a9ac0946a..7cdd0077d 100644
--- a/MediaBrowser.Server.Implementations/UserViews/StripCollageBuilder.cs
+++ b/Emby.Drawing/ImageMagick/StripCollageBuilder.cs
@@ -1,13 +1,10 @@
using ImageMagickSharp;
using MediaBrowser.Common.Configuration;
-using MediaBrowser.Server.Implementations.Drawing;
-using MediaBrowser.Server.Implementations.Photos;
using System;
using System.Collections.Generic;
-using System.IO;
using System.Linq;
-namespace MediaBrowser.Server.Implementations.UserViews
+namespace Emby.Drawing.ImageMagick
{
public class StripCollageBuilder
{
@@ -18,52 +15,61 @@ namespace MediaBrowser.Server.Implementations.UserViews
_appPaths = appPaths;
}
- public Stream BuildPosterCollage(IEnumerable<string> paths, int width, int height, bool renderWithText, string text)
+ public void BuildPosterCollage(IEnumerable<string> paths, string outputPath, int width, int height, string text)
{
- if (renderWithText)
+ if (!string.IsNullOrWhiteSpace(text))
{
using (var wand = BuildPosterCollageWandWithText(paths, text, width, height))
{
- return DynamicImageHelpers.GetStream(wand, _appPaths);
+ wand.SaveImage(outputPath);
}
}
- using (var wand = BuildPosterCollageWand(paths, width, height))
+ else
{
- return DynamicImageHelpers.GetStream(wand, _appPaths);
+ using (var wand = BuildPosterCollageWand(paths, width, height))
+ {
+ wand.SaveImage(outputPath);
+ }
}
}
- public Stream BuildSquareCollage(IEnumerable<string> paths, int width, int height, bool renderWithText, string text)
+ public void BuildSquareCollage(IEnumerable<string> paths, string outputPath, int width, int height, string text)
{
- if (renderWithText)
+ if (!string.IsNullOrWhiteSpace(text))
{
using (var wand = BuildSquareCollageWandWithText(paths, text, width, height))
{
- return DynamicImageHelpers.GetStream(wand, _appPaths);
+ wand.SaveImage(outputPath);
}
}
- using (var wand = BuildSquareCollageWand(paths, width, height))
+ else
{
- return DynamicImageHelpers.GetStream(wand, _appPaths);
+ using (var wand = BuildSquareCollageWand(paths, width, height))
+ {
+ wand.SaveImage(outputPath);
+ }
}
}
- public Stream BuildThumbCollage(IEnumerable<string> paths, int width, int height, bool renderWithText, string text)
+ public void BuildThumbCollage(IEnumerable<string> paths, string outputPath, int width, int height, string text)
{
- if (renderWithText)
+ if (!string.IsNullOrWhiteSpace(text))
{
using (var wand = BuildThumbCollageWandWithText(paths, text, width, height))
{
- return DynamicImageHelpers.GetStream(wand, _appPaths);
+ wand.SaveImage(outputPath);
}
}
- using (var wand = BuildThumbCollageWand(paths, width, height))
+ else
{
- return DynamicImageHelpers.GetStream(wand, _appPaths);
+ using (var wand = BuildThumbCollageWand(paths, width, height))
+ {
+ wand.SaveImage(outputPath);
+ }
}
}
- private string[] ProjectPaths(IEnumerable<string> paths, int count)
+ internal static string[] ProjectPaths(IEnumerable<string> paths, int count)
{
var clone = paths.ToList();
var list = new List<string>();
@@ -129,21 +135,27 @@ namespace MediaBrowser.Server.Implementations.UserViews
wandList.CurrentImage.TrimImage(1);
using (var mwr = wandList.CloneMagickWand())
{
- mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
- mwr.CurrentImage.FlipImage();
-
- mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
- mwr.CurrentImage.ColorizeImage(ColorName.Black, ColorName.Grey70);
-
- using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
+ using (var blackPixelWand = new PixelWand(ColorName.Black))
{
- mwg.OpenImage("gradient:black-none");
- var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
- mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.DstInCompositeOp, 0, verticalSpacing);
-
- wandList.AddImage(mwr);
- int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
- wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * 0.26851851851851851851851851851852));
+ using (var greyPixelWand = new PixelWand(ColorName.Grey70))
+ {
+ mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
+ mwr.CurrentImage.FlipImage();
+
+ mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
+ mwr.CurrentImage.ColorizeImage(blackPixelWand, greyPixelWand);
+
+ using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
+ {
+ mwg.OpenImage("gradient:black-none");
+ var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
+ mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.DstInCompositeOp, 0, verticalSpacing);
+
+ wandList.AddImage(mwr);
+ int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
+ wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * 0.26851851851851851851851851851852));
+ }
+ }
}
}
}
@@ -169,14 +181,17 @@ namespace MediaBrowser.Server.Implementations.UserViews
foreach (var element in wandImages.ImageList)
{
- int iWidth = (int)Math.Abs(iHeight * element.Width / element.Height);
- element.Gravity = GravityType.CenterGravity;
- element.BackgroundColor = ColorName.Black;
- element.ResizeImage(iWidth, iHeight, FilterTypes.LanczosFilter);
- int ix = (int)Math.Abs((iWidth - iSlice) / 2);
- element.CropImage(iSlice, iHeight, ix, 0);
-
- element.ExtentImage(iSlice, iHeight, 0 - horizontalImagePadding, 0);
+ using (var blackPixelWand = new PixelWand(ColorName.Black))
+ {
+ int iWidth = (int)Math.Abs(iHeight * element.Width / element.Height);
+ element.Gravity = GravityType.CenterGravity;
+ element.BackgroundColor = blackPixelWand;
+ element.ResizeImage(iWidth, iHeight, FilterTypes.LanczosFilter);
+ int ix = (int)Math.Abs((iWidth - iSlice) / 2);
+ element.CropImage(iSlice, iHeight, ix, 0);
+
+ element.ExtentImage(iSlice, iHeight, 0 - horizontalImagePadding, 0);
+ }
}
wandImages.SetFirstIterator();
@@ -185,21 +200,27 @@ namespace MediaBrowser.Server.Implementations.UserViews
wandList.CurrentImage.TrimImage(1);
using (var mwr = wandList.CloneMagickWand())
{
- mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
- mwr.CurrentImage.FlipImage();
-
- mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
- mwr.CurrentImage.ColorizeImage(ColorName.Black, ColorName.Grey70);
-
- using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
+ using (var blackPixelWand = new PixelWand(ColorName.Black))
{
- mwg.OpenImage("gradient:black-none");
- var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
- mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.CopyOpacityCompositeOp, 0, verticalSpacing);
-
- wandList.AddImage(mwr);
- int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
- wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * .05));
+ using (var greyPixelWand = new PixelWand(ColorName.Grey70))
+ {
+ mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
+ mwr.CurrentImage.FlipImage();
+
+ mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
+ mwr.CurrentImage.ColorizeImage(blackPixelWand, greyPixelWand);
+
+ using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
+ {
+ mwg.OpenImage("gradient:black-none");
+ var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
+ mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.CopyOpacityCompositeOp, 0, verticalSpacing);
+
+ wandList.AddImage(mwr);
+ int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
+ wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * .05));
+ }
+ }
}
}
}
@@ -254,21 +275,27 @@ namespace MediaBrowser.Server.Implementations.UserViews
wandList.CurrentImage.TrimImage(1);
using (var mwr = wandList.CloneMagickWand())
{
- mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
- mwr.CurrentImage.FlipImage();
-
- mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
- mwr.CurrentImage.ColorizeImage(ColorName.Black, ColorName.Grey60);
-
- using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
+ using (var blackPixelWand = new PixelWand(ColorName.Black))
{
- mwg.OpenImage("gradient:black-none");
- var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
- mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.DstInCompositeOp, 0, verticalSpacing);
-
- wandList.AddImage(mwr);
- int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
- wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * 0.26851851851851851851851851851852));
+ using (var greyPixelWand = new PixelWand(ColorName.Grey70))
+ {
+ mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
+ mwr.CurrentImage.FlipImage();
+
+ mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
+ mwr.CurrentImage.ColorizeImage(blackPixelWand, greyPixelWand);
+
+ using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
+ {
+ mwg.OpenImage("gradient:black-none");
+ var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
+ mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.DstInCompositeOp, 0, verticalSpacing);
+
+ wandList.AddImage(mwr);
+ int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
+ wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * 0.26851851851851851851851851851852));
+ }
+ }
}
}
}
@@ -294,14 +321,17 @@ namespace MediaBrowser.Server.Implementations.UserViews
foreach (var element in wandImages.ImageList)
{
- int iWidth = (int)Math.Abs(iHeight * element.Width / element.Height);
- element.Gravity = GravityType.CenterGravity;
- element.BackgroundColor = ColorName.Black;
- element.ResizeImage(iWidth, iHeight, FilterTypes.LanczosFilter);
- int ix = (int)Math.Abs((iWidth - iSlice) / 2);
- element.CropImage(iSlice, iHeight, ix, 0);
-
- element.ExtentImage(iSlice, iHeight, 0 - horizontalImagePadding, 0);
+ using (var blackPixelWand = new PixelWand(ColorName.Black))
+ {
+ int iWidth = (int)Math.Abs(iHeight * element.Width / element.Height);
+ element.Gravity = GravityType.CenterGravity;
+ element.BackgroundColor = blackPixelWand;
+ element.ResizeImage(iWidth, iHeight, FilterTypes.LanczosFilter);
+ int ix = (int)Math.Abs((iWidth - iSlice) / 2);
+ element.CropImage(iSlice, iHeight, ix, 0);
+
+ element.ExtentImage(iSlice, iHeight, 0 - horizontalImagePadding, 0);
+ }
}
wandImages.SetFirstIterator();
@@ -310,21 +340,27 @@ namespace MediaBrowser.Server.Implementations.UserViews
wandList.CurrentImage.TrimImage(1);
using (var mwr = wandList.CloneMagickWand())
{
- mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
- mwr.CurrentImage.FlipImage();
-
- mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
- mwr.CurrentImage.ColorizeImage(ColorName.Black, ColorName.Grey60);
-
- using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
+ using (var blackPixelWand = new PixelWand(ColorName.Black))
{
- mwg.OpenImage("gradient:black-none");
- var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
- mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.CopyOpacityCompositeOp, 0, verticalSpacing);
-
- wandList.AddImage(mwr);
- int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
- wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * .085));
+ using (var greyPixelWand = new PixelWand(ColorName.Grey70))
+ {
+ mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
+ mwr.CurrentImage.FlipImage();
+
+ mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
+ mwr.CurrentImage.ColorizeImage(blackPixelWand, greyPixelWand);
+
+ using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
+ {
+ mwg.OpenImage("gradient:black-none");
+ var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
+ mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.CopyOpacityCompositeOp, 0, verticalSpacing);
+
+ wandList.AddImage(mwr);
+ int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
+ wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * .085));
+ }
+ }
}
}
}
@@ -350,14 +386,17 @@ namespace MediaBrowser.Server.Implementations.UserViews
foreach (var element in wandImages.ImageList)
{
- int iWidth = (int)Math.Abs(iHeight * element.Width / element.Height);
- element.Gravity = GravityType.CenterGravity;
- element.BackgroundColor = ColorName.Black;
- element.ResizeImage(iWidth, iHeight, FilterTypes.LanczosFilter);
- int ix = (int)Math.Abs((iWidth - iSlice) / 2);
- element.CropImage(iSlice, iHeight, ix, 0);
-
- element.ExtentImage(iSlice, iHeight, 0 - horizontalImagePadding, 0);
+ using (var blackPixelWand = new PixelWand(ColorName.Black))
+ {
+ int iWidth = (int)Math.Abs(iHeight * element.Width / element.Height);
+ element.Gravity = GravityType.CenterGravity;
+ element.BackgroundColor = blackPixelWand;
+ element.ResizeImage(iWidth, iHeight, FilterTypes.LanczosFilter);
+ int ix = (int)Math.Abs((iWidth - iSlice) / 2);
+ element.CropImage(iSlice, iHeight, ix, 0);
+
+ element.ExtentImage(iSlice, iHeight, 0 - horizontalImagePadding, 0);
+ }
}
wandImages.SetFirstIterator();
@@ -366,21 +405,27 @@ namespace MediaBrowser.Server.Implementations.UserViews
wandList.CurrentImage.TrimImage(1);
using (var mwr = wandList.CloneMagickWand())
{
- mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
- mwr.CurrentImage.FlipImage();
-
- mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
- mwr.CurrentImage.ColorizeImage(ColorName.Black, ColorName.Grey70);
-
- using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
+ using (var blackPixelWand = new PixelWand(ColorName.Black))
{
- mwg.OpenImage("gradient:black-none");
- var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
- mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.CopyOpacityCompositeOp, 0, verticalSpacing);
-
- wandList.AddImage(mwr);
- int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
- wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * .07));
+ using (var greyPixelWand = new PixelWand(ColorName.Grey70))
+ {
+ mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
+ mwr.CurrentImage.FlipImage();
+
+ mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
+ mwr.CurrentImage.ColorizeImage(blackPixelWand, greyPixelWand);
+
+ using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
+ {
+ mwg.OpenImage("gradient:black-none");
+ var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
+ mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.CopyOpacityCompositeOp, 0, verticalSpacing);
+
+ wandList.AddImage(mwr);
+ int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
+ wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * .07));
+ }
+ }
}
}
}
@@ -435,21 +480,27 @@ namespace MediaBrowser.Server.Implementations.UserViews
wandList.CurrentImage.TrimImage(1);
using (var mwr = wandList.CloneMagickWand())
{
- mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
- mwr.CurrentImage.FlipImage();
-
- mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
- mwr.CurrentImage.ColorizeImage(ColorName.Black, ColorName.Grey60);
-
- using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
+ using (var blackPixelWand = new PixelWand(ColorName.Black))
{
- mwg.OpenImage("gradient:black-none");
- var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
- mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.DstInCompositeOp, 0, verticalSpacing);
-
- wandList.AddImage(mwr);
- int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
- wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * 0.26851851851851851851851851851852));
+ using (var greyPixelWand = new PixelWand(ColorName.Grey70))
+ {
+ mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
+ mwr.CurrentImage.FlipImage();
+
+ mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
+ mwr.CurrentImage.ColorizeImage(blackPixelWand, greyPixelWand);
+
+ using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
+ {
+ mwg.OpenImage("gradient:black-none");
+ var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
+ mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.DstInCompositeOp, 0, verticalSpacing);
+
+ wandList.AddImage(mwr);
+ int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
+ wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * 0.26851851851851851851851851851852));
+ }
+ }
}
}
}
diff --git a/MediaBrowser.Server.Implementations/Drawing/UnplayedCountIndicator.cs b/Emby.Drawing/ImageMagick/UnplayedCountIndicator.cs
index 71cced041..dd25004d6 100644
--- a/MediaBrowser.Server.Implementations/Drawing/UnplayedCountIndicator.cs
+++ b/Emby.Drawing/ImageMagick/UnplayedCountIndicator.cs
@@ -3,7 +3,7 @@ using MediaBrowser.Common.Configuration;
using MediaBrowser.Model.Drawing;
using System.Globalization;
-namespace MediaBrowser.Server.Implementations.Drawing
+namespace Emby.Drawing.ImageMagick
{
public class UnplayedCountIndicator
{
diff --git a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs
index d78d5e8ea..55c6f6455 100644
--- a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
+++ b/Emby.Drawing/ImageProcessor.cs
@@ -1,4 +1,4 @@
-using ImageMagickSharp;
+using Emby.Drawing.Common;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller;
@@ -18,7 +18,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-namespace MediaBrowser.Server.Implementations.Drawing
+namespace Emby.Drawing
{
/// <summary>
/// Class ImageProcessor
@@ -50,14 +50,17 @@ namespace MediaBrowser.Server.Implementations.Drawing
private readonly IFileSystem _fileSystem;
private readonly IJsonSerializer _jsonSerializer;
private readonly IServerApplicationPaths _appPaths;
+ private readonly IImageEncoder _imageEncoder;
- public ImageProcessor(ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem, IJsonSerializer jsonSerializer)
+ public ImageProcessor(ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem, IJsonSerializer jsonSerializer, IImageEncoder imageEncoder)
{
_logger = logger;
_fileSystem = fileSystem;
_jsonSerializer = jsonSerializer;
+ _imageEncoder = imageEncoder;
_appPaths = appPaths;
+ ImageEnhancers = new List<IImageEnhancer>();
_saveImageSizeTimer = new Timer(SaveImageSizeCallback, null, Timeout.Infinite, Timeout.Infinite);
Dictionary<Guid, ImageSize> sizeDictionary;
@@ -85,8 +88,14 @@ namespace MediaBrowser.Server.Implementations.Drawing
}
_cachedImagedSizes = new ConcurrentDictionary<Guid, ImageSize>(sizeDictionary);
+ }
- LogImageMagickVersionVersion();
+ public string[] SupportedInputFormats
+ {
+ get
+ {
+ return _imageEncoder.SupportedInputFormats;
+ }
}
private string ResizedImageCachePath
@@ -130,44 +139,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
public ImageFormat[] GetSupportedImageOutputFormats()
{
- if (_webpAvailable)
- {
- return new[] { ImageFormat.Webp, ImageFormat.Gif, ImageFormat.Jpg, ImageFormat.Png };
- }
- return new[] { ImageFormat.Gif, ImageFormat.Jpg, ImageFormat.Png };
- }
-
- private bool _webpAvailable = true;
- private void TestWebp()
- {
- try
- {
- var tmpPath = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid() + ".webp");
- Directory.CreateDirectory(Path.GetDirectoryName(tmpPath));
-
- using (var wand = new MagickWand(1, 1, new PixelWand("none", 1)))
- {
- wand.SaveImage(tmpPath);
- }
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error loading webp: ", ex);
- _webpAvailable = false;
- }
- }
-
- private void LogImageMagickVersionVersion()
- {
- try
- {
- _logger.Info("ImageMagick version: " + Wand.VersionString);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error loading ImageMagick: ", ex);
- }
- TestWebp();
+ return _imageEncoder.SupportedOutputFormats;
}
public async Task<string> ProcessImage(ImageProcessingOptions options)
@@ -186,22 +158,19 @@ namespace MediaBrowser.Server.Implementations.Drawing
}
var dateModified = options.Image.DateModified;
- var length = options.Image.Length;
if (options.CropWhiteSpace)
{
- var tuple = await GetWhitespaceCroppedImage(originalImagePath, dateModified, length).ConfigureAwait(false);
+ var tuple = await GetWhitespaceCroppedImage(originalImagePath, dateModified).ConfigureAwait(false);
originalImagePath = tuple.Item1;
dateModified = tuple.Item2;
- length = tuple.Item3;
}
if (options.Enhancers.Count > 0)
{
var tuple = await GetEnhancedImage(new ItemImageInfo
{
- Length = length,
DateModified = dateModified,
Type = options.Image.Type,
Path = originalImagePath
@@ -210,7 +179,6 @@ namespace MediaBrowser.Server.Implementations.Drawing
originalImagePath = tuple.Item1;
dateModified = tuple.Item2;
- length = tuple.Item3;
}
var originalImageSize = GetImageSize(originalImagePath, dateModified);
@@ -227,7 +195,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
var quality = options.Quality ?? 90;
var outputFormat = GetOutputFormat(options.OutputFormat);
- var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, length, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.BackgroundColor);
+ var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.BackgroundColor);
var semaphore = GetLock(cacheFilePath);
@@ -244,36 +212,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
- if (string.IsNullOrWhiteSpace(options.BackgroundColor))
- {
- using (var originalImage = new MagickWand(originalImagePath))
- {
- originalImage.CurrentImage.ResizeImage(newWidth, newHeight);
-
- DrawIndicator(originalImage, newWidth, newHeight, options);
-
- originalImage.CurrentImage.CompressionQuality = quality;
-
- originalImage.SaveImage(cacheFilePath);
- }
- }
- else
- {
- using (var wand = new MagickWand(newWidth, newHeight, options.BackgroundColor))
- {
- using (var originalImage = new MagickWand(originalImagePath))
- {
- originalImage.CurrentImage.ResizeImage(newWidth, newHeight);
-
- wand.CurrentImage.CompositeImage(originalImage, CompositeOperator.OverCompositeOp, 0, 0);
- DrawIndicator(wand, newWidth, newHeight, options);
-
- wand.CurrentImage.CompressionQuality = quality;
-
- wand.SaveImage(cacheFilePath);
- }
- }
- }
+ _imageEncoder.EncodeImage(originalImagePath, cacheFilePath, newWidth, newHeight, quality, options);
}
}
finally
@@ -286,7 +225,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
private ImageFormat GetOutputFormat(ImageFormat requestedFormat)
{
- if (requestedFormat == ImageFormat.Webp && !_webpAvailable)
+ if (requestedFormat == ImageFormat.Webp && !_imageEncoder.SupportedOutputFormats.Contains(ImageFormat.Webp))
{
return ImageFormat.Png;
}
@@ -295,53 +234,12 @@ namespace MediaBrowser.Server.Implementations.Drawing
}
/// <summary>
- /// Draws the indicator.
- /// </summary>
- /// <param name="wand">The wand.</param>
- /// <param name="imageWidth">Width of the image.</param>
- /// <param name="imageHeight">Height of the image.</param>
- /// <param name="options">The options.</param>
- private void DrawIndicator(MagickWand wand, int imageWidth, int imageHeight, ImageProcessingOptions options)
- {
- if (!options.AddPlayedIndicator && !options.UnplayedCount.HasValue && options.PercentPlayed.Equals(0))
- {
- return;
- }
-
- try
- {
- if (options.AddPlayedIndicator)
- {
- var currentImageSize = new ImageSize(imageWidth, imageHeight);
-
- new PlayedIndicatorDrawer(_appPaths).DrawPlayedIndicator(wand, currentImageSize);
- }
- else if (options.UnplayedCount.HasValue)
- {
- var currentImageSize = new ImageSize(imageWidth, imageHeight);
-
- new UnplayedCountIndicator(_appPaths).DrawUnplayedCountIndicator(wand, currentImageSize, options.UnplayedCount.Value);
- }
-
- if (options.PercentPlayed > 0)
- {
- new PercentPlayedDrawer().Process(wand, options.PercentPlayed);
- }
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error drawing indicator overlay", ex);
- }
- }
-
- /// <summary>
/// Crops whitespace from an image, caches the result, and returns the cached path
/// </summary>
- private async Task<Tuple<string, DateTime, long>> GetWhitespaceCroppedImage(string originalImagePath, DateTime dateModified, long length)
+ private async Task<Tuple<string, DateTime>> GetWhitespaceCroppedImage(string originalImagePath, DateTime dateModified)
{
var name = originalImagePath;
name += "datemodified=" + dateModified.Ticks;
- name += "length=" + length;
var croppedImagePath = GetCachePath(CroppedWhitespaceImageCachePath, name, Path.GetExtension(originalImagePath));
@@ -360,18 +258,14 @@ namespace MediaBrowser.Server.Implementations.Drawing
{
Directory.CreateDirectory(Path.GetDirectoryName(croppedImagePath));
- using (var wand = new MagickWand(originalImagePath))
- {
- wand.CurrentImage.TrimImage(10);
- wand.SaveImage(croppedImagePath);
- }
+ _imageEncoder.CropWhiteSpace(originalImagePath, croppedImagePath);
}
catch (Exception ex)
{
// We have to have a catch-all here because some of the .net image methods throw a plain old Exception
_logger.ErrorException("Error cropping image {0}", ex, originalImagePath);
- return new Tuple<string, DateTime, long>(originalImagePath, dateModified, length);
+ return new Tuple<string, DateTime>(originalImagePath, dateModified);
}
finally
{
@@ -381,11 +275,9 @@ namespace MediaBrowser.Server.Implementations.Drawing
return GetResult(croppedImagePath);
}
- private Tuple<string, DateTime, long> GetResult(string path)
+ private Tuple<string, DateTime> GetResult(string path)
{
- var file = new FileInfo(path);
-
- return new Tuple<string, DateTime, long>(path, _fileSystem.GetLastWriteTimeUtc(file), file.Length);
+ return new Tuple<string, DateTime>(path, _fileSystem.GetLastWriteTimeUtc(path));
}
/// <summary>
@@ -396,7 +288,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
/// <summary>
/// Gets the cache file path based on a set of parameters
/// </summary>
- private string GetCacheFilePath(string originalPath, ImageSize outputSize, int quality, DateTime dateModified, long length, ImageFormat format, bool addPlayedIndicator, double percentPlayed, int? unwatchedCount, string backgroundColor)
+ private string GetCacheFilePath(string originalPath, ImageSize outputSize, int quality, DateTime dateModified, ImageFormat format, bool addPlayedIndicator, double percentPlayed, int? unwatchedCount, string backgroundColor)
{
var filename = originalPath;
@@ -407,7 +299,6 @@ namespace MediaBrowser.Server.Implementations.Drawing
filename += "quality=" + quality;
filename += "datemodified=" + dateModified.Ticks;
- filename += "length=" + length;
filename += "f=" + format;
@@ -500,17 +391,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
CheckDisposed();
- using (var wand = new MagickWand())
- {
- wand.PingImage(path);
- var img = wand.CurrentImage;
-
- size = new ImageSize
- {
- Width = img.Width,
- Height = img.Height
- };
- }
+ size = _imageEncoder.GetImageSize(path);
}
StartSaveImageSizeTimer();
@@ -603,17 +484,16 @@ namespace MediaBrowser.Server.Implementations.Drawing
var originalImagePath = image.Path;
var dateModified = image.DateModified;
var imageType = image.Type;
- var length = image.Length;
// Optimization
if (imageEnhancers.Count == 0)
{
- return (originalImagePath + dateModified.Ticks + string.Empty + length).GetMD5().ToString("N");
+ return (originalImagePath + dateModified.Ticks).GetMD5().ToString("N");
}
// Cache name is created with supported enhancers combined with the last config change so we pick up new config changes
var cacheKeys = imageEnhancers.Select(i => i.GetConfigurationCacheKey(item, imageType)).ToList();
- cacheKeys.Add(originalImagePath + dateModified.Ticks + string.Empty + length);
+ cacheKeys.Add(originalImagePath + dateModified.Ticks);
return string.Join("|", cacheKeys.ToArray()).GetMD5().ToString("N");
}
@@ -636,7 +516,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
return result.Item1;
}
- private async Task<Tuple<string, DateTime, long>> GetEnhancedImage(ItemImageInfo image,
+ private async Task<Tuple<string, DateTime>> GetEnhancedImage(ItemImageInfo image,
IHasImages item,
int imageIndex,
List<IImageEnhancer> enhancers)
@@ -644,7 +524,6 @@ namespace MediaBrowser.Server.Implementations.Drawing
var originalImagePath = image.Path;
var dateModified = image.DateModified;
var imageType = image.Type;
- var length = image.Length;
try
{
@@ -664,7 +543,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
_logger.Error("Error enhancing image", ex);
}
- return new Tuple<string, DateTime, long>(originalImagePath, dateModified, length);
+ return new Tuple<string, DateTime>(originalImagePath, dateModified);
}
/// <summary>
@@ -838,6 +717,11 @@ namespace MediaBrowser.Server.Implementations.Drawing
return Path.Combine(path, filename);
}
+ public void CreateImageCollage(ImageCollageOptions options)
+ {
+ _imageEncoder.CreateImageCollage(options);
+ }
+
public IEnumerable<IImageEnhancer> GetSupportedEnhancers(IHasImages item, ImageType imageType)
{
return ImageEnhancers.Where(i =>
@@ -860,7 +744,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
public void Dispose()
{
_disposed = true;
- Wand.CloseEnvironment();
+ _imageEncoder.Dispose();
_saveImageSizeTimer.Dispose();
}
diff --git a/Emby.Drawing/Properties/AssemblyInfo.cs b/Emby.Drawing/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..fba168d03
--- /dev/null
+++ b/Emby.Drawing/Properties/AssemblyInfo.cs
@@ -0,0 +1,31 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Emby.Drawing")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Emby.Drawing")]
+[assembly: AssemblyCopyright("Copyright © 2015")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("87b6f14e-16d8-4a58-a553-fd9945e47458")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+// \ No newline at end of file
diff --git a/Emby.Drawing/packages.config b/Emby.Drawing/packages.config
new file mode 100644
index 000000000..35c98e592
--- /dev/null
+++ b/Emby.Drawing/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="ImageMagickSharp" version="1.0.0.15" targetFramework="net45" />
+</packages> \ No newline at end of file
diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs
index ed5fa5bfd..55aa778e2 100644
--- a/MediaBrowser.Api/ApiEntryPoint.cs
+++ b/MediaBrowser.Api/ApiEntryPoint.cs
@@ -2,6 +2,7 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Configuration;
@@ -40,6 +41,7 @@ namespace MediaBrowser.Api
private readonly ISessionManager _sessionManager;
private readonly IFileSystem _fileSystem;
+ private readonly IMediaSourceManager _mediaSourceManager;
public readonly SemaphoreSlim TranscodingStartLock = new SemaphoreSlim(1, 1);
@@ -49,12 +51,15 @@ namespace MediaBrowser.Api
/// <param name="logger">The logger.</param>
/// <param name="sessionManager">The session manager.</param>
/// <param name="config">The configuration.</param>
- public ApiEntryPoint(ILogger logger, ISessionManager sessionManager, IServerConfigurationManager config, IFileSystem fileSystem)
+ /// <param name="fileSystem">The file system.</param>
+ /// <param name="mediaSourceManager">The media source manager.</param>
+ public ApiEntryPoint(ILogger logger, ISessionManager sessionManager, IServerConfigurationManager config, IFileSystem fileSystem, IMediaSourceManager mediaSourceManager)
{
Logger = logger;
_sessionManager = sessionManager;
_config = config;
_fileSystem = fileSystem;
+ _mediaSourceManager = mediaSourceManager;
Instance = this;
}
@@ -114,7 +119,7 @@ namespace MediaBrowser.Api
{
var jobCount = _activeTranscodingJobs.Count;
- Parallel.ForEach(_activeTranscodingJobs.ToList(), j => KillTranscodingJob(j, path => true));
+ Parallel.ForEach(_activeTranscodingJobs.ToList(), j => KillTranscodingJob(j, false, path => true));
// Try to allow for some time to kill the ffmpeg processes and delete the partial stream files
if (jobCount > 0)
@@ -133,6 +138,7 @@ namespace MediaBrowser.Api
/// </summary>
/// <param name="path">The path.</param>
/// <param name="playSessionId">The play session identifier.</param>
+ /// <param name="liveStreamId">The live stream identifier.</param>
/// <param name="transcodingJobId">The transcoding job identifier.</param>
/// <param name="type">The type.</param>
/// <param name="process">The process.</param>
@@ -142,6 +148,7 @@ namespace MediaBrowser.Api
/// <returns>TranscodingJob.</returns>
public TranscodingJob OnTranscodeBeginning(string path,
string playSessionId,
+ string liveStreamId,
string transcodingJobId,
TranscodingJobType type,
Process process,
@@ -151,7 +158,7 @@ namespace MediaBrowser.Api
{
lock (_activeTranscodingJobs)
{
- var job = new TranscodingJob
+ var job = new TranscodingJob(Logger)
{
Type = type,
Path = path,
@@ -160,7 +167,8 @@ namespace MediaBrowser.Api
DeviceId = deviceId,
CancellationTokenSource = cancellationTokenSource,
Id = transcodingJobId,
- PlaySessionId = playSessionId
+ PlaySessionId = playSessionId,
+ LiveStreamId = liveStreamId
};
_activeTranscodingJobs.Add(job);
@@ -284,66 +292,86 @@ namespace MediaBrowser.Api
{
job.ActiveRequestCount++;
- job.DisposeKillTimer();
+ if (string.IsNullOrWhiteSpace(job.PlaySessionId) || job.Type == TranscodingJobType.Progressive)
+ {
+ job.StopKillTimer();
+ }
}
public void OnTranscodeEndRequest(TranscodingJob job)
{
job.ActiveRequestCount--;
-
- if (job.ActiveRequestCount == 0)
+ Logger.Debug("OnTranscodeEndRequest job.ActiveRequestCount={0}", job.ActiveRequestCount);
+ if (job.ActiveRequestCount <= 0)
{
- PingTimer(job, true);
+ PingTimer(job, false);
}
}
- internal void PingTranscodingJob(string deviceId, string playSessionId)
+ internal void PingTranscodingJob(string playSessionId)
{
- if (string.IsNullOrEmpty(deviceId))
+ if (string.IsNullOrEmpty(playSessionId))
{
- throw new ArgumentNullException("deviceId");
+ throw new ArgumentNullException("playSessionId");
}
+ Logger.Debug("PingTranscodingJob PlaySessionId={0}", playSessionId);
+
var jobs = new List<TranscodingJob>();
lock (_activeTranscodingJobs)
{
// This is really only needed for HLS.
// Progressive streams can stop on their own reliably
- jobs = jobs.Where(j =>
- {
- if (string.Equals(deviceId, j.DeviceId, StringComparison.OrdinalIgnoreCase))
- {
- return string.Equals(playSessionId, j.PlaySessionId, StringComparison.OrdinalIgnoreCase);
- }
-
- return false;
-
- }).ToList();
+ jobs = jobs.Where(j => string.Equals(playSessionId, j.PlaySessionId, StringComparison.OrdinalIgnoreCase)).ToList();
}
foreach (var job in jobs)
{
- PingTimer(job, false);
+ PingTimer(job, true);
}
}
- private void PingTimer(TranscodingJob job, bool startTimerIfNeeded)
+ private async void PingTimer(TranscodingJob job, bool isProgressCheckIn)
{
- // TODO: Lower this hls timeout
+ if (job.HasExited)
+ {
+ job.StopKillTimer();
+ return;
+ }
+
var timerDuration = job.Type == TranscodingJobType.Progressive ?
1000 :
1800000;
- if (job.KillTimer == null)
+ // We can really reduce the timeout for apps that are using the newer api
+ if (!string.IsNullOrWhiteSpace(job.PlaySessionId) && job.Type != TranscodingJobType.Progressive)
{
- if (startTimerIfNeeded)
- {
- job.KillTimer = new Timer(OnTranscodeKillTimerStopped, job, timerDuration, Timeout.Infinite);
- }
+ timerDuration = 60000;
+ }
+
+ job.PingTimeout = timerDuration;
+ job.LastPingDate = DateTime.UtcNow;
+
+ // Don't start the timer for playback checkins with progressive streaming
+ if (job.Type != TranscodingJobType.Progressive || !isProgressCheckIn)
+ {
+ job.StartKillTimer(OnTranscodeKillTimerStopped);
}
else
{
- job.KillTimer.Change(timerDuration, Timeout.Infinite);
+ job.ChangeKillTimerIfStarted();
+ }
+
+ if (!string.IsNullOrWhiteSpace(job.LiveStreamId))
+ {
+ try
+ {
+ await _mediaSourceManager.PingLiveStream(job.LiveStreamId, CancellationToken.None).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error closing live stream", ex);
+ }
}
}
@@ -355,7 +383,20 @@ namespace MediaBrowser.Api
{
var job = (TranscodingJob)state;
- KillTranscodingJob(job, path => true);
+ if (!job.HasExited && job.Type != TranscodingJobType.Progressive)
+ {
+ var timeSinceLastPing = (DateTime.UtcNow - job.LastPingDate).TotalMilliseconds;
+
+ if (timeSinceLastPing < job.PingTimeout)
+ {
+ job.StartKillTimer(OnTranscodeKillTimerStopped, job.PingTimeout);
+ return;
+ }
+ }
+
+ Logger.Debug("Transcoding kill timer stopped for JobId {0} PlaySessionId {1}. Killing transcoding", job.Id, job.PlaySessionId);
+
+ KillTranscodingJob(job, true, path => true);
}
/// <summary>
@@ -367,19 +408,14 @@ namespace MediaBrowser.Api
/// <returns>Task.</returns>
internal void KillTranscodingJobs(string deviceId, string playSessionId, Func<string, bool> deleteFiles)
{
- if (string.IsNullOrEmpty(deviceId))
- {
- throw new ArgumentNullException("deviceId");
- }
-
KillTranscodingJobs(j =>
{
- if (string.Equals(deviceId, j.DeviceId, StringComparison.OrdinalIgnoreCase))
+ if (!string.IsNullOrWhiteSpace(playSessionId))
{
- return string.IsNullOrWhiteSpace(playSessionId) || string.Equals(playSessionId, j.PlaySessionId, StringComparison.OrdinalIgnoreCase);
+ return string.Equals(playSessionId, j.PlaySessionId, StringComparison.OrdinalIgnoreCase);
}
- return false;
+ return string.Equals(deviceId, j.DeviceId, StringComparison.OrdinalIgnoreCase);
}, deleteFiles);
}
@@ -408,7 +444,7 @@ namespace MediaBrowser.Api
foreach (var job in jobs)
{
- KillTranscodingJob(job, deleteFiles);
+ KillTranscodingJob(job, false, deleteFiles);
}
}
@@ -416,9 +452,14 @@ namespace MediaBrowser.Api
/// Kills the transcoding job.
/// </summary>
/// <param name="job">The job.</param>
+ /// <param name="closeLiveStream">if set to <c>true</c> [close live stream].</param>
/// <param name="delete">The delete.</param>
- private void KillTranscodingJob(TranscodingJob job, Func<string, bool> delete)
+ private async void KillTranscodingJob(TranscodingJob job, bool closeLiveStream, Func<string, bool> delete)
{
+ job.DisposeKillTimer();
+
+ Logger.Debug("KillTranscodingJob - JobId {0} PlaySessionId {1}. Killing transcoding", job.Id, job.PlaySessionId);
+
lock (_activeTranscodingJobs)
{
_activeTranscodingJobs.Remove(job);
@@ -427,34 +468,23 @@ namespace MediaBrowser.Api
{
job.CancellationTokenSource.Cancel();
}
-
- job.DisposeKillTimer();
}
lock (job.ProcessLock)
{
- var process = job.Process;
-
- var hasExited = true;
-
- try
- {
- hasExited = process.HasExited;
- }
- catch (Exception ex)
+ if (job.TranscodingThrottler != null)
{
- Logger.ErrorException("Error determining if ffmpeg process has exited for {0}", ex, job.Path);
+ job.TranscodingThrottler.Stop();
}
+ var process = job.Process;
+
+ var hasExited = job.HasExited;
+
if (!hasExited)
{
try
{
- if (job.TranscodingThrottler != null)
- {
- job.TranscodingThrottler.Stop();
- }
-
Logger.Info("Killing ffmpeg process for {0}", job.Path);
//process.Kill();
@@ -474,6 +504,18 @@ namespace MediaBrowser.Api
{
DeletePartialStreamFiles(job.Path, job.Type, 0, 1500);
}
+
+ if (closeLiveStream && !string.IsNullOrWhiteSpace(job.LiveStreamId))
+ {
+ try
+ {
+ await _mediaSourceManager.CloseLiveStream(job.LiveStreamId, CancellationToken.None).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error closing live stream for {0}", ex, job.Path);
+ }
+ }
}
private async void DeletePartialStreamFiles(string path, TranscodingJobType jobType, int retryCount, int delayMs)
@@ -582,6 +624,11 @@ namespace MediaBrowser.Api
/// <value>The play session identifier.</value>
public string PlaySessionId { get; set; }
/// <summary>
+ /// Gets or sets the live stream identifier.
+ /// </summary>
+ /// <value>The live stream identifier.</value>
+ public string LiveStreamId { get; set; }
+ /// <summary>
/// Gets or sets the path.
/// </summary>
/// <value>The path.</value>
@@ -596,6 +643,7 @@ namespace MediaBrowser.Api
/// </summary>
/// <value>The process.</value>
public Process Process { get; set; }
+ public ILogger Logger { get; private set; }
/// <summary>
/// Gets or sets the active request count.
/// </summary>
@@ -605,7 +653,7 @@ namespace MediaBrowser.Api
/// Gets or sets the kill timer.
/// </summary>
/// <value>The kill timer.</value>
- public Timer KillTimer { get; set; }
+ private Timer KillTimer { get; set; }
public string DeviceId { get; set; }
@@ -628,12 +676,84 @@ namespace MediaBrowser.Api
public TranscodingThrottler TranscodingThrottler { get; set; }
+ private readonly object _timerLock = new object();
+
+ public DateTime LastPingDate { get; set; }
+ public int PingTimeout { get; set; }
+
+ public TranscodingJob(ILogger logger)
+ {
+ Logger = logger;
+ }
+
+ public void StopKillTimer()
+ {
+ lock (_timerLock)
+ {
+ if (KillTimer != null)
+ {
+ KillTimer.Change(Timeout.Infinite, Timeout.Infinite);
+ }
+ }
+ }
+
public void DisposeKillTimer()
{
- if (KillTimer != null)
+ lock (_timerLock)
+ {
+ if (KillTimer != null)
+ {
+ KillTimer.Dispose();
+ KillTimer = null;
+ }
+ }
+ }
+
+ public void StartKillTimer(TimerCallback callback)
+ {
+ StartKillTimer(callback, PingTimeout);
+ }
+
+ public void StartKillTimer(TimerCallback callback, int intervalMs)
+ {
+ CheckHasExited();
+
+ lock (_timerLock)
+ {
+ if (KillTimer == null)
+ {
+ Logger.Debug("Starting kill timer at {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
+ KillTimer = new Timer(callback, this, intervalMs, Timeout.Infinite);
+ }
+ else
+ {
+ Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
+ KillTimer.Change(intervalMs, Timeout.Infinite);
+ }
+ }
+ }
+
+ public void ChangeKillTimerIfStarted()
+ {
+ CheckHasExited();
+
+ lock (_timerLock)
+ {
+ if (KillTimer != null)
+ {
+ var intervalMs = PingTimeout;
+
+ Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
+ KillTimer.Change(intervalMs, Timeout.Infinite);
+ }
+ }
+ }
+
+ private void CheckHasExited()
+ {
+ if (HasExited)
{
- KillTimer.Dispose();
- KillTimer = null;
+ throw new ObjectDisposedException("Job");
}
}
}
diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs
index 4465be97a..66b2a314e 100644
--- a/MediaBrowser.Api/BaseApiService.cs
+++ b/MediaBrowser.Api/BaseApiService.cs
@@ -259,7 +259,7 @@ namespace MediaBrowser.Api
.GetRecursiveChildren(i => i is IHasArtist)
.Cast<IHasArtist>()
.SelectMany(i => i.AllArtists)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.FirstOrDefault(i =>
{
i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar));
@@ -281,7 +281,7 @@ namespace MediaBrowser.Api
return libraryManager.RootFolder.GetRecursiveChildren()
.SelectMany(i => i.Genres)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.FirstOrDefault(i =>
{
i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar));
@@ -301,7 +301,7 @@ namespace MediaBrowser.Api
return libraryManager.RootFolder
.GetRecursiveChildren(i => i is Game)
.SelectMany(i => i.Genres)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.FirstOrDefault(i =>
{
i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar));
@@ -324,7 +324,7 @@ namespace MediaBrowser.Api
return libraryManager.RootFolder
.GetRecursiveChildren()
.SelectMany(i => i.Studios)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.FirstOrDefault(i =>
{
i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar));
@@ -348,7 +348,7 @@ namespace MediaBrowser.Api
.GetRecursiveChildren()
.SelectMany(i => i.People)
.Select(i => i.Name)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.FirstOrDefault(i =>
{
i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar));
diff --git a/MediaBrowser.Api/FilterService.cs b/MediaBrowser.Api/FilterService.cs
index fb51b2bdd..6d1c5d868 100644
--- a/MediaBrowser.Api/FilterService.cs
+++ b/MediaBrowser.Api/FilterService.cs
@@ -76,7 +76,7 @@ namespace MediaBrowser.Api
.ToArray();
result.Genres = items.SelectMany(i => i.Genres)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.OrderBy(i => i)
.ToArray();
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index ec9b2571e..7da11a405 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -40,8 +40,8 @@ namespace MediaBrowser.Api.Images
[Route("/Items/{Id}/Images/{Type}/{Index}", "GET")]
[Route("/Items/{Id}/Images/{Type}", "HEAD")]
[Route("/Items/{Id}/Images/{Type}/{Index}", "HEAD")]
- [Route("/Items/{Id}/Images/{Type}/{Index}/{Tag}/{Format}/{MaxWidth}/{MaxHeight}/{PercentPlayed}", "GET")]
- [Route("/Items/{Id}/Images/{Type}/{Index}/{Tag}/{Format}/{MaxWidth}/{MaxHeight}/{PercentPlayed}", "HEAD")]
+ [Route("/Items/{Id}/Images/{Type}/{Index}/{Tag}/{Format}/{MaxWidth}/{MaxHeight}/{PercentPlayed}/{UnplayedCount}", "GET")]
+ [Route("/Items/{Id}/Images/{Type}/{Index}/{Tag}/{Format}/{MaxWidth}/{MaxHeight}/{PercentPlayed}/{UnplayedCount}", "HEAD")]
public class GetItemImage : ImageRequest
{
/// <summary>
@@ -511,6 +511,30 @@ namespace MediaBrowser.Api.Images
/// <exception cref="ResourceNotFoundException"></exception>
public object GetImage(ImageRequest request, IHasImages item, bool isHeadRequest)
{
+ if (request.PercentPlayed.HasValue)
+ {
+ if (request.PercentPlayed.Value <= 0)
+ {
+ request.PercentPlayed = null;
+ }
+ else if (request.PercentPlayed.Value >= 100)
+ {
+ request.PercentPlayed = null;
+ request.AddPlayedIndicator = true;
+ }
+ }
+ if (request.PercentPlayed.HasValue)
+ {
+ request.UnplayedCount = null;
+ }
+ if (request.UnplayedCount.HasValue)
+ {
+ if (request.UnplayedCount.Value <= 0)
+ {
+ request.UnplayedCount = null;
+ }
+ }
+
var imageInfo = GetImageInfo(request, item);
if (imageInfo == null)
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index bb6f74f36..b8b74369c 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Dto;
@@ -433,7 +434,7 @@ namespace MediaBrowser.Api.LiveTv
var result = await _liveTvManager.GetPrograms(query, CancellationToken.None).ConfigureAwait(false);
- return ToOptimizedSerializedResultUsingCache(result);
+ return ToOptimizedResult(result);
}
public async Task<object> Get(GetRecommendedPrograms request)
@@ -450,7 +451,7 @@ namespace MediaBrowser.Api.LiveTv
var result = await _liveTvManager.GetRecommendedPrograms(query, CancellationToken.None).ConfigureAwait(false);
- return ToOptimizedSerializedResultUsingCache(result);
+ return ToOptimizedResult(result);
}
public object Post(GetPrograms request)
@@ -460,6 +461,9 @@ namespace MediaBrowser.Api.LiveTv
public async Task<object> Get(GetRecordings request)
{
+ var options = new DtoOptions();
+ options.DeviceId = AuthorizationContext.GetAuthorizationInfo(Request).DeviceId;
+
var result = await _liveTvManager.GetRecordings(new RecordingQuery
{
ChannelId = request.ChannelId,
@@ -471,16 +475,19 @@ namespace MediaBrowser.Api.LiveTv
SeriesTimerId = request.SeriesTimerId,
IsInProgress = request.IsInProgress
- }, CancellationToken.None).ConfigureAwait(false);
+ }, options, CancellationToken.None).ConfigureAwait(false);
- return ToOptimizedSerializedResultUsingCache(result);
+ return ToOptimizedResult(result);
}
public async Task<object> Get(GetRecording request)
{
var user = string.IsNullOrEmpty(request.UserId) ? null : _userManager.GetUserById(request.UserId);
- var result = await _liveTvManager.GetRecording(request.Id, CancellationToken.None, user).ConfigureAwait(false);
+ var options = new DtoOptions();
+ options.DeviceId = AuthorizationContext.GetAuthorizationInfo(Request).DeviceId;
+
+ var result = await _liveTvManager.GetRecording(request.Id, options, CancellationToken.None, user).ConfigureAwait(false);
return ToOptimizedSerializedResultUsingCache(result);
}
diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index 14d0f13fb..ab205d6eb 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -156,6 +156,7 @@
<Compile Include="UserLibrary\PlaystateService.cs" />
<Compile Include="UserLibrary\StudiosService.cs" />
<Compile Include="UserLibrary\UserLibraryService.cs" />
+ <Compile Include="UserLibrary\UserViewsService.cs" />
<Compile Include="UserLibrary\YearsService.cs" />
<Compile Include="UserService.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs
index 07f5942c6..1a7f6d8f4 100644
--- a/MediaBrowser.Api/Movies/MoviesService.cs
+++ b/MediaBrowser.Api/Movies/MoviesService.cs
@@ -410,7 +410,7 @@ namespace MediaBrowser.Api.Movies
return items
.SelectMany(i => i.People.Where(p => !string.Equals(PersonType.Director, p.Type, StringComparison.OrdinalIgnoreCase)).Take(2))
.Select(i => i.Name)
- .Distinct(StringComparer.OrdinalIgnoreCase);
+ .DistinctNames();
}
private IEnumerable<string> GetDirectors(IEnumerable<BaseItem> items)
@@ -419,7 +419,7 @@ namespace MediaBrowser.Api.Movies
.Select(i => i.People.FirstOrDefault(p => string.Equals(PersonType.Director, p.Type, StringComparison.OrdinalIgnoreCase)))
.Where(i => i != null)
.Select(i => i.Name)
- .Distinct(StringComparer.OrdinalIgnoreCase);
+ .DistinctNames();
}
}
}
diff --git a/MediaBrowser.Api/Music/AlbumsService.cs b/MediaBrowser.Api/Music/AlbumsService.cs
index a1c98addb..37f79bf20 100644
--- a/MediaBrowser.Api/Music/AlbumsService.cs
+++ b/MediaBrowser.Api/Music/AlbumsService.cs
@@ -79,12 +79,12 @@ namespace MediaBrowser.Api.Music
var artists1 = album1
.AllArtists
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.ToList();
var artists2 = album2
.AllArtists
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
return points + artists1.Where(artists2.ContainsKey).Sum(i => 5);
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index 75321f872..923af3816 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -1010,6 +1010,7 @@ namespace MediaBrowser.Api.Playback
var transcodingJob = ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath,
state.Request.PlaySessionId,
+ state.MediaSource.LiveStreamId,
transcodingId,
TranscodingJobType,
process,
@@ -1026,7 +1027,7 @@ namespace MediaBrowser.Api.Playback
// FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory.
state.LogFileStream = FileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true);
- var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(commandLineLogMessage + Environment.NewLine + Environment.NewLine);
+ var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(Request.AbsoluteUri + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine);
await state.LogFileStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationTokenSource.Token).ConfigureAwait(false);
process.Exited += (sender, args) => OnFfMpegProcessExited(process, transcodingJob, state);
@@ -1515,6 +1516,10 @@ namespace MediaBrowser.Api.Playback
}
else if (i == 22)
{
+ // api_key
+ }
+ else if (i == 23)
+ {
request.LiveStreamId = val;
}
}
@@ -1624,14 +1629,19 @@ namespace MediaBrowser.Api.Playback
var archivable = item as IArchivable;
state.IsInputArchive = archivable != null && archivable.IsArchive;
- MediaSourceInfo mediaSource = null;
+ MediaSourceInfo mediaSource;
if (string.IsNullOrWhiteSpace(request.LiveStreamId))
{
- var mediaSources = await MediaSourceManager.GetPlayackMediaSources(request.Id, false, cancellationToken).ConfigureAwait(false);
+ var mediaSources = (await MediaSourceManager.GetPlayackMediaSources(request.Id, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false)).ToList();
mediaSource = string.IsNullOrEmpty(request.MediaSourceId)
? mediaSources.First()
- : mediaSources.First(i => string.Equals(i.Id, request.MediaSourceId));
+ : mediaSources.FirstOrDefault(i => string.Equals(i.Id, request.MediaSourceId));
+
+ if (mediaSource == null && string.Equals(request.Id, request.MediaSourceId, StringComparison.OrdinalIgnoreCase))
+ {
+ mediaSource = mediaSources.First();
+ }
}
else
{
diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
index 701516b48..919fe0773 100644
--- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
@@ -85,6 +85,7 @@ namespace MediaBrowser.Api.Playback.Hls
state.Request.StartTimeTicks = null;
}
+ TranscodingJob job = null;
var playlist = state.OutputFilePath;
if (!File.Exists(playlist))
@@ -97,7 +98,7 @@ namespace MediaBrowser.Api.Playback.Hls
// If the playlist doesn't already exist, startup ffmpeg
try
{
- await StartFfMpeg(state, playlist, cancellationTokenSource).ConfigureAwait(false);
+ job = await StartFfMpeg(state, playlist, cancellationTokenSource).ConfigureAwait(false);
}
catch
{
@@ -116,6 +117,12 @@ namespace MediaBrowser.Api.Playback.Hls
if (isLive)
{
+ job = job ?? ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType);
+
+ if (job != null)
+ {
+ ApiEntryPoint.Instance.OnTranscodeEndRequest(job);
+ }
return ResultFactory.GetResult(GetLivePlaylistText(playlist, state.SegmentLength), MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
}
@@ -134,6 +141,13 @@ namespace MediaBrowser.Api.Playback.Hls
var playlistText = GetMasterPlaylistFileText(playlist, videoBitrate + audioBitrate, appendBaselineStream, baselineStreamBitrate);
+ job = job ?? ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType);
+
+ if (job != null)
+ {
+ ApiEntryPoint.Instance.OnTranscodeEndRequest(job);
+ }
+
return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
}
diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
index 98d6c9a76..a55f54d3c 100644
--- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
@@ -127,9 +127,27 @@ namespace MediaBrowser.Api.Playback.Hls
}
else
{
+ var startTranscoding = false;
+
var currentTranscodingIndex = GetCurrentTranscodingIndex(playlistPath, segmentExtension);
- var segmentGapRequiringTranscodingChange = 24/state.SegmentLength;
- if (currentTranscodingIndex == null || requestedIndex < currentTranscodingIndex.Value || (requestedIndex - currentTranscodingIndex.Value) > segmentGapRequiringTranscodingChange)
+ var segmentGapRequiringTranscodingChange = 24 / state.SegmentLength;
+
+ if (currentTranscodingIndex == null)
+ {
+ Logger.Debug("Starting transcoding because currentTranscodingIndex=null");
+ startTranscoding = true;
+ }
+ else if (requestedIndex < currentTranscodingIndex.Value)
+ {
+ Logger.Debug("Starting transcoding because requestedIndex={0} and currentTranscodingIndex={1}", requestedIndex, currentTranscodingIndex);
+ startTranscoding = true;
+ }
+ else if ((requestedIndex - currentTranscodingIndex.Value) > segmentGapRequiringTranscodingChange)
+ {
+ Logger.Debug("Starting transcoding because segmentGap is {0} and max allowed gap is {1}. requestedIndex={2}", (requestedIndex - currentTranscodingIndex.Value), segmentGapRequiringTranscodingChange, requestedIndex);
+ startTranscoding = true;
+ }
+ if (startTranscoding)
{
// If the playlist doesn't already exist, startup ffmpeg
try
@@ -144,7 +162,6 @@ namespace MediaBrowser.Api.Playback.Hls
request.StartTimeTicks = GetSeekPositionTicks(state, requestedIndex);
job = await StartFfMpeg(state, playlistPath, cancellationTokenSource).ConfigureAwait(false);
- ApiEntryPoint.Instance.OnTranscodeBeginRequest(job);
}
catch
{
@@ -152,7 +169,15 @@ namespace MediaBrowser.Api.Playback.Hls
throw;
}
- await WaitForMinimumSegmentCount(playlistPath, 1, cancellationTokenSource.Token).ConfigureAwait(false);
+ //await WaitForMinimumSegmentCount(playlistPath, 1, cancellationTokenSource.Token).ConfigureAwait(false);
+ }
+ else
+ {
+ job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
+ if (job.TranscodingThrottler != null)
+ {
+ job.TranscodingThrottler.UnpauseTranscoding();
+ }
}
}
}
@@ -518,7 +543,9 @@ namespace MediaBrowser.Api.Playback.Hls
return false;
}
- return state.VideoRequest.VideoBitRate.HasValue;
+ // Having problems in android
+ return false;
+ //return state.VideoRequest.VideoBitRate.HasValue;
}
private void AppendPlaylist(StringBuilder builder, string url, int bitrate, string subtitleGroup)
@@ -711,7 +738,7 @@ namespace MediaBrowser.Api.Playback.Hls
).Trim();
}
- return string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -flags -global_header -sc_threshold 0 {5} -hls_time {6} -start_number {7} -hls_list_size {8} -y \"{9}\"",
+ return string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -flags -global_header -copyts -sc_threshold 0 {5} -hls_time {6} -start_number {7} -hls_list_size {8} -y \"{9}\"",
inputModifier,
GetInputArgument(state),
threads,
diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
index b1964f4ae..8e2854c5e 100644
--- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
@@ -3,12 +3,10 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.IO;
using ServiceStack;
using System;
-using System.IO;
namespace MediaBrowser.Api.Playback.Hls
{
diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs
index 08c5d56db..c71048b0d 100644
--- a/MediaBrowser.Api/Playback/MediaInfoService.cs
+++ b/MediaBrowser.Api/Playback/MediaInfoService.cs
@@ -1,4 +1,6 @@
-using MediaBrowser.Controller.Devices;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
@@ -59,23 +61,27 @@ namespace MediaBrowser.Api.Playback
private readonly IMediaSourceManager _mediaSourceManager;
private readonly IDeviceManager _deviceManager;
private readonly ILibraryManager _libraryManager;
+ private readonly IServerConfigurationManager _config;
+ private readonly INetworkManager _networkManager;
- public MediaInfoService(IMediaSourceManager mediaSourceManager, IDeviceManager deviceManager, ILibraryManager libraryManager)
+ public MediaInfoService(IMediaSourceManager mediaSourceManager, IDeviceManager deviceManager, ILibraryManager libraryManager, IServerConfigurationManager config, INetworkManager networkManager)
{
_mediaSourceManager = mediaSourceManager;
_deviceManager = deviceManager;
_libraryManager = libraryManager;
+ _config = config;
+ _networkManager = networkManager;
}
public async Task<object> Get(GetPlaybackInfo request)
{
- var result = await GetPlaybackInfo(request.Id, request.UserId).ConfigureAwait(false);
+ var result = await GetPlaybackInfo(request.Id, request.UserId, new[] { MediaType.Audio, MediaType.Video }).ConfigureAwait(false);
return ToOptimizedResult(result);
}
public async Task<object> Get(GetLiveMediaInfo request)
{
- var result = await GetPlaybackInfo(request.Id, request.UserId).ConfigureAwait(false);
+ var result = await GetPlaybackInfo(request.Id, request.UserId, new[] { MediaType.Audio, MediaType.Video }).ConfigureAwait(false);
return ToOptimizedResult(result);
}
@@ -122,29 +128,32 @@ namespace MediaBrowser.Api.Playback
public async Task<object> Post(GetPostedPlaybackInfo request)
{
- var info = await GetPlaybackInfo(request.Id, request.UserId, request.MediaSourceId, request.LiveStreamId).ConfigureAwait(false);
var authInfo = AuthorizationContext.GetAuthorizationInfo(Request);
var profile = request.DeviceProfile;
- if (profile == null)
+
+ var caps = _deviceManager.GetCapabilities(authInfo.DeviceId);
+ if (caps != null)
{
- var caps = _deviceManager.GetCapabilities(authInfo.DeviceId);
- if (caps != null)
+ if (profile == null)
{
profile = caps.DeviceProfile;
}
}
+ var info = await GetPlaybackInfo(request.Id, request.UserId, new[] { MediaType.Audio, MediaType.Video }, request.MediaSourceId, request.LiveStreamId).ConfigureAwait(false);
+
if (profile != null)
{
var mediaSourceId = request.MediaSourceId;
+
SetDeviceSpecificData(request.Id, info, profile, authInfo, request.MaxStreamingBitrate, request.StartTimeTicks ?? 0, mediaSourceId, request.AudioStreamIndex, request.SubtitleStreamIndex);
}
return ToOptimizedResult(info);
}
- private async Task<PlaybackInfoResponse> GetPlaybackInfo(string id, string userId, string mediaSourceId = null, string liveStreamId = null)
+ private async Task<PlaybackInfoResponse> GetPlaybackInfo(string id, string userId, string[] supportedLiveMediaTypes, string mediaSourceId = null, string liveStreamId = null)
{
var result = new PlaybackInfoResponse();
@@ -153,7 +162,7 @@ namespace MediaBrowser.Api.Playback
IEnumerable<MediaSourceInfo> mediaSources;
try
{
- mediaSources = await _mediaSourceManager.GetPlayackMediaSources(id, userId, true, CancellationToken.None).ConfigureAwait(false);
+ mediaSources = await _mediaSourceManager.GetPlayackMediaSources(id, userId, true, supportedLiveMediaTypes, CancellationToken.None).ConfigureAwait(false);
}
catch (PlaybackException ex)
{
@@ -223,7 +232,7 @@ namespace MediaBrowser.Api.Playback
int? subtitleStreamIndex,
string playSessionId)
{
- var streamBuilder = new StreamBuilder();
+ var streamBuilder = new StreamBuilder(Logger);
var options = new VideoOptions
{
@@ -231,8 +240,7 @@ namespace MediaBrowser.Api.Playback
Context = EncodingContext.Streaming,
DeviceId = auth.DeviceId,
ItemId = item.Id.ToString("N"),
- Profile = profile,
- MaxBitrate = maxBitrate
+ Profile = profile
};
if (string.Equals(mediaSourceId, mediaSource.Id, StringComparison.OrdinalIgnoreCase))
@@ -248,6 +256,7 @@ namespace MediaBrowser.Api.Playback
// Dummy this up to fool StreamBuilder
mediaSource.SupportsDirectStream = true;
+ options.MaxBitrate = maxBitrate;
// The MediaSource supports direct stream, now test to see if the client supports it
var streamInfo = string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase) ?
@@ -270,6 +279,8 @@ namespace MediaBrowser.Api.Playback
if (mediaSource.SupportsDirectStream)
{
+ options.MaxBitrate = GetMaxBitrate(maxBitrate);
+
// The MediaSource supports direct stream, now test to see if the client supports it
var streamInfo = string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase) ?
streamBuilder.BuildAudioItem(options) :
@@ -288,6 +299,8 @@ namespace MediaBrowser.Api.Playback
if (mediaSource.SupportsTranscoding)
{
+ options.MaxBitrate = GetMaxBitrate(maxBitrate);
+
// The MediaSource supports direct stream, now test to see if the client supports it
var streamInfo = string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase) ?
streamBuilder.BuildAudioItem(options) :
@@ -309,6 +322,18 @@ namespace MediaBrowser.Api.Playback
}
}
+ private int? GetMaxBitrate(int? clientMaxBitrate)
+ {
+ var maxBitrate = clientMaxBitrate;
+
+ if (_config.Configuration.RemoteClientBitrateLimit > 0 && !_networkManager.IsInLocalNetwork(Request.RemoteIp))
+ {
+ maxBitrate = Math.Min(maxBitrate ?? _config.Configuration.RemoteClientBitrateLimit, _config.Configuration.RemoteClientBitrateLimit);
+ }
+
+ return maxBitrate;
+ }
+
private void SetDeviceSpecificSubtitleInfo(StreamInfo info, MediaSourceInfo mediaSource, string accessToken)
{
var profiles = info.GetSubtitleProfiles(false, "-", accessToken);
diff --git a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
index 4a51f8644..6a3443f35 100644
--- a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
+++ b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
@@ -63,6 +63,13 @@ namespace MediaBrowser.Api.Playback.Progressive
new ProgressiveFileCopier(_fileSystem, _job)
.StreamFile(Path, responseStream);
}
+ catch (IOException)
+ {
+ // These error are always the same so don't dump the whole stack trace
+ Logger.Error("Error streaming media. The client has most likely disconnected or transcoding has failed.");
+
+ throw;
+ }
catch (Exception ex)
{
Logger.ErrorException("Error streaming media. The client has most likely disconnected or transcoding has failed.", ex);
diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
index 540c39a0c..0ded108b1 100644
--- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
@@ -5,7 +5,6 @@ using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.IO;
using ServiceStack;
diff --git a/MediaBrowser.Api/Playback/TranscodingThrottler.cs b/MediaBrowser.Api/Playback/TranscodingThrottler.cs
index ff79bb48f..ece455009 100644
--- a/MediaBrowser.Api/Playback/TranscodingThrottler.cs
+++ b/MediaBrowser.Api/Playback/TranscodingThrottler.cs
@@ -42,7 +42,7 @@ namespace MediaBrowser.Api.Playback
var options = GetOptions();
- if (/*options.EnableThrottling &&*/ IsThrottleAllowed(_job, options.ThrottleThresholdSeconds))
+ if (options.EnableThrottling && IsThrottleAllowed(_job, options.ThrottleThresholdSeconds))
{
PauseTranscoding();
}
@@ -70,7 +70,7 @@ namespace MediaBrowser.Api.Playback
}
}
- private void UnpauseTranscoding()
+ public void UnpauseTranscoding()
{
if (_isPaused)
{
diff --git a/MediaBrowser.Api/Session/SessionsService.cs b/MediaBrowser.Api/Session/SessionsService.cs
index 52ecb95ec..d4ea6a0eb 100644
--- a/MediaBrowser.Api/Session/SessionsService.cs
+++ b/MediaBrowser.Api/Session/SessionsService.cs
@@ -383,12 +383,12 @@ namespace MediaBrowser.Api.Session
if (!user.Policy.EnableRemoteControlOfOtherUsers)
{
- result = result.Where(i => i.ContainsUser(request.ControllableByUserId.Value));
+ result = result.Where(i => !i.UserId.HasValue || i.ContainsUser(request.ControllableByUserId.Value));
}
if (!user.Policy.EnableSharedDeviceControl)
{
- result = result.Where(i => !i.UserId.HasValue);
+ result = result.Where(i => i.UserId.HasValue);
}
result = result.Where(i =>
diff --git a/MediaBrowser.Api/SimilarItemsHelper.cs b/MediaBrowser.Api/SimilarItemsHelper.cs
index e061c391a..fb04dd030 100644
--- a/MediaBrowser.Api/SimilarItemsHelper.cs
+++ b/MediaBrowser.Api/SimilarItemsHelper.cs
@@ -170,7 +170,7 @@ namespace MediaBrowser.Api
points += item1.Studios.Where(i => item2.Studios.Contains(i, StringComparer.OrdinalIgnoreCase)).Sum(i => 3);
var item2PeopleNames = item2.People.Select(i => i.Name)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
points += item1.People.Where(i => item2PeopleNames.ContainsKey(i.Name)).Sum(i =>
diff --git a/MediaBrowser.Api/Subtitles/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs
index 73589d677..a70118d3c 100644
--- a/MediaBrowser.Api/Subtitles/SubtitleService.cs
+++ b/MediaBrowser.Api/Subtitles/SubtitleService.cs
@@ -136,11 +136,11 @@ namespace MediaBrowser.Api.Subtitles
_providerManager = providerManager;
}
- public object Get(GetSubtitlePlaylist request)
+ public async Task<object> Get(GetSubtitlePlaylist request)
{
var item = (Video)_libraryManager.GetItemById(new Guid(request.Id));
- var mediaSource = _mediaSourceManager.GetStaticMediaSource(item, request.MediaSourceId, false);
+ var mediaSource = await _mediaSourceManager.GetMediaSource(item, request.MediaSourceId, false).ConfigureAwait(false);
var builder = new StringBuilder();
diff --git a/MediaBrowser.Api/Sync/SyncService.cs b/MediaBrowser.Api/Sync/SyncService.cs
index bcadb4c08..d5f88e6a4 100644
--- a/MediaBrowser.Api/Sync/SyncService.cs
+++ b/MediaBrowser.Api/Sync/SyncService.cs
@@ -65,6 +65,16 @@ namespace MediaBrowser.Api.Sync
public string Id { get; set; }
}
+ [Route("/Sync/{TargetId}/Items", "DELETE", Summary = "Cancels items from a sync target")]
+ public class CancelItems : IReturnVoid
+ {
+ [ApiMember(Name = "TargetId", Description = "TargetId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "Items")]
+ public string TargetId { get; set; }
+
+ [ApiMember(Name = "ItemIds", Description = "ItemIds", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "Items")]
+ public string ItemIds { get; set; }
+ }
+
[Route("/Sync/Jobs", "GET", Summary = "Gets sync jobs.")]
public class GetSyncJobs : SyncJobQuery, IReturn<QueryResult<SyncJob>>
{
@@ -200,6 +210,15 @@ namespace MediaBrowser.Api.Sync
return ToOptimizedResult(result);
}
+ public void Delete(CancelItems request)
+ {
+ var itemIds = request.ItemIds.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+
+ var task = _syncManager.CancelItems(request.TargetId, itemIds);
+
+ Task.WaitAll(task);
+ }
+
public void Post(ReportSyncJobItemTransferred request)
{
var task = _syncManager.ReportSyncJobItemTransferred(request.Id);
@@ -229,6 +248,9 @@ namespace MediaBrowser.Api.Sync
result.Targets = _syncManager.GetSyncTargets(request.UserId)
.ToList();
+ var auth = AuthorizationContext.GetAuthorizationInfo(Request);
+ var authenticatedUser = _userManager.GetUserById(auth.UserId);
+
if (!string.IsNullOrWhiteSpace(request.TargetId))
{
result.Targets = result.Targets
@@ -236,11 +258,11 @@ namespace MediaBrowser.Api.Sync
.ToList();
result.QualityOptions = _syncManager
- .GetQualityOptions(request.TargetId)
+ .GetQualityOptions(request.TargetId, authenticatedUser)
.ToList();
result.ProfileOptions = _syncManager
- .GetProfileOptions(request.TargetId)
+ .GetProfileOptions(request.TargetId, authenticatedUser)
.ToList();
}
@@ -258,10 +280,6 @@ namespace MediaBrowser.Api.Sync
}
};
- var auth = AuthorizationContext.GetAuthorizationInfo(Request);
-
- var authenticatedUser = _userManager.GetUserById(auth.UserId);
-
var items = request.ItemIds.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(_libraryManager.GetItemById)
.Where(i => i != null);
diff --git a/MediaBrowser.Api/UserLibrary/ArtistsService.cs b/MediaBrowser.Api/UserLibrary/ArtistsService.cs
index dd9825deb..9f3f17465 100644
--- a/MediaBrowser.Api/UserLibrary/ArtistsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ArtistsService.cs
@@ -132,7 +132,7 @@ namespace MediaBrowser.Api.UserLibrary
.Where(i => !i.IsFolder)
.OfType<IHasAlbumArtist>()
.SelectMany(i => i.AlbumArtists)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.Select(name =>
{
try
@@ -152,7 +152,7 @@ namespace MediaBrowser.Api.UserLibrary
.Where(i => !i.IsFolder)
.OfType<IHasArtist>()
.SelectMany(i => i.AllArtists)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.Select(name =>
{
try
diff --git a/MediaBrowser.Api/UserLibrary/GameGenresService.cs b/MediaBrowser.Api/UserLibrary/GameGenresService.cs
index 3063e19c7..2f7430d33 100644
--- a/MediaBrowser.Api/UserLibrary/GameGenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/GameGenresService.cs
@@ -105,7 +105,7 @@ namespace MediaBrowser.Api.UserLibrary
return itemsList
.SelectMany(i => i.Genres)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.Select(name => LibraryManager.GetGameGenre(name));
}
}
diff --git a/MediaBrowser.Api/UserLibrary/GenresService.cs b/MediaBrowser.Api/UserLibrary/GenresService.cs
index c659852de..63c0575bf 100644
--- a/MediaBrowser.Api/UserLibrary/GenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/GenresService.cs
@@ -108,7 +108,7 @@ namespace MediaBrowser.Api.UserLibrary
{
return items
.SelectMany(i => i.Genres)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.Select(name =>
{
try
diff --git a/MediaBrowser.Api/UserLibrary/MusicGenresService.cs b/MediaBrowser.Api/UserLibrary/MusicGenresService.cs
index 3733128f0..1fe9dfaaa 100644
--- a/MediaBrowser.Api/UserLibrary/MusicGenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/MusicGenresService.cs
@@ -105,7 +105,7 @@ namespace MediaBrowser.Api.UserLibrary
return itemsList
.SelectMany(i => i.Genres)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.Select(name => LibraryManager.GetMusicGenre(name));
}
}
diff --git a/MediaBrowser.Api/UserLibrary/PersonsService.cs b/MediaBrowser.Api/UserLibrary/PersonsService.cs
index e9b3fa402..08ee6e462 100644
--- a/MediaBrowser.Api/UserLibrary/PersonsService.cs
+++ b/MediaBrowser.Api/UserLibrary/PersonsService.cs
@@ -127,7 +127,7 @@ namespace MediaBrowser.Api.UserLibrary
return allPeople
.Select(i => i.Name)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.Select(name =>
{
diff --git a/MediaBrowser.Api/UserLibrary/PlaystateService.cs b/MediaBrowser.Api/UserLibrary/PlaystateService.cs
index 6c767596e..f66f307db 100644
--- a/MediaBrowser.Api/UserLibrary/PlaystateService.cs
+++ b/MediaBrowser.Api/UserLibrary/PlaystateService.cs
@@ -67,6 +67,13 @@ namespace MediaBrowser.Api.UserLibrary
{
}
+ [Route("/Sessions/Playing/Ping", "POST", Summary = "Pings a playback session")]
+ public class PingPlaybackSession : IReturnVoid
+ {
+ [ApiMember(Name = "PlaySessionId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
+ public string PlaySessionId { get; set; }
+ }
+
[Route("/Sessions/Playing/Stopped", "POST", Summary = "Reports playback has stopped within a session")]
public class ReportPlaybackStopped : PlaybackStopInfo, IReturnVoid
{
@@ -114,6 +121,15 @@ namespace MediaBrowser.Api.UserLibrary
[ApiMember(Name = "SubtitleStreamIndex", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")]
public int? SubtitleStreamIndex { get; set; }
+
+ [ApiMember(Name = "PlayMethod", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
+ public PlayMethod PlayMethod { get; set; }
+
+ [ApiMember(Name = "LiveStreamId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
+ public string LiveStreamId { get; set; }
+
+ [ApiMember(Name = "PlaySessionId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
+ public string PlaySessionId { get; set; }
}
/// <summary>
@@ -160,6 +176,15 @@ namespace MediaBrowser.Api.UserLibrary
[ApiMember(Name = "VolumeLevel", Description = "Scale of 0-100", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")]
public int? VolumeLevel { get; set; }
+
+ [ApiMember(Name = "PlayMethod", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
+ public PlayMethod PlayMethod { get; set; }
+
+ [ApiMember(Name = "LiveStreamId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
+ public string LiveStreamId { get; set; }
+
+ [ApiMember(Name = "PlaySessionId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
+ public string PlaySessionId { get; set; }
}
/// <summary>
@@ -191,6 +216,12 @@ namespace MediaBrowser.Api.UserLibrary
/// <value>The position ticks.</value>
[ApiMember(Name = "PositionTicks", Description = "Optional. The position, in ticks, where playback stopped. 1 tick = 10000 ms", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "DELETE")]
public long? PositionTicks { get; set; }
+
+ [ApiMember(Name = "LiveStreamId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
+ public string LiveStreamId { get; set; }
+
+ [ApiMember(Name = "PlaySessionId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
+ public string PlaySessionId { get; set; }
}
[Authenticated]
@@ -260,7 +291,10 @@ namespace MediaBrowser.Api.UserLibrary
QueueableMediaTypes = queueableMediaTypes.Split(',').ToList(),
MediaSourceId = request.MediaSourceId,
AudioStreamIndex = request.AudioStreamIndex,
- SubtitleStreamIndex = request.SubtitleStreamIndex
+ SubtitleStreamIndex = request.SubtitleStreamIndex,
+ PlayMethod = request.PlayMethod,
+ PlaySessionId = request.PlaySessionId,
+ LiveStreamId = request.LiveStreamId
});
}
@@ -288,7 +322,10 @@ namespace MediaBrowser.Api.UserLibrary
MediaSourceId = request.MediaSourceId,
AudioStreamIndex = request.AudioStreamIndex,
SubtitleStreamIndex = request.SubtitleStreamIndex,
- VolumeLevel = request.VolumeLevel
+ VolumeLevel = request.VolumeLevel,
+ PlayMethod = request.PlayMethod,
+ PlaySessionId = request.PlaySessionId,
+ LiveStreamId = request.LiveStreamId
});
}
@@ -296,7 +333,7 @@ namespace MediaBrowser.Api.UserLibrary
{
if (!string.IsNullOrWhiteSpace(request.PlaySessionId))
{
- ApiEntryPoint.Instance.PingTranscodingJob(AuthorizationContext.GetAuthorizationInfo(Request).DeviceId, request.PlaySessionId);
+ ApiEntryPoint.Instance.PingTranscodingJob(request.PlaySessionId);
}
request.SessionId = GetSession().Result.Id;
@@ -306,6 +343,11 @@ namespace MediaBrowser.Api.UserLibrary
Task.WaitAll(task);
}
+ public void Post(PingPlaybackSession request)
+ {
+ ApiEntryPoint.Instance.PingTranscodingJob(request.PlaySessionId);
+ }
+
/// <summary>
/// Posts the specified request.
/// </summary>
@@ -316,7 +358,9 @@ namespace MediaBrowser.Api.UserLibrary
{
ItemId = request.Id,
PositionTicks = request.PositionTicks,
- MediaSourceId = request.MediaSourceId
+ MediaSourceId = request.MediaSourceId,
+ PlaySessionId = request.PlaySessionId,
+ LiveStreamId = request.LiveStreamId
});
}
diff --git a/MediaBrowser.Api/UserLibrary/StudiosService.cs b/MediaBrowser.Api/UserLibrary/StudiosService.cs
index a4ebef684..ae1da0346 100644
--- a/MediaBrowser.Api/UserLibrary/StudiosService.cs
+++ b/MediaBrowser.Api/UserLibrary/StudiosService.cs
@@ -109,7 +109,7 @@ namespace MediaBrowser.Api.UserLibrary
return itemsList
.SelectMany(i => i.Studios)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.Select(name => LibraryManager.GetStudio(name));
}
}
diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
index 38eae2577..aa6e227d8 100644
--- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
+++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
@@ -38,20 +38,6 @@ namespace MediaBrowser.Api.UserLibrary
public string Id { get; set; }
}
- [Route("/Users/{UserId}/Views", "GET")]
- public class GetUserViews : IReturn<QueryResult<BaseItemDto>>
- {
- /// <summary>
- /// Gets or sets the user id.
- /// </summary>
- /// <value>The user id.</value>
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string UserId { get; set; }
-
- [ApiMember(Name = "IncludeExternalContent", Description = "Whether or not to include external views such as channels or live tv", IsRequired = true, DataType = "boolean", ParameterType = "query", Verb = "POST")]
- public bool? IncludeExternalContent { get; set; }
- }
-
/// <summary>
/// Class GetItem
/// </summary>
@@ -345,37 +331,6 @@ namespace MediaBrowser.Api.UserLibrary
return ToOptimizedResult(dtos.ToList());
}
- public async Task<object> Get(GetUserViews request)
- {
- var user = _userManager.GetUserById(request.UserId);
-
- var query = new UserViewQuery
- {
- UserId = request.UserId
-
- };
-
- if (request.IncludeExternalContent.HasValue)
- {
- query.IncludeExternalContent = request.IncludeExternalContent.Value;
- }
-
- var folders = await _userViewManager.GetUserViews(query, CancellationToken.None).ConfigureAwait(false);
-
- var dtoOptions = GetDtoOptions(request);
-
- var dtos = folders.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
- .ToArray();
-
- var result = new QueryResult<BaseItemDto>
- {
- Items = dtos,
- TotalRecordCount = dtos.Length
- };
-
- return ToOptimizedResult(result);
- }
-
private List<BaseItemDto> GetAsync(GetSpecialFeatures request)
{
var user = _userManager.GetUserById(request.UserId);
diff --git a/MediaBrowser.Api/UserLibrary/UserViewsService.cs b/MediaBrowser.Api/UserLibrary/UserViewsService.cs
new file mode 100644
index 000000000..43d8dbc16
--- /dev/null
+++ b/MediaBrowser.Api/UserLibrary/UserViewsService.cs
@@ -0,0 +1,121 @@
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Library;
+using MediaBrowser.Model.Querying;
+using ServiceStack;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Api.UserLibrary
+{
+ [Route("/Users/{UserId}/Views", "GET")]
+ public class GetUserViews : IReturn<QueryResult<BaseItemDto>>
+ {
+ /// <summary>
+ /// Gets or sets the user id.
+ /// </summary>
+ /// <value>The user id.</value>
+ [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string UserId { get; set; }
+
+ [ApiMember(Name = "IncludeExternalContent", Description = "Whether or not to include external views such as channels or live tv", IsRequired = true, DataType = "boolean", ParameterType = "query", Verb = "POST")]
+ public bool? IncludeExternalContent { get; set; }
+ }
+
+ [Route("/Users/{UserId}/SpecialViewOptions", "GET")]
+ public class GetSpecialViewOptions : IReturn<List<SpecialViewOption>>
+ {
+ /// <summary>
+ /// Gets or sets the user id.
+ /// </summary>
+ /// <value>The user id.</value>
+ [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string UserId { get; set; }
+ }
+
+ public class UserViewsService : BaseApiService
+ {
+ private readonly IUserManager _userManager;
+ private readonly IUserViewManager _userViewManager;
+ private readonly IDtoService _dtoService;
+
+ public UserViewsService(IUserManager userManager, IUserViewManager userViewManager, IDtoService dtoService)
+ {
+ _userManager = userManager;
+ _userViewManager = userViewManager;
+ _dtoService = dtoService;
+ }
+
+ public async Task<object> Get(GetUserViews request)
+ {
+ var query = new UserViewQuery
+ {
+ UserId = request.UserId
+ };
+
+ if (request.IncludeExternalContent.HasValue)
+ {
+ query.IncludeExternalContent = request.IncludeExternalContent.Value;
+ }
+
+ var folders = await _userViewManager.GetUserViews(query, CancellationToken.None).ConfigureAwait(false);
+
+ var dtoOptions = GetDtoOptions(request);
+
+ var user = _userManager.GetUserById(request.UserId);
+
+ var dtos = folders.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
+ .ToArray();
+
+ var result = new QueryResult<BaseItemDto>
+ {
+ Items = dtos,
+ TotalRecordCount = dtos.Length
+ };
+
+ return ToOptimizedResult(result);
+ }
+
+ public async Task<object> Get(GetSpecialViewOptions request)
+ {
+ var user = _userManager.GetUserById(request.UserId);
+
+ var views = user.RootFolder
+ .GetChildren(user, true)
+ .OfType<ICollectionFolder>()
+ .Where(i => IsEligibleForSpecialView(i))
+ .ToList();
+
+ var list = views
+ .Select(i => new SpecialViewOption
+ {
+ Name = i.Name,
+ Id = i.Id.ToString("N")
+
+ })
+ .OrderBy(i => i.Name)
+ .ToList();
+
+ return ToOptimizedResult(list);
+ }
+
+ private bool IsEligibleForSpecialView(ICollectionFolder view)
+ {
+ var types = new[] { CollectionType.Movies, CollectionType.TvShows, CollectionType.Games, CollectionType.Music, CollectionType.Photos };
+
+ return types.Contains(view.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
+ }
+ }
+
+ class SpecialViewOption
+ {
+ public string Name { get; set; }
+ public string Id { get; set; }
+ }
+}
diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
index bc1b0e785..70ed5c319 100644
--- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
+++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
@@ -102,12 +102,6 @@ namespace MediaBrowser.Common.Implementations
public List<string> FailedAssemblies { get; protected set; }
/// <summary>
- /// Gets all types within all running assemblies
- /// </summary>
- /// <value>All types.</value>
- public Type[] AllTypes { get; protected set; }
-
- /// <summary>
/// Gets all concrete types.
/// </summary>
/// <value>All concrete types.</value>
@@ -438,9 +432,10 @@ namespace MediaBrowser.Common.Implementations
Logger.Info("Loading {0}", assembly.FullName);
}
- AllTypes = assemblies.SelectMany(GetTypes).ToArray();
-
- AllConcreteTypes = AllTypes.Where(t => t.IsClass && !t.IsAbstract && !t.IsInterface && !t.IsGenericType).ToArray();
+ AllConcreteTypes = assemblies
+ .SelectMany(GetTypes)
+ .Where(t => t.IsClass && !t.IsAbstract && !t.IsInterface && !t.IsGenericType)
+ .ToArray();
}
/// <summary>
diff --git a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs
index 1762ed575..0fd4e2787 100644
--- a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs
+++ b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs
@@ -172,11 +172,11 @@ namespace MediaBrowser.Common.Implementations.Networking
Uri uri;
if (Uri.TryCreate(endpoint, UriKind.RelativeOrAbsolute, out uri))
{
- var host = uri.DnsSafeHost;
- Logger.Debug("Resolving host {0}", host);
-
try
{
+ var host = uri.DnsSafeHost;
+ Logger.Debug("Resolving host {0}", host);
+
address = GetIpAddresses(host).FirstOrDefault();
if (address != null)
@@ -186,9 +186,13 @@ namespace MediaBrowser.Common.Implementations.Networking
return IsInLocalNetworkInternal(address.ToString(), false);
}
}
+ catch (InvalidOperationException)
+ {
+ // Can happen with reverse proxy or IIS url rewriting
+ }
catch (Exception ex)
{
- Logger.ErrorException("Error resovling hostname {0}", ex, host);
+ Logger.ErrorException("Error resovling hostname", ex);
}
}
}
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
index 78dcea493..c2551731f 100644
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
+++ b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
@@ -121,12 +121,12 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
{
if (_lastExecutionResult == null)
{
+ var path = GetHistoryFilePath();
+
lock (_lastExecutionResultSyncLock)
{
if (_lastExecutionResult == null)
{
- var path = GetHistoryFilePath();
-
try
{
return JsonSerializer.DeserializeFromFile<TaskResult>(path);
@@ -152,6 +152,14 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
private set
{
_lastExecutionResult = value;
+
+ var path = GetHistoryFilePath();
+ Directory.CreateDirectory(Path.GetDirectoryName(path));
+
+ lock (_lastExecutionResultSyncLock)
+ {
+ JsonSerializer.SerializeToFile(value, path);
+ }
}
}
@@ -582,11 +590,6 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
result.LongErrorMessage = ex.StackTrace;
}
- var path = GetHistoryFilePath();
- Directory.CreateDirectory(Path.GetDirectoryName(path));
-
- JsonSerializer.SerializeToFile(result, path);
-
LastExecutionResult = result;
((TaskManager)TaskManager).OnTaskCompleted(this, result);
diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs
index f746d87ff..f0328a1d8 100644
--- a/MediaBrowser.Controller/Channels/Channel.cs
+++ b/MediaBrowser.Controller/Channels/Channel.cs
@@ -14,11 +14,21 @@ namespace MediaBrowser.Controller.Channels
public override bool IsVisible(User user)
{
- if (!user.Policy.EnableAllChannels && !user.Policy.EnabledChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
+ if (user.Policy.BlockedChannels != null)
{
- return false;
+ if (user.Policy.BlockedChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
+ {
+ return false;
+ }
}
-
+ else
+ {
+ if (!user.Policy.EnableAllChannels && !user.Policy.EnabledChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+ }
+
return base.IsVisible(user);
}
diff --git a/MediaBrowser.Controller/Channels/ChannelAudioItem.cs b/MediaBrowser.Controller/Channels/ChannelAudioItem.cs
index 8d9024676..82fe66c7b 100644
--- a/MediaBrowser.Controller/Channels/ChannelAudioItem.cs
+++ b/MediaBrowser.Controller/Channels/ChannelAudioItem.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Model.Channels;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dto;
@@ -100,5 +101,10 @@ namespace MediaBrowser.Controller.Channels
{
return false;
}
+
+ public override bool IsVisibleStandalone(User user)
+ {
+ return IsVisibleStandaloneInternal(user, false) && ChannelVideoItem.IsChannelVisible(this, user);
+ }
}
}
diff --git a/MediaBrowser.Controller/Channels/ChannelFolderItem.cs b/MediaBrowser.Controller/Channels/ChannelFolderItem.cs
index 7ba73d126..641d37161 100644
--- a/MediaBrowser.Controller/Channels/ChannelFolderItem.cs
+++ b/MediaBrowser.Controller/Channels/ChannelFolderItem.cs
@@ -80,5 +80,10 @@ namespace MediaBrowser.Controller.Channels
{
return false;
}
+
+ public override bool IsVisibleStandalone(User user)
+ {
+ return IsVisibleStandaloneInternal(user, false) && ChannelVideoItem.IsChannelVisible(this, user);
+ }
}
}
diff --git a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs
index 8eec2021b..ef3cc7cba 100644
--- a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs
+++ b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs
@@ -130,5 +130,17 @@ namespace MediaBrowser.Controller.Channels
{
return false;
}
+
+ public override bool IsVisibleStandalone(User user)
+ {
+ return IsVisibleStandaloneInternal(user, false) && IsChannelVisible(this, user);
+ }
+
+ internal static bool IsChannelVisible(IChannelItem item, User user)
+ {
+ var channel = ChannelManager.GetChannel(item.ChannelId);
+
+ return channel.IsVisible(user);
+ }
}
}
diff --git a/MediaBrowser.Controller/Connect/IConnectManager.cs b/MediaBrowser.Controller/Connect/IConnectManager.cs
index 7eecf6ebf..1f7652221 100644
--- a/MediaBrowser.Controller/Connect/IConnectManager.cs
+++ b/MediaBrowser.Controller/Connect/IConnectManager.cs
@@ -42,6 +42,13 @@ namespace MediaBrowser.Controller.Connect
Task<List<ConnectAuthorization>> GetPendingGuests();
/// <summary>
+ /// Gets the user from exchange token.
+ /// </summary>
+ /// <param name="token">The token.</param>
+ /// <returns>User.</returns>
+ User GetUserFromExchangeToken(string token);
+
+ /// <summary>
/// Cancels the authorization.
/// </summary>
/// <param name="id">The identifier.</param>
diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
index 6fafc2b46..685d2706d 100644
--- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs
+++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
@@ -14,6 +14,12 @@ namespace MediaBrowser.Controller.Drawing
public interface IImageProcessor
{
/// <summary>
+ /// Gets the supported input formats.
+ /// </summary>
+ /// <value>The supported input formats.</value>
+ string[] SupportedInputFormats { get; }
+
+ /// <summary>
/// Gets the image enhancers.
/// </summary>
/// <value>The image enhancers.</value>
@@ -93,5 +99,11 @@ namespace MediaBrowser.Controller.Drawing
/// </summary>
/// <returns>ImageOutputFormat[].</returns>
ImageFormat[] GetSupportedImageOutputFormats();
+
+ /// <summary>
+ /// Creates the image collage.
+ /// </summary>
+ /// <param name="options">The options.</param>
+ void CreateImageCollage(ImageCollageOptions options);
}
}
diff --git a/MediaBrowser.Controller/Drawing/ImageCollageOptions.cs b/MediaBrowser.Controller/Drawing/ImageCollageOptions.cs
new file mode 100644
index 000000000..edc4f8558
--- /dev/null
+++ b/MediaBrowser.Controller/Drawing/ImageCollageOptions.cs
@@ -0,0 +1,32 @@
+
+namespace MediaBrowser.Controller.Drawing
+{
+ public class ImageCollageOptions
+ {
+ /// <summary>
+ /// Gets or sets the input paths.
+ /// </summary>
+ /// <value>The input paths.</value>
+ public string[] InputPaths { 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 width.
+ /// </summary>
+ /// <value>The width.</value>
+ public int Width { get; set; }
+ /// <summary>
+ /// Gets or sets the height.
+ /// </summary>
+ /// <value>The height.</value>
+ public int Height { get; set; }
+ /// <summary>
+ /// Gets or sets the text.
+ /// </summary>
+ /// <value>The text.</value>
+ public string Text { get; set; }
+ }
+}
diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs
index ea311d993..5ec8f274b 100644
--- a/MediaBrowser.Controller/Dto/IDtoService.cs
+++ b/MediaBrowser.Controller/Dto/IDtoService.cs
@@ -36,6 +36,14 @@ namespace MediaBrowser.Controller.Dto
BaseItemDto GetBaseItemDto(BaseItem item, List<ItemFields> fields, User user = null, BaseItem owner = null);
/// <summary>
+ /// Fills the synchronize information.
+ /// </summary>
+ /// <param name="dtos">The dtos.</param>
+ /// <param name="options">The options.</param>
+ /// <param name="user">The user.</param>
+ void FillSyncInfo(IEnumerable<IHasSyncInfo> dtos, DtoOptions options, User user);
+
+ /// <summary>
/// Gets the base item dto.
/// </summary>
/// <param name="item">The item.</param>
diff --git a/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs b/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs
index 56921409a..254f90376 100644
--- a/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs
@@ -1,6 +1,5 @@
-using System;
+using MediaBrowser.Controller.Library;
using System.Collections.Generic;
-using System.Linq;
namespace MediaBrowser.Controller.Entities.Audio
{
@@ -20,11 +19,11 @@ namespace MediaBrowser.Controller.Entities.Audio
{
public static bool HasArtist(this IHasArtist hasArtist, string artist)
{
- return hasArtist.Artists.Contains(artist, StringComparer.OrdinalIgnoreCase);
+ return NameExtensions.EqualsAny(hasArtist.Artists, artist);
}
public static bool HasAnyArtist(this IHasArtist hasArtist, string artist)
{
- return hasArtist.AllArtists.Contains(artist, StringComparer.OrdinalIgnoreCase);
+ return NameExtensions.EqualsAny(hasArtist.AllArtists, artist);
}
}
}
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 94fc76125..22efd3fba 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -17,6 +17,7 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Users;
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
@@ -44,7 +45,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// The supported image extensions
/// </summary>
- public static readonly string[] SupportedImageExtensions = { ".png", ".jpg", ".jpeg", ".tbn" };
+ public static readonly string[] SupportedImageExtensions = { ".png", ".jpg", ".jpeg" };
public static readonly List<string> SupportedImageExtensionsList = SupportedImageExtensions.ToList();
@@ -1144,6 +1145,11 @@ namespace MediaBrowser.Controller.Entities
public virtual bool IsVisibleStandalone(User user)
{
+ return IsVisibleStandaloneInternal(user, true);
+ }
+
+ protected bool IsVisibleStandaloneInternal(User user, bool checkFolders)
+ {
if (!IsVisible(user))
{
return false;
@@ -1154,7 +1160,23 @@ namespace MediaBrowser.Controller.Entities
return false;
}
- // TODO: Need some work here, e.g. is in user library, for channels, can user access channel, etc.
+ if (checkFolders)
+ {
+ var topParent = Parents.LastOrDefault() ?? this;
+
+ if (string.IsNullOrWhiteSpace(topParent.Path))
+ {
+ return true;
+ }
+
+ var userCollectionFolders = user.RootFolder.GetChildren(user, true).Select(i => i.Id).ToList();
+ var itemCollectionFolders = LibraryManager.GetCollectionFolders(this).Select(i => i.Id);
+
+ if (!itemCollectionFolders.Any(userCollectionFolders.Contains))
+ {
+ return false;
+ }
+ }
return true;
}
@@ -1490,7 +1512,6 @@ namespace MediaBrowser.Controller.Entities
image.Path = file.FullName;
image.DateModified = imageInfo.DateModified;
- image.Length = imageInfo.Length;
}
}
@@ -1511,7 +1532,7 @@ namespace MediaBrowser.Controller.Entities
}
// Remove it from the item
- ImageInfos.Remove(info);
+ RemoveImage(info);
// Delete the source file
var currentFile = new FileInfo(info.Path);
@@ -1530,6 +1551,11 @@ namespace MediaBrowser.Controller.Entities
return UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None);
}
+ public void RemoveImage(ItemImageInfo image)
+ {
+ ImageInfos.Remove(image);
+ }
+
public virtual Task UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken)
{
return LibraryManager.UpdateItem(this, updateReason, cancellationToken);
@@ -1595,14 +1621,11 @@ namespace MediaBrowser.Controller.Entities
return null;
}
- var fileInfo = new FileInfo(path);
-
return new ItemImageInfo
{
Path = path,
- DateModified = FileSystem.GetLastWriteTimeUtc(fileInfo),
- Type = imageType,
- Length = fileInfo.Length
+ DateModified = FileSystem.GetLastWriteTimeUtc(path),
+ Type = imageType
};
}
@@ -1622,7 +1645,7 @@ namespace MediaBrowser.Controller.Entities
public bool AddImages(ImageType imageType, IEnumerable<FileInfo> images)
{
- return AddImages(imageType, images.Cast<FileSystemInfo>());
+ return AddImages(imageType, images.Cast<FileSystemInfo>().ToList());
}
/// <summary>
@@ -1632,7 +1655,7 @@ namespace MediaBrowser.Controller.Entities
/// <param name="images">The images.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
/// <exception cref="System.ArgumentException">Cannot call AddImages with chapter images</exception>
- public bool AddImages(ImageType imageType, IEnumerable<FileSystemInfo> images)
+ public bool AddImages(ImageType imageType, List<FileSystemInfo> images)
{
if (imageType == ImageType.Chapter)
{
@@ -1643,6 +1666,7 @@ namespace MediaBrowser.Controller.Entities
.ToList();
var newImageList = new List<FileSystemInfo>();
+ var imageAdded = false;
foreach (var newImage in images)
{
@@ -1657,14 +1681,25 @@ namespace MediaBrowser.Controller.Entities
if (existing == null)
{
newImageList.Add(newImage);
+ imageAdded = true;
}
else
{
existing.DateModified = FileSystem.GetLastWriteTimeUtc(newImage);
- existing.Length = ((FileInfo) newImage).Length;
}
}
+ if (imageAdded || images.Count != existingImages.Count)
+ {
+ var newImagePaths = images.Select(i => i.FullName).ToList();
+
+ var deleted = existingImages
+ .Where(i => !newImagePaths.Contains(i.Path, StringComparer.OrdinalIgnoreCase) && !File.Exists(i.Path))
+ .ToList();
+
+ ImageInfos = ImageInfos.Except(deleted).ToList();
+ }
+
ImageInfos.AddRange(newImageList.Select(i => GetImageInfo(i, imageType)));
return newImageList.Count > 0;
@@ -1676,8 +1711,7 @@ namespace MediaBrowser.Controller.Entities
{
Path = file.FullName,
Type = type,
- DateModified = FileSystem.GetLastWriteTimeUtc(file),
- Length = ((FileInfo)file).Length
+ DateModified = FileSystem.GetLastWriteTimeUtc(file)
};
}
@@ -1716,15 +1750,9 @@ namespace MediaBrowser.Controller.Entities
FileSystem.SwapFiles(path1, path2);
- var file1 = new FileInfo(info1.Path);
- var file2 = new FileInfo(info2.Path);
-
// Refresh these values
- info1.DateModified = FileSystem.GetLastWriteTimeUtc(file1);
- info2.DateModified = FileSystem.GetLastWriteTimeUtc(file2);
-
- info1.Length = file1.Length;
- info2.Length = file2.Length;
+ info1.DateModified = FileSystem.GetLastWriteTimeUtc(info1.Path);
+ info2.DateModified = FileSystem.GetLastWriteTimeUtc(info2.Path);
return UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None);
}
@@ -1853,5 +1881,18 @@ namespace MediaBrowser.Controller.Entities
return video.RefreshMetadata(newOptions, cancellationToken);
}
+
+ public string GetEtag(User user)
+ {
+ return string.Join("|", GetEtagValues(user).ToArray()).GetMD5().ToString("N");
+ }
+
+ protected virtual List<string> GetEtagValues(User user)
+ {
+ return new List<string>
+ {
+ DateLastSaved.Ticks.ToString(CultureInfo.InvariantCulture)
+ };
+ }
}
}
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 14095f7ff..821e6b5ca 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -164,18 +164,22 @@ namespace MediaBrowser.Controller.Entities
protected void AddChildrenInternal(IEnumerable<BaseItem> children)
{
+ var actualChildren = ActualChildren;
+
lock (_childrenSyncLock)
{
- var newChildren = ActualChildren.ToList();
+ var newChildren = actualChildren.ToList();
newChildren.AddRange(children);
_children = newChildren;
}
}
protected void AddChildInternal(BaseItem child)
{
+ var actualChildren = ActualChildren;
+
lock (_childrenSyncLock)
{
- var newChildren = ActualChildren.ToList();
+ var newChildren = actualChildren.ToList();
newChildren.Add(child);
_children = newChildren;
}
@@ -184,10 +188,11 @@ namespace MediaBrowser.Controller.Entities
protected void RemoveChildrenInternal(IEnumerable<BaseItem> children)
{
var ids = children.Select(i => i.Id).ToList();
+ var actualChildren = ActualChildren;
lock (_childrenSyncLock)
{
- _children = ActualChildren.Where(i => !ids.Contains(i.Id)).ToList();
+ _children = actualChildren.Where(i => !ids.Contains(i.Id)).ToList();
}
}
@@ -302,7 +307,7 @@ namespace MediaBrowser.Controller.Entities
{
if (_children == null)
{
- _children = LoadChildrenInternal();
+ _children = LoadChildren().ToList();
}
}
}
@@ -334,20 +339,28 @@ namespace MediaBrowser.Controller.Entities
{
if (this is ICollectionFolder && !(this is BasePluginFolder))
{
- if (!user.Policy.EnableAllFolders && !user.Policy.EnabledFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
+ if (user.Policy.BlockedMediaFolders != null)
{
- return false;
+ if (user.Policy.BlockedMediaFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase) ||
+
+ // Backwards compatibility
+ user.Policy.BlockedMediaFolders.Contains(Name, StringComparer.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if (!user.Policy.EnableAllFolders && !user.Policy.EnabledFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
+ {
+ return false;
+ }
}
}
return base.IsVisible(user);
}
- private List<BaseItem> LoadChildrenInternal()
- {
- return LoadChildren().ToList();
- }
-
/// <summary>
/// Loads our children. Validation will occur externally.
/// We want this sychronous.
@@ -991,8 +1004,9 @@ namespace MediaBrowser.Controller.Entities
}
var locations = user.RootFolder
- .GetChildren(user, true)
+ .Children
.OfType<CollectionFolder>()
+ .Where(i => i.IsVisible(user))
.SelectMany(i => i.PhysicalLocations)
.ToList();
diff --git a/MediaBrowser.Controller/Entities/ICollectionFolder.cs b/MediaBrowser.Controller/Entities/ICollectionFolder.cs
index 656aa37ce..f46d7ed6f 100644
--- a/MediaBrowser.Controller/Entities/ICollectionFolder.cs
+++ b/MediaBrowser.Controller/Entities/ICollectionFolder.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
namespace MediaBrowser.Controller.Entities
{
@@ -9,6 +10,8 @@ namespace MediaBrowser.Controller.Entities
{
string CollectionType { get; }
string Path { get; }
+ string Name { get; }
+ Guid Id { get; }
IEnumerable<string> PhysicalLocations { get; }
}
}
diff --git a/MediaBrowser.Controller/Entities/IHasImages.cs b/MediaBrowser.Controller/Entities/IHasImages.cs
index 00a42271b..1871d7b68 100644
--- a/MediaBrowser.Controller/Entities/IHasImages.cs
+++ b/MediaBrowser.Controller/Entities/IHasImages.cs
@@ -141,7 +141,7 @@ namespace MediaBrowser.Controller.Entities
/// <param name="imageType">Type of the image.</param>
/// <param name="images">The images.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
- bool AddImages(ImageType imageType, IEnumerable<FileSystemInfo> images);
+ bool AddImages(ImageType imageType, List<FileSystemInfo> images);
/// <summary>
/// Determines whether [is save local metadata enabled].
@@ -190,6 +190,12 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <returns><c>true</c> if [is internet metadata enabled]; otherwise, <c>false</c>.</returns>
bool IsInternetMetadataEnabled();
+
+ /// <summary>
+ /// Removes the image.
+ /// </summary>
+ /// <param name="image">The image.</param>
+ void RemoveImage(ItemImageInfo image);
}
public static class HasImagesExtensions
diff --git a/MediaBrowser.Controller/Entities/ItemImageInfo.cs b/MediaBrowser.Controller/Entities/ItemImageInfo.cs
index 1122de403..b36b818ff 100644
--- a/MediaBrowser.Controller/Entities/ItemImageInfo.cs
+++ b/MediaBrowser.Controller/Entities/ItemImageInfo.cs
@@ -12,12 +12,6 @@ namespace MediaBrowser.Controller.Entities
public string Path { get; set; }
/// <summary>
- /// Gets or sets the length.
- /// </summary>
- /// <value>The length.</value>
- public long Length { get; set; }
-
- /// <summary>
/// Gets or sets the type.
/// </summary>
/// <value>The type.</value>
diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
index 0778643da..02e9d4cf9 100644
--- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
+++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
@@ -175,19 +175,19 @@ namespace MediaBrowser.Controller.Entities.Movies
public override bool IsVisible(User user)
{
- if (base.IsVisible(user))
- {
- var userId = user.Id.ToString("N");
-
- // 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;
- }
+ var userId = user.Id.ToString("N");
+ // 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 true;
}
+ if (base.IsVisible(user))
+ {
+ return GetChildren(user, true).Any();
+ }
+
return false;
}
}
diff --git a/MediaBrowser.Controller/Entities/PhotoAlbum.cs b/MediaBrowser.Controller/Entities/PhotoAlbum.cs
index 24ebf8815..5b48a70e9 100644
--- a/MediaBrowser.Controller/Entities/PhotoAlbum.cs
+++ b/MediaBrowser.Controller/Entities/PhotoAlbum.cs
@@ -1,11 +1,15 @@
-using MediaBrowser.Model.Configuration;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Users;
+using System;
using System.Linq;
using System.Runtime.Serialization;
-using MediaBrowser.Model.Users;
+using System.Threading;
+using System.Threading.Tasks;
namespace MediaBrowser.Controller.Entities
{
- public class PhotoAlbum : Folder
+ public class PhotoAlbum : Folder, IMetadataContainer
{
public override bool SupportsLocalMetadata
{
@@ -28,5 +32,31 @@ namespace MediaBrowser.Controller.Entities
{
return config.BlockUnratedItems.Contains(UnratedItem.Other);
}
+
+ public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken)
+ {
+ var items = GetRecursiveChildren().ToList();
+
+ var totalItems = items.Count;
+ var numComplete = 0;
+
+ // Refresh songs
+ foreach (var item in items)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
+
+ numComplete++;
+ double percent = numComplete;
+ percent /= totalItems;
+ progress.Report(percent * 100);
+ }
+
+ // Refresh current item
+ await RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
+
+ progress.Report(100);
+ }
}
}
diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
index 0e602dabe..1672bda92 100644
--- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs
+++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
@@ -50,6 +50,16 @@ namespace MediaBrowser.Controller.Entities
{
var user = query.User;
+ if (query.IncludeItemTypes != null &&
+ query.IncludeItemTypes.Length == 1 &&
+ string.Equals(query.IncludeItemTypes[0], "Playlist", StringComparison.OrdinalIgnoreCase))
+ {
+ if (!string.Equals(viewType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))
+ {
+ return await FindPlaylists(queryParent, user, query).ConfigureAwait(false);
+ }
+ }
+
switch (viewType)
{
case CollectionType.Channels:
@@ -107,13 +117,10 @@ namespace MediaBrowser.Controller.Entities
case CollectionType.LiveTv:
{
- var result = await GetLiveTvFolders(user).ConfigureAwait(false);
-
- return GetResult(result, queryParent, query);
+ return await GetLiveTvView(queryParent, user, query).ConfigureAwait(false);
}
case CollectionType.Books:
- case CollectionType.Photos:
case CollectionType.HomeVideos:
case CollectionType.MusicVideos:
return GetResult(queryParent.GetChildren(user, true), queryParent, query);
@@ -130,6 +137,9 @@ namespace MediaBrowser.Controller.Entities
case CollectionType.BoxSets:
return await GetBoxsetView(queryParent, user, query).ConfigureAwait(false);
+ case CollectionType.Photos:
+ return await GetPhotosView(queryParent, user, query).ConfigureAwait(false);
+
case CollectionType.TvShows:
return await GetTvView(queryParent, user, query).ConfigureAwait(false);
@@ -205,6 +215,9 @@ namespace MediaBrowser.Controller.Entities
case SpecialFolder.MusicLatest:
return GetMusicLatest(queryParent, user, query);
+ case SpecialFolder.MusicPlaylists:
+ return await GetMusicPlaylists(queryParent, user, query).ConfigureAwait(false);
+
case SpecialFolder.MusicAlbums:
return GetMusicAlbums(queryParent, user, query);
@@ -236,10 +249,29 @@ namespace MediaBrowser.Controller.Entities
return GetFavoriteSongs(queryParent, user, query);
default:
- return GetResult(GetMediaFolders(user).SelectMany(i => i.GetChildren(user, true)), queryParent, query);
+ {
+ if (queryParent is UserView)
+ {
+ return GetResult(GetMediaFolders(user).SelectMany(i => i.GetChildren(user, true)), queryParent, query);
+ }
+ else
+ {
+ return GetResult(queryParent.GetChildren(user, true), queryParent, query);
+ }
+ }
}
}
+ private async Task<QueryResult<BaseItem>> FindPlaylists(Folder parent, User user, InternalItemsQuery query)
+ {
+ var collectionFolders = user.RootFolder.GetChildren(user, true).Select(i => i.Id).ToList();
+
+ var list = _playlistManager.GetPlaylists(user.Id.ToString("N"))
+ .Where(i => i.GetChildren(user, true).Any(media => _libraryManager.GetCollectionFolders(media).Select(c => c.Id).Any(collectionFolders.Contains)));
+
+ return GetResult(list, parent, query);
+ }
+
private int GetSpecialItemsLimit()
{
return 50;
@@ -257,12 +289,13 @@ namespace MediaBrowser.Controller.Entities
var list = new List<BaseItem>();
list.Add(await GetUserView(SpecialFolder.MusicLatest, user, "0", parent).ConfigureAwait(false));
- list.Add(await GetUserView(SpecialFolder.MusicAlbums, user, "1", parent).ConfigureAwait(false));
- list.Add(await GetUserView(SpecialFolder.MusicAlbumArtists, user, "2", parent).ConfigureAwait(false));
- list.Add(await GetUserView(SpecialFolder.MusicArtists, user, "3", parent).ConfigureAwait(false));
- list.Add(await GetUserView(SpecialFolder.MusicSongs, user, "4", parent).ConfigureAwait(false));
- list.Add(await GetUserView(SpecialFolder.MusicGenres, user, "5", parent).ConfigureAwait(false));
- list.Add(await GetUserView(SpecialFolder.MusicFavorites, user, "6", parent).ConfigureAwait(false));
+ list.Add(await GetUserView(SpecialFolder.MusicPlaylists, user, "1", parent).ConfigureAwait(false));
+ list.Add(await GetUserView(SpecialFolder.MusicAlbums, user, "2", parent).ConfigureAwait(false));
+ list.Add(await GetUserView(SpecialFolder.MusicAlbumArtists, user, "3", parent).ConfigureAwait(false));
+ //list.Add(await GetUserView(SpecialFolder.MusicArtists, user, "4", parent).ConfigureAwait(false));
+ list.Add(await GetUserView(SpecialFolder.MusicSongs, user, "5", parent).ConfigureAwait(false));
+ list.Add(await GetUserView(SpecialFolder.MusicGenres, user, "6", parent).ConfigureAwait(false));
+ list.Add(await GetUserView(SpecialFolder.MusicFavorites, user, "7", parent).ConfigureAwait(false));
return GetResult(list, parent, query);
}
@@ -283,7 +316,7 @@ namespace MediaBrowser.Controller.Entities
var tasks = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos })
.Where(i => !i.IsFolder)
.SelectMany(i => i.Genres)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.Select(i =>
{
try
@@ -313,7 +346,7 @@ namespace MediaBrowser.Controller.Entities
.Where(i => i.Genres.Contains(displayParent.Name, StringComparer.OrdinalIgnoreCase))
.OfType<IHasAlbumArtist>()
.SelectMany(i => i.AlbumArtists)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.Select(i =>
{
try
@@ -337,7 +370,7 @@ namespace MediaBrowser.Controller.Entities
.Where(i => !i.IsFolder)
.OfType<IHasAlbumArtist>()
.SelectMany(i => i.AlbumArtists)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.Select(i =>
{
try
@@ -361,7 +394,7 @@ namespace MediaBrowser.Controller.Entities
.Where(i => !i.IsFolder)
.OfType<IHasArtist>()
.SelectMany(i => i.Artists)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.Select(i =>
{
try
@@ -385,7 +418,7 @@ namespace MediaBrowser.Controller.Entities
.Where(i => !i.IsFolder)
.OfType<IHasAlbumArtist>()
.SelectMany(i => i.AlbumArtists)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.Select(i =>
{
try
@@ -403,6 +436,14 @@ namespace MediaBrowser.Controller.Entities
return GetResult(artists, parent, query);
}
+ private Task<QueryResult<BaseItem>> GetMusicPlaylists(Folder parent, User user, InternalItemsQuery query)
+ {
+ query.IncludeItemTypes = new[] { "Playlist" };
+ query.Recursive = true;
+
+ return parent.GetItems(query);
+ }
+
private QueryResult<BaseItem> GetMusicAlbums(Folder parent, User user, InternalItemsQuery query)
{
var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }, i => (i is MusicAlbum) && FilterItem(i, query));
@@ -552,7 +593,7 @@ namespace MediaBrowser.Controller.Entities
var tasks = GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty })
.Where(i => i is Movie)
.SelectMany(i => i.Genres)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.Select(i =>
{
try
@@ -606,6 +647,19 @@ namespace MediaBrowser.Controller.Entities
}), parent, query);
}
+ private async Task<QueryResult<BaseItem>> GetPhotosView(Folder queryParent, User user, InternalItemsQuery query)
+ {
+ if (query.Recursive)
+ {
+ var mediaTypes = new[] { MediaType.Video, MediaType.Photo };
+ var items = GetRecursiveChildren(queryParent, user, new[] { CollectionType.Photos, string.Empty }, i => (i is PhotoAlbum || mediaTypes.Contains(i.MediaType ?? string.Empty, StringComparer.OrdinalIgnoreCase)) && FilterItem(i, query));
+
+ return PostFilterAndSort(items, queryParent, null, query);
+ }
+
+ return GetResult(queryParent.GetChildren(user, true), queryParent, query);
+ }
+
private async Task<QueryResult<BaseItem>> GetTvView(Folder parent, User user, InternalItemsQuery query)
{
if (query.Recursive)
@@ -724,7 +778,7 @@ namespace MediaBrowser.Controller.Entities
var tasks = GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty })
.OfType<Series>()
.SelectMany(i => i.Genres)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.Select(i =>
{
try
@@ -776,7 +830,7 @@ namespace MediaBrowser.Controller.Entities
var tasks = GetRecursiveChildren(parent, user, new[] { CollectionType.Games })
.OfType<Game>()
.SelectMany(i => i.Genres)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.Select(i =>
{
try
@@ -1749,17 +1803,26 @@ namespace MediaBrowser.Controller.Entities
return parent.GetRecursiveChildren(user, filter);
}
- private async Task<IEnumerable<BaseItem>> GetLiveTvFolders(User user)
+ private async Task<QueryResult<BaseItem>> GetLiveTvView(Folder queryParent, User user, InternalItemsQuery query)
{
- var list = new List<BaseItem>();
+ if (query.Recursive)
+ {
+ return await _liveTvManager.GetInternalRecordings(new RecordingQuery
+ {
+ IsInProgress = false,
+ Status = RecordingStatus.Completed,
+ UserId = user.Id.ToString("N")
- var parent = user.RootFolder;
+ }, CancellationToken.None).ConfigureAwait(false);
+ }
+
+ var list = new List<BaseItem>();
//list.Add(await GetUserSubView(SpecialFolder.LiveTvNowPlaying, user, "0", parent).ConfigureAwait(false));
- list.Add(await GetUserView(SpecialFolder.LiveTvChannels, user, string.Empty, parent).ConfigureAwait(false));
- list.Add(await GetUserView(SpecialFolder.LiveTvRecordingGroups, user, string.Empty, parent).ConfigureAwait(false));
+ list.Add(await GetUserView(SpecialFolder.LiveTvChannels, user, string.Empty, user.RootFolder).ConfigureAwait(false));
+ list.Add(await GetUserView(SpecialFolder.LiveTvRecordingGroups, user, string.Empty, user.RootFolder).ConfigureAwait(false));
- return list;
+ return GetResult(list, queryParent, query);
}
private async Task<UserView> GetUserView(string name, string type, User user, string sortName, BaseItem parent)
diff --git a/MediaBrowser.Server.Implementations/HttpServer/ThrottledStream.cs b/MediaBrowser.Controller/IO/ThrottledStream.cs
index 1c01fa9e0..1df00b45a 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/ThrottledStream.cs
+++ b/MediaBrowser.Controller/IO/ThrottledStream.cs
@@ -3,7 +3,7 @@ using System.IO;
using System.Threading;
using System.Threading.Tasks;
-namespace MediaBrowser.Server.Implementations.HttpServer
+namespace MediaBrowser.Controller.IO
{
/// <summary>
/// Class for streaming data with throttling support.
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index d16589f07..c00912115 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -309,6 +309,7 @@ namespace MediaBrowser.Controller.Library
/// <param name="parentId">The parent identifier.</param>
/// <param name="viewType">Type of the view.</param>
/// <param name="sortName">Name of the sort.</param>
+ /// <param name="uniqueId">The unique identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;UserView&gt;.</returns>
Task<UserView> GetNamedView(User user,
@@ -316,6 +317,7 @@ namespace MediaBrowser.Controller.Library
string parentId,
string viewType,
string sortName,
+ string uniqueId,
CancellationToken cancellationToken);
/// <summary>
diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs
index 5bcc5f313..a77d88049 100644
--- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs
+++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs
@@ -43,18 +43,10 @@ namespace MediaBrowser.Controller.Library
/// <param name="id">The identifier.</param>
/// <param name="userId">The user identifier.</param>
/// <param name="enablePathSubstitution">if set to <c>true</c> [enable path substitution].</param>
+ /// <param name="supportedLiveMediaTypes">The supported live media types.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>IEnumerable&lt;MediaSourceInfo&gt;.</returns>
- Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, string userId, bool enablePathSubstitution, CancellationToken cancellationToken);
-
- /// <summary>
- /// Gets the playack media sources.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <param name="enablePathSubstitution">if set to <c>true</c> [enable path substitution].</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task&lt;IEnumerable&lt;MediaSourceInfo&gt;&gt;.</returns>
- Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, bool enablePathSubstitution, CancellationToken cancellationToken);
+ Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, string userId, bool enablePathSubstitution, string[] supportedLiveMediaTypes, CancellationToken cancellationToken);
/// <summary>
/// Gets the static media sources.
@@ -64,7 +56,7 @@ namespace MediaBrowser.Controller.Library
/// <param name="user">The user.</param>
/// <returns>IEnumerable&lt;MediaSourceInfo&gt;.</returns>
IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user = null);
-
+
/// <summary>
/// Gets the static media source.
/// </summary>
@@ -72,7 +64,7 @@ namespace MediaBrowser.Controller.Library
/// <param name="mediaSourceId">The media source identifier.</param>
/// <param name="enablePathSubstitution">if set to <c>true</c> [enable path substitution].</param>
/// <returns>MediaSourceInfo.</returns>
- MediaSourceInfo GetStaticMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution);
+ Task<MediaSourceInfo> GetMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution);
/// <summary>
/// Opens the media source.
diff --git a/MediaBrowser.Controller/Library/NameExtensions.cs b/MediaBrowser.Controller/Library/NameExtensions.cs
new file mode 100644
index 000000000..6973dce64
--- /dev/null
+++ b/MediaBrowser.Controller/Library/NameExtensions.cs
@@ -0,0 +1,79 @@
+using MediaBrowser.Common.Extensions;
+using MoreLinq;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+namespace MediaBrowser.Controller.Library
+{
+ public static class NameExtensions
+ {
+ public static bool AreEqual(string x, string y)
+ {
+ if (string.IsNullOrWhiteSpace(x) && string.IsNullOrWhiteSpace(y))
+ {
+ return true;
+ }
+
+ return string.Compare(x, y, CultureInfo.InvariantCulture, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace) == 0;
+ }
+
+ public static bool EqualsAny(IEnumerable<string> names, string x)
+ {
+ x = NormalizeForComparison(x);
+
+ return names.Any(y => string.Compare(x, y, CultureInfo.InvariantCulture, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace) == 0);
+ }
+
+ private static string NormalizeForComparison(string name)
+ {
+ if (name == null)
+ {
+ return string.Empty;
+ }
+
+ return name;
+ //return name.RemoveDiacritics();
+ }
+
+ private static string RemoveDiacritics(string name)
+ {
+ if (name == null)
+ {
+ return string.Empty;
+ }
+
+ //return name;
+ return name.RemoveDiacritics();
+ }
+
+ public static IEnumerable<string> DistinctNames(this IEnumerable<string> names)
+ {
+ return names.DistinctBy(RemoveDiacritics, StringComparer.OrdinalIgnoreCase);
+ }
+ }
+
+ class TextComparer : IComparer<string>, IEqualityComparer<string>
+ {
+ public int Compare(string x, string y)
+ {
+ if (string.IsNullOrWhiteSpace(x) && string.IsNullOrWhiteSpace(y))
+ {
+ return 0;
+ }
+
+ return string.Compare(x, y, CultureInfo.InvariantCulture, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace);
+ }
+
+ public bool Equals(string x, string y)
+ {
+ return Compare(x, y) == 0;
+ }
+
+ public int GetHashCode(string obj)
+ {
+ return (obj ?? string.Empty).GetHashCode();
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
index d5b5d92a6..4ee0565f9 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
@@ -1,4 +1,5 @@
using MediaBrowser.Controller.Channels;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.LiveTv;
@@ -74,10 +75,11 @@ namespace MediaBrowser.Controller.LiveTv
/// Gets the recording.
/// </summary>
/// <param name="id">The identifier.</param>
- /// <param name="user">The user.</param>
+ /// <param name="options">The options.</param>
/// <param name="cancellationToken">The cancellation token.</param>
+ /// <param name="user">The user.</param>
/// <returns>Task{RecordingInfoDto}.</returns>
- Task<RecordingInfoDto> GetRecording(string id, CancellationToken cancellationToken, User user = null);
+ Task<RecordingInfoDto> GetRecording(string id, DtoOptions options, CancellationToken cancellationToken, User user = null);
/// <summary>
/// Gets the channel.
@@ -103,14 +105,15 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{TimerInfoDto}.</returns>
Task<SeriesTimerInfoDto> GetSeriesTimer(string id, CancellationToken cancellationToken);
-
+
/// <summary>
/// Gets the recordings.
/// </summary>
/// <param name="query">The query.</param>
+ /// <param name="options">The options.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>QueryResult{RecordingInfoDto}.</returns>
- Task<QueryResult<RecordingInfoDto>> GetRecordings(RecordingQuery query, CancellationToken cancellationToken);
+ Task<QueryResult<RecordingInfoDto>> GetRecordings(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken);
/// <summary>
/// Gets the timers.
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs
index d7e3df4e2..4ef4847a3 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs
@@ -1,10 +1,9 @@
-using System;
+using MediaBrowser.Controller.Drawing;
+using MediaBrowser.Model.Dto;
+using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Controller.Channels;
-using MediaBrowser.Controller.Drawing;
-using MediaBrowser.Model.Dto;
namespace MediaBrowser.Controller.LiveTv
{
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs b/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs
index cdf2f0ef5..46cf4dd98 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs
@@ -1,5 +1,5 @@
-using System.Collections.Generic;
-using MediaBrowser.Model.LiveTv;
+using MediaBrowser.Model.LiveTv;
+using System.Collections.Generic;
namespace MediaBrowser.Controller.LiveTv
{
@@ -24,6 +24,12 @@ namespace MediaBrowser.Controller.LiveTv
public string Id { get; set; }
/// <summary>
+ /// Gets or sets the URL.
+ /// </summary>
+ /// <value>The URL.</value>
+ public string Url { get; set; }
+
+ /// <summary>
/// Gets or sets the status.
/// </summary>
/// <value>The status.</value>
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 2fa62f79f..199f5e0d1 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -48,6 +48,9 @@
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="Interfaces.IO">
+ <HintPath>..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll</HintPath>
+ </Reference>
<Reference Include="MoreLinq, Version=1.1.17511.0, Culture=neutral, PublicKeyToken=384d532d7e88985d, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\morelinq.1.1.0\lib\net35\MoreLinq.dll</HintPath>
@@ -115,6 +118,7 @@
<Compile Include="Dlna\IMediaReceiverRegistrar.cs" />
<Compile Include="Dlna\IUpnpService.cs" />
<Compile Include="Drawing\IImageProcessor.cs" />
+ <Compile Include="Drawing\ImageCollageOptions.cs" />
<Compile Include="Drawing\ImageProcessingOptions.cs" />
<Compile Include="Drawing\ImageProcessorExtensions.cs" />
<Compile Include="Drawing\ImageStream.cs" />
@@ -171,6 +175,7 @@
<Compile Include="Entities\UserView.cs" />
<Compile Include="Entities\UserViewBuilder.cs" />
<Compile Include="FileOrganization\IFileOrganizationService.cs" />
+ <Compile Include="IO\ThrottledStream.cs" />
<Compile Include="Library\DeleteOptions.cs" />
<Compile Include="Library\ILibraryPostScanTask.cs" />
<Compile Include="Library\IMediaSourceManager.cs" />
@@ -184,6 +189,7 @@
<Compile Include="Library\IUserViewManager.cs" />
<Compile Include="Library\LibraryManagerExtensions.cs" />
<Compile Include="Library\MetadataConfigurationStore.cs" />
+ <Compile Include="Library\NameExtensions.cs" />
<Compile Include="Library\PlaybackStopEventArgs.cs" />
<Compile Include="Library\UserDataSaveEventArgs.cs" />
<Compile Include="LiveTv\ILiveTvItem.cs" />
@@ -211,8 +217,8 @@
<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\MediaInfoRequest.cs" />
<Compile Include="MediaEncoding\MediaStreamSelector.cs" />
<Compile Include="Net\AuthenticatedAttribute.cs" />
<Compile Include="Net\AuthorizationInfo.cs" />
@@ -394,6 +400,7 @@
<Compile Include="Subtitles\SubtitleResponse.cs" />
<Compile Include="Subtitles\SubtitleSearchRequest.cs" />
<Compile Include="Sync\IHasDynamicAccess.cs" />
+ <Compile Include="Sync\IRemoteSyncProvider.cs" />
<Compile Include="Sync\IServerSyncProvider.cs" />
<Compile Include="Sync\ISyncDataProvider.cs" />
<Compile Include="Sync\ISyncManager.cs" />
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
index fe0fb3295..bb8841222 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
@@ -41,6 +41,8 @@ namespace MediaBrowser.Controller.MediaEncoding
public int? SubtitleStreamIndex { get; set; }
public int? MaxRefFrames { get; set; }
public int? MaxVideoBitDepth { get; set; }
+ public int? CpuCoreLimit { get; set; }
+ public bool ReadInputAtNativeFramerate { get; set; }
public SubtitleDeliveryMethod SubtitleMethod { get; set; }
/// <summary>
diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
index 47544f972..5bec7980a 100644
--- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
+++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
@@ -63,16 +63,14 @@ namespace MediaBrowser.Controller.MediaEncoding
string filenamePrefix,
int? maxWidth,
CancellationToken cancellationToken);
-
+
/// <summary>
/// Gets the media info.
/// </summary>
- /// <param name="inputFiles">The input files.</param>
- /// <param name="protocol">The protocol.</param>
- /// <param name="isAudio">if set to <c>true</c> [is audio].</param>
+ /// <param name="request">The request.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- Task<InternalMediaInfoResult> GetMediaInfo(string[] inputFiles, MediaProtocol protocol, bool isAudio, CancellationToken cancellationToken);
+ Task<MediaInfo> GetMediaInfo(MediaInfoRequest request, CancellationToken cancellationToken);
/// <summary>
/// Gets the probe size argument.
diff --git a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
index 530c127da..da9dd4dfd 100644
--- a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
+++ b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
@@ -1,9 +1,7 @@
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
+using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
using System;
using System.Collections.Generic;
-using System.Globalization;
using System.IO;
using System.Linq;
@@ -46,291 +44,5 @@ namespace MediaBrowser.Controller.MediaEncoding
.Where(f => !string.IsNullOrEmpty(f))
.ToList();
}
-
- public static MediaInfo GetMediaInfo(InternalMediaInfoResult data)
- {
- var internalStreams = data.streams ?? new MediaStreamInfo[] { };
-
- var info = new MediaInfo
- {
- MediaStreams = internalStreams.Select(s => GetMediaStream(s, data.format))
- .Where(i => i != null)
- .ToList()
- };
-
- if (data.format != null)
- {
- info.Format = data.format.format_name;
-
- if (!string.IsNullOrEmpty(data.format.bit_rate))
- {
- info.TotalBitrate = int.Parse(data.format.bit_rate, UsCulture);
- }
- }
-
- return info;
- }
-
- private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- /// <summary>
- /// Converts ffprobe stream info to our MediaStream class
- /// </summary>
- /// <param name="streamInfo">The stream info.</param>
- /// <param name="formatInfo">The format info.</param>
- /// <returns>MediaStream.</returns>
- private static MediaStream GetMediaStream(MediaStreamInfo streamInfo, MediaFormatInfo formatInfo)
- {
- var stream = new MediaStream
- {
- Codec = streamInfo.codec_name,
- Profile = streamInfo.profile,
- Level = streamInfo.level,
- Index = streamInfo.index,
- PixelFormat = streamInfo.pix_fmt
- };
-
- if (streamInfo.tags != null)
- {
- stream.Language = GetDictionaryValue(streamInfo.tags, "language");
- }
-
- if (string.Equals(streamInfo.codec_type, "audio", StringComparison.OrdinalIgnoreCase))
- {
- stream.Type = MediaStreamType.Audio;
-
- stream.Channels = streamInfo.channels;
-
- if (!string.IsNullOrEmpty(streamInfo.sample_rate))
- {
- stream.SampleRate = int.Parse(streamInfo.sample_rate, UsCulture);
- }
-
- stream.ChannelLayout = ParseChannelLayout(streamInfo.channel_layout);
- }
- else if (string.Equals(streamInfo.codec_type, "subtitle", StringComparison.OrdinalIgnoreCase))
- {
- stream.Type = MediaStreamType.Subtitle;
- }
- else if (string.Equals(streamInfo.codec_type, "video", StringComparison.OrdinalIgnoreCase))
- {
- stream.Type = (streamInfo.codec_name ?? string.Empty).IndexOf("mjpeg", StringComparison.OrdinalIgnoreCase) != -1
- ? MediaStreamType.EmbeddedImage
- : MediaStreamType.Video;
-
- stream.Width = streamInfo.width;
- stream.Height = streamInfo.height;
- stream.AspectRatio = GetAspectRatio(streamInfo);
-
- stream.AverageFrameRate = GetFrameRate(streamInfo.avg_frame_rate);
- stream.RealFrameRate = GetFrameRate(streamInfo.r_frame_rate);
-
- stream.BitDepth = GetBitDepth(stream.PixelFormat);
-
- //stream.IsAnamorphic = string.Equals(streamInfo.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase) ||
- // string.Equals(stream.AspectRatio, "2.35:1", StringComparison.OrdinalIgnoreCase) ||
- // string.Equals(stream.AspectRatio, "2.40:1", StringComparison.OrdinalIgnoreCase);
-
- stream.IsAnamorphic = string.Equals(streamInfo.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase);
- }
- else
- {
- return null;
- }
-
- // Get stream bitrate
- var bitrate = 0;
-
- if (!string.IsNullOrEmpty(streamInfo.bit_rate))
- {
- bitrate = int.Parse(streamInfo.bit_rate, UsCulture);
- }
- else if (formatInfo != null && !string.IsNullOrEmpty(formatInfo.bit_rate) && stream.Type == MediaStreamType.Video)
- {
- // If the stream info doesn't have a bitrate get the value from the media format info
- bitrate = int.Parse(formatInfo.bit_rate, UsCulture);
- }
-
- if (bitrate > 0)
- {
- stream.BitRate = bitrate;
- }
-
- if (streamInfo.disposition != null)
- {
- var isDefault = GetDictionaryValue(streamInfo.disposition, "default");
- var isForced = GetDictionaryValue(streamInfo.disposition, "forced");
-
- stream.IsDefault = string.Equals(isDefault, "1", StringComparison.OrdinalIgnoreCase);
-
- stream.IsForced = string.Equals(isForced, "1", StringComparison.OrdinalIgnoreCase);
- }
-
- return stream;
- }
-
- private static int? GetBitDepth(string pixelFormat)
- {
- var eightBit = new List<string>
- {
- "yuv420p",
- "yuv411p",
- "yuvj420p",
- "uyyvyy411",
- "nv12",
- "nv21",
- "rgb444le",
- "rgb444be",
- "bgr444le",
- "bgr444be",
- "yuvj411p"
- };
-
- if (!string.IsNullOrEmpty(pixelFormat))
- {
- if (eightBit.Contains(pixelFormat, StringComparer.OrdinalIgnoreCase))
- {
- return 8;
- }
- }
-
- return null;
- }
-
- /// <summary>
- /// Gets a string from an FFProbeResult tags dictionary
- /// </summary>
- /// <param name="tags">The tags.</param>
- /// <param name="key">The key.</param>
- /// <returns>System.String.</returns>
- private static string GetDictionaryValue(Dictionary<string, string> tags, string key)
- {
- if (tags == null)
- {
- return null;
- }
-
- string val;
-
- tags.TryGetValue(key, out val);
- return val;
- }
-
- private static string ParseChannelLayout(string input)
- {
- if (string.IsNullOrEmpty(input))
- {
- return input;
- }
-
- return input.Split('(').FirstOrDefault();
- }
-
- private static string GetAspectRatio(MediaStreamInfo info)
- {
- var original = info.display_aspect_ratio;
-
- int height;
- int width;
-
- var parts = (original ?? string.Empty).Split(':');
- if (!(parts.Length == 2 &&
- int.TryParse(parts[0], NumberStyles.Any, UsCulture, out width) &&
- int.TryParse(parts[1], NumberStyles.Any, UsCulture, out height) &&
- width > 0 &&
- height > 0))
- {
- width = info.width;
- height = info.height;
- }
-
- if (width > 0 && height > 0)
- {
- double ratio = width;
- ratio /= height;
-
- if (IsClose(ratio, 1.777777778, .03))
- {
- return "16:9";
- }
-
- if (IsClose(ratio, 1.3333333333, .05))
- {
- return "4:3";
- }
-
- if (IsClose(ratio, 1.41))
- {
- return "1.41:1";
- }
-
- if (IsClose(ratio, 1.5))
- {
- return "1.5:1";
- }
-
- if (IsClose(ratio, 1.6))
- {
- return "1.6:1";
- }
-
- if (IsClose(ratio, 1.66666666667))
- {
- return "5:3";
- }
-
- if (IsClose(ratio, 1.85, .02))
- {
- return "1.85:1";
- }
-
- if (IsClose(ratio, 2.35, .025))
- {
- return "2.35:1";
- }
-
- if (IsClose(ratio, 2.4, .025))
- {
- return "2.40:1";
- }
- }
-
- return original;
- }
-
- private static bool IsClose(double d1, double d2, double variance = .005)
- {
- return Math.Abs(d1 - d2) <= variance;
- }
-
- /// <summary>
- /// Gets a frame rate from a string value in ffprobe output
- /// This could be a number or in the format of 2997/125.
- /// </summary>
- /// <param name="value">The value.</param>
- /// <returns>System.Nullable{System.Single}.</returns>
- private static float? GetFrameRate(string value)
- {
- if (!string.IsNullOrEmpty(value))
- {
- var parts = value.Split('/');
-
- float result;
-
- if (parts.Length == 2)
- {
- result = float.Parse(parts[0], UsCulture) / float.Parse(parts[1], UsCulture);
- }
- else
- {
- result = float.Parse(parts[0], UsCulture);
- }
-
- return float.IsNaN(result) ? (float?)null : result;
- }
-
- return null;
- }
-
}
}
diff --git a/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs b/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs
new file mode 100644
index 000000000..24df7b885
--- /dev/null
+++ b/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs
@@ -0,0 +1,25 @@
+using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Model.MediaInfo;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.MediaEncoding
+{
+ public class MediaInfoRequest
+ {
+ public string InputPath { get; set; }
+ public MediaProtocol Protocol { get; set; }
+ public bool ExtractChapters { get; set; }
+ public DlnaProfileType MediaType { get; set; }
+ public IIsoMount MountedIso { get; set; }
+ public VideoType VideoType { get; set; }
+ public List<string> PlayableStreamFileNames { get; set; }
+ public bool ExtractKeyFrameInterval { get; set; }
+
+ public MediaInfoRequest()
+ {
+ PlayableStreamFileNames = new List<string>();
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs
index f306518df..aa5376ec3 100644
--- a/MediaBrowser.Controller/Persistence/IItemRepository.cs
+++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs
@@ -107,7 +107,7 @@ namespace MediaBrowser.Controller.Persistence
/// </summary>
/// <param name="type">The type.</param>
/// <returns>IEnumerable{Guid}.</returns>
- IEnumerable<Guid> GetItemsOfType(Type type);
+ IEnumerable<Guid> GetItemIdsOfType(Type type);
/// <summary>
/// Saves the children.
@@ -133,6 +133,13 @@ namespace MediaBrowser.Controller.Persistence
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task SaveMediaStreams(Guid id, IEnumerable<MediaStream> streams, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the type of the items of.
+ /// </summary>
+ /// <param name="type">The type.</param>
+ /// <returns>IEnumerable&lt;BaseItem&gt;.</returns>
+ IEnumerable<BaseItem> GetItemsOfType(Type type);
}
}
diff --git a/MediaBrowser.Controller/Providers/IImageEnhancer.cs b/MediaBrowser.Controller/Providers/IImageEnhancer.cs
index e5a51a56e..a43941607 100644
--- a/MediaBrowser.Controller/Providers/IImageEnhancer.cs
+++ b/MediaBrowser.Controller/Providers/IImageEnhancer.cs
@@ -1,5 +1,4 @@
-using MediaBrowser.Controller.Drawing;
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Entities;
using System.Threading.Tasks;
diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs
index d40fa835f..d6fc39c5f 100644
--- a/MediaBrowser.Controller/Providers/IProviderManager.cs
+++ b/MediaBrowser.Controller/Providers/IProviderManager.cs
@@ -78,6 +78,19 @@ namespace MediaBrowser.Controller.Providers
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, string internalCacheKey, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Saves the image.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="source">The source.</param>
+ /// <param name="mimeType">Type of the MIME.</param>
+ /// <param name="type">The type.</param>
+ /// <param name="imageIndex">Index of the image.</param>
+ /// <param name="internalCacheKey">The internal cache key.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task SaveImage(IHasImages item, string source, string mimeType, ImageType type, int? imageIndex, string internalCacheKey, CancellationToken cancellationToken);
/// <summary>
/// Adds the metadata providers.
diff --git a/MediaBrowser.Controller/Providers/MetadataStatus.cs b/MediaBrowser.Controller/Providers/MetadataStatus.cs
index 12844c3c4..283b9edbc 100644
--- a/MediaBrowser.Controller/Providers/MetadataStatus.cs
+++ b/MediaBrowser.Controller/Providers/MetadataStatus.cs
@@ -1,6 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
namespace MediaBrowser.Controller.Providers
{
@@ -54,13 +52,6 @@ namespace MediaBrowser.Controller.Providers
/// <value>The last result error message.</value>
public string LastErrorMessage { get; set; }
- /// <summary>
- /// Gets or sets the providers refreshed.
- /// </summary>
- /// <value>The providers refreshed.</value>
- public List<Guid> MetadataProvidersRefreshed { get; set; }
- public List<Guid> ImageProvidersRefreshed { get; set; }
-
public DateTime? ItemDateModified { get; set; }
public void AddStatus(ProviderRefreshStatus status, string errorMessage)
@@ -83,9 +74,6 @@ namespace MediaBrowser.Controller.Providers
public MetadataStatus()
{
LastStatus = ProviderRefreshStatus.Success;
-
- MetadataProvidersRefreshed = new List<Guid>();
- ImageProvidersRefreshed = new List<Guid>();
}
public bool IsDirty { get; private set; }
@@ -109,33 +97,5 @@ namespace MediaBrowser.Controller.Providers
DateLastImagesRefresh = date;
}
-
- public void AddImageProvidersRefreshed(List<Guid> providerIds)
- {
- var count = ImageProvidersRefreshed.Count;
-
- providerIds.AddRange(ImageProvidersRefreshed);
-
- ImageProvidersRefreshed = providerIds.Distinct().ToList();
-
- if (ImageProvidersRefreshed.Count != count)
- {
- IsDirty = true;
- }
- }
-
- public void AddMetadataProvidersRefreshed(List<Guid> providerIds)
- {
- var count = MetadataProvidersRefreshed.Count;
-
- providerIds.AddRange(MetadataProvidersRefreshed);
-
- MetadataProvidersRefreshed = providerIds.Distinct().ToList();
-
- if (MetadataProvidersRefreshed.Count != count)
- {
- IsDirty = true;
- }
- }
}
}
diff --git a/MediaBrowser.Controller/Sync/IHasDynamicAccess.cs b/MediaBrowser.Controller/Sync/IHasDynamicAccess.cs
index f907de729..cf868a381 100644
--- a/MediaBrowser.Controller/Sync/IHasDynamicAccess.cs
+++ b/MediaBrowser.Controller/Sync/IHasDynamicAccess.cs
@@ -9,10 +9,10 @@ namespace MediaBrowser.Controller.Sync
/// <summary>
/// Gets the synced file information.
/// </summary>
- /// <param name="remotePath">The remote path.</param>
+ /// <param name="id">The identifier.</param>
/// <param name="target">The target.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;SyncedFileInfo&gt;.</returns>
- Task<SyncedFileInfo> GetSyncedFileInfo(string remotePath, SyncTarget target, CancellationToken cancellationToken);
+ Task<SyncedFileInfo> GetSyncedFileInfo(string id, SyncTarget target, CancellationToken cancellationToken);
}
}
diff --git a/MediaBrowser.Controller/Sync/IRemoteSyncProvider.cs b/MediaBrowser.Controller/Sync/IRemoteSyncProvider.cs
new file mode 100644
index 000000000..aeb7a3bff
--- /dev/null
+++ b/MediaBrowser.Controller/Sync/IRemoteSyncProvider.cs
@@ -0,0 +1,10 @@
+
+namespace MediaBrowser.Controller.Sync
+{
+ /// <summary>
+ /// A marker interface
+ /// </summary>
+ public interface IRemoteSyncProvider
+ {
+ }
+}
diff --git a/MediaBrowser.Controller/Sync/IServerSyncProvider.cs b/MediaBrowser.Controller/Sync/IServerSyncProvider.cs
index 46bbbd329..2635a4cbf 100644
--- a/MediaBrowser.Controller/Sync/IServerSyncProvider.cs
+++ b/MediaBrowser.Controller/Sync/IServerSyncProvider.cs
@@ -1,6 +1,7 @@
-using MediaBrowser.Model.Sync;
+using MediaBrowser.Model.Querying;
+using MediaBrowser.Model.Sync;
+using Interfaces.IO;
using System;
-using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
@@ -13,46 +14,39 @@ namespace MediaBrowser.Controller.Sync
/// Transfers the file.
/// </summary>
/// <param name="stream">The stream.</param>
- /// <param name="remotePath">The remote path.</param>
+ /// <param name="pathParts">The path parts.</param>
/// <param name="target">The target.</param>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- Task<SyncedFileInfo> SendFile(Stream stream, string remotePath, SyncTarget target, IProgress<double> progress, CancellationToken cancellationToken);
+ Task<SyncedFileInfo> SendFile(Stream stream, string[] pathParts, SyncTarget target, IProgress<double> progress, CancellationToken cancellationToken);
/// <summary>
/// Deletes the file.
/// </summary>
- /// <param name="path">The path.</param>
+ /// <param name="id">The identifier.</param>
/// <param name="target">The target.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- Task DeleteFile(string path, SyncTarget target, CancellationToken cancellationToken);
+ Task DeleteFile(string id, SyncTarget target, CancellationToken cancellationToken);
/// <summary>
/// Gets the file.
/// </summary>
- /// <param name="path">The path.</param>
+ /// <param name="id">The identifier.</param>
/// <param name="target">The target.</param>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;Stream&gt;.</returns>
- Task<Stream> GetFile(string path, SyncTarget target, IProgress<double> progress, CancellationToken cancellationToken);
+ Task<Stream> GetFile(string id, SyncTarget target, IProgress<double> progress, CancellationToken cancellationToken);
/// <summary>
- /// Gets the full path.
+ /// Gets the files.
/// </summary>
- /// <param name="path">The path.</param>
+ /// <param name="query">The query.</param>
/// <param name="target">The target.</param>
- /// <returns>System.String.</returns>
- string GetFullPath(IEnumerable<string> path, SyncTarget target);
-
- /// <summary>
- /// Gets the parent directory path.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="target">The target.</param>
- /// <returns>System.String.</returns>
- string GetParentDirectoryPath(string path, SyncTarget target);
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task&lt;QueryResult&lt;FileMetadata&gt;&gt;.</returns>
+ Task<QueryResult<FileMetadata>> GetFiles(FileQuery query, SyncTarget target, CancellationToken cancellationToken);
}
}
diff --git a/MediaBrowser.Controller/Sync/ISyncDataProvider.cs b/MediaBrowser.Controller/Sync/ISyncDataProvider.cs
index 04101fd46..ebff50cb0 100644
--- a/MediaBrowser.Controller/Sync/ISyncDataProvider.cs
+++ b/MediaBrowser.Controller/Sync/ISyncDataProvider.cs
@@ -7,22 +7,14 @@ namespace MediaBrowser.Controller.Sync
public interface ISyncDataProvider
{
/// <summary>
- /// Gets the server item ids.
+ /// Gets the local items.
/// </summary>
/// <param name="target">The target.</param>
/// <param name="serverId">The server identifier.</param>
- /// <returns>Task&lt;List&lt;System.String&gt;&gt;.</returns>
- Task<List<string>> GetServerItemIds(SyncTarget target, string serverId);
+ /// <returns>Task&lt;List&lt;LocalItem&gt;&gt;.</returns>
+ Task<List<LocalItem>> GetLocalItems(SyncTarget target, string serverId);
/// <summary>
- /// Gets the synchronize job item ids.
- /// </summary>
- /// <param name="target">The target.</param>
- /// <param name="serverId">The server identifier.</param>
- /// <returns>Task&lt;List&lt;System.String&gt;&gt;.</returns>
- Task<List<string>> GetSyncJobItemIds(SyncTarget target, string serverId);
-
- /// <summary>
/// Adds the or update.
/// </summary>
/// <param name="target">The target.</param>
@@ -53,7 +45,7 @@ namespace MediaBrowser.Controller.Sync
/// <param name="serverId">The server identifier.</param>
/// <param name="itemId">The item identifier.</param>
/// <returns>Task&lt;LocalItem&gt;.</returns>
- Task<List<LocalItem>> GetCachedItems(SyncTarget target, string serverId, string itemId);
+ Task<List<LocalItem>> GetItems(SyncTarget target, string serverId, string itemId);
/// <summary>
/// Gets the cached items by synchronize job item identifier.
/// </summary>
@@ -61,6 +53,6 @@ namespace MediaBrowser.Controller.Sync
/// <param name="serverId">The server identifier.</param>
/// <param name="syncJobItemId">The synchronize job item identifier.</param>
/// <returns>Task&lt;List&lt;LocalItem&gt;&gt;.</returns>
- Task<List<LocalItem>> GetCachedItemsBySyncJobItemId(SyncTarget target, string serverId, string syncJobItemId);
+ Task<List<LocalItem>> GetItemsBySyncJobItemId(SyncTarget target, string serverId, string syncJobItemId);
}
}
diff --git a/MediaBrowser.Controller/Sync/ISyncManager.cs b/MediaBrowser.Controller/Sync/ISyncManager.cs
index c51c8c1ba..97591551c 100644
--- a/MediaBrowser.Controller/Sync/ISyncManager.cs
+++ b/MediaBrowser.Controller/Sync/ISyncManager.cs
@@ -74,6 +74,14 @@ namespace MediaBrowser.Controller.Sync
Task CancelJob(string id);
/// <summary>
+ /// Cancels the items.
+ /// </summary>
+ /// <param name="targetId">The target identifier.</param>
+ /// <param name="itemIds">The item ids.</param>
+ /// <returns>Task.</returns>
+ Task CancelItems(string targetId, IEnumerable<string> itemIds);
+
+ /// <summary>
/// Adds the parts.
/// </summary>
void AddParts(IEnumerable<ISyncProvider> providers);
@@ -166,6 +174,13 @@ namespace MediaBrowser.Controller.Sync
/// <param name="targetId">The target identifier.</param>
/// <returns>IEnumerable&lt;SyncQualityOption&gt;.</returns>
IEnumerable<SyncQualityOption> GetQualityOptions(string targetId);
+ /// <summary>
+ /// Gets the quality options.
+ /// </summary>
+ /// <param name="targetId">The target identifier.</param>
+ /// <param name="user">The user.</param>
+ /// <returns>IEnumerable&lt;SyncQualityOption&gt;.</returns>
+ IEnumerable<SyncQualityOption> GetQualityOptions(string targetId, User user);
/// <summary>
/// Gets the profile options.
@@ -173,5 +188,12 @@ namespace MediaBrowser.Controller.Sync
/// <param name="targetId">The target identifier.</param>
/// <returns>IEnumerable&lt;SyncQualityOption&gt;.</returns>
IEnumerable<SyncProfileOption> GetProfileOptions(string targetId);
+ /// <summary>
+ /// Gets the profile options.
+ /// </summary>
+ /// <param name="targetId">The target identifier.</param>
+ /// <param name="user">The user.</param>
+ /// <returns>IEnumerable&lt;SyncProfileOption&gt;.</returns>
+ IEnumerable<SyncProfileOption> GetProfileOptions(string targetId, User user);
}
}
diff --git a/MediaBrowser.Controller/Sync/SyncedFileInfo.cs b/MediaBrowser.Controller/Sync/SyncedFileInfo.cs
index 550af2d55..844e7d890 100644
--- a/MediaBrowser.Controller/Sync/SyncedFileInfo.cs
+++ b/MediaBrowser.Controller/Sync/SyncedFileInfo.cs
@@ -20,6 +20,11 @@ namespace MediaBrowser.Controller.Sync
/// </summary>
/// <value>The required HTTP headers.</value>
public Dictionary<string, string> RequiredHttpHeaders { get; set; }
+ /// <summary>
+ /// Gets or sets the identifier.
+ /// </summary>
+ /// <value>The identifier.</value>
+ public string Id { get; set; }
public SyncedFileInfo()
{
diff --git a/MediaBrowser.Controller/packages.config b/MediaBrowser.Controller/packages.config
index 6df166204..8846b5a06 100644
--- a/MediaBrowser.Controller/packages.config
+++ b/MediaBrowser.Controller/packages.config
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
+ <package id="Interfaces.IO" version="1.0.0.5" targetFramework="net45" />
<package id="morelinq" version="1.1.0" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
index 5ccea52ba..3d7ae8cc4 100644
--- a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
+++ b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
@@ -58,7 +58,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
_profile = profile;
_config = config;
- _didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager);
+ _didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, Logger);
}
protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, Headers methodParams)
@@ -223,7 +223,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
if (string.Equals(flag, "BrowseMetadata"))
{
totalCount = 1;
-
+
if (item.IsFolder || serverItem.StubType.HasValue)
{
var childrenResult = (await GetUserItems(item, serverItem.StubType, user, sortCriteria, start, requestedCount).ConfigureAwait(false));
@@ -350,7 +350,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
};
}
- private async Task<QueryResult<BaseItem>> GetChildrenSorted(BaseItem item, User user, SearchCriteria search, SortCriteria sort, int? startIndex, int? limit)
+ private Task<QueryResult<BaseItem>> GetChildrenSorted(BaseItem item, User user, SearchCriteria search, SortCriteria sort, int? startIndex, int? limit)
{
var folder = (Folder)item;
@@ -389,7 +389,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
isFolder = true;
}
- return await folder.GetItems(new InternalItemsQuery
+ return folder.GetItems(new InternalItemsQuery
{
Limit = limit,
StartIndex = startIndex,
@@ -401,7 +401,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
IsFolder = isFolder,
MediaTypes = mediaTypes.ToArray()
- }).ConfigureAwait(false);
+ });
}
private async Task<QueryResult<ServerItem>> GetUserItems(BaseItem item, StubType? stubType, User user, SortCriteria sort, int? startIndex, int? limit)
diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs
index 19dab2246..52791822b 100644
--- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs
+++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs
@@ -12,6 +12,7 @@ using MediaBrowser.Dlna.ContentDirectory;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net;
using System;
using System.Globalization;
@@ -38,8 +39,9 @@ namespace MediaBrowser.Dlna.Didl
private readonly IUserDataManager _userDataManager;
private readonly ILocalizationManager _localization;
private readonly IMediaSourceManager _mediaSourceManager;
+ private readonly ILogger _logger;
- public DidlBuilder(DeviceProfile profile, User user, IImageProcessor imageProcessor, string serverAddress, string accessToken, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager)
+ public DidlBuilder(DeviceProfile profile, User user, IImageProcessor imageProcessor, string serverAddress, string accessToken, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, ILogger logger)
{
_profile = profile;
_imageProcessor = imageProcessor;
@@ -47,6 +49,7 @@ namespace MediaBrowser.Dlna.Didl
_userDataManager = userDataManager;
_localization = localization;
_mediaSourceManager = mediaSourceManager;
+ _logger = logger;
_accessToken = accessToken;
_user = user;
}
@@ -126,7 +129,7 @@ namespace MediaBrowser.Dlna.Didl
{
var sources = _mediaSourceManager.GetStaticMediaSources(video, true, _user).ToList();
- streamInfo = new StreamBuilder().BuildVideoItem(new VideoOptions
+ streamInfo = new StreamBuilder(_logger).BuildVideoItem(new VideoOptions
{
ItemId = GetClientId(video),
MediaSources = sources,
@@ -353,7 +356,7 @@ namespace MediaBrowser.Dlna.Didl
{
var sources = _mediaSourceManager.GetStaticMediaSources(audio, true, _user).ToList();
- streamInfo = new StreamBuilder().BuildAudioItem(new AudioOptions
+ streamInfo = new StreamBuilder(new NullLogger()).BuildAudioItem(new AudioOptions
{
ItemId = GetClientId(audio),
MediaSources = sources,
@@ -779,19 +782,33 @@ namespace MediaBrowser.Dlna.Didl
var result = element.OwnerDocument;
var playbackPercentage = 0;
+ var unplayedCount = 0;
if (item is Video)
{
var userData = _userDataManager.GetUserDataDto(item, _user);
playbackPercentage = Convert.ToInt32(userData.PlayedPercentage ?? 0);
- if (playbackPercentage >= 100)
+ if (playbackPercentage >= 100 || userData.Played)
{
- playbackPercentage = 0;
+ playbackPercentage = 100;
+ }
+ }
+ else if (item is Series || item is Season || item is BoxSet)
+ {
+ var userData = _userDataManager.GetUserDataDto(item, _user);
+
+ if (userData.Played)
+ {
+ playbackPercentage = 100;
+ }
+ else
+ {
+ unplayedCount = userData.UnplayedItemCount ?? 0;
}
}
- var albumartUrlInfo = GetImageUrl(imageInfo, _profile.MaxAlbumArtWidth, _profile.MaxAlbumArtHeight, playbackPercentage, "jpg");
+ var albumartUrlInfo = GetImageUrl(imageInfo, _profile.MaxAlbumArtWidth, _profile.MaxAlbumArtHeight, playbackPercentage, unplayedCount, "jpg");
var icon = result.CreateElement("upnp", "albumArtURI", NS_UPNP);
var profile = result.CreateAttribute("dlna", "profileID", NS_DLNA);
@@ -801,7 +818,7 @@ namespace MediaBrowser.Dlna.Didl
element.AppendChild(icon);
// TOOD: Remove these default values
- var iconUrlInfo = GetImageUrl(imageInfo, _profile.MaxIconWidth ?? 48, _profile.MaxIconHeight ?? 48, playbackPercentage, "jpg");
+ var iconUrlInfo = GetImageUrl(imageInfo, _profile.MaxIconWidth ?? 48, _profile.MaxIconHeight ?? 48, playbackPercentage, unplayedCount, "jpg");
icon = result.CreateElement("upnp", "icon", NS_UPNP);
icon.InnerText = iconUrlInfo.Url;
element.AppendChild(icon);
@@ -818,15 +835,15 @@ namespace MediaBrowser.Dlna.Didl
}
}
- AddImageResElement(item, element, 160, 160, playbackPercentage, "jpg", "JPEG_TN");
+ AddImageResElement(item, element, 160, 160, playbackPercentage, unplayedCount, "jpg", "JPEG_TN");
if (!_profile.EnableSingleAlbumArtLimit)
{
- AddImageResElement(item, element, 4096, 4096, playbackPercentage, "jpg", "JPEG_LRG");
- AddImageResElement(item, element, 1024, 768, playbackPercentage, "jpg", "JPEG_MED");
- AddImageResElement(item, element, 640, 480, playbackPercentage, "jpg", "JPEG_SM");
- AddImageResElement(item, element, 4096, 4096, playbackPercentage, "png", "PNG_LRG");
- AddImageResElement(item, element, 160, 160, playbackPercentage, "png", "PNG_TN");
+ AddImageResElement(item, element, 4096, 4096, playbackPercentage, unplayedCount, "jpg", "JPEG_LRG");
+ AddImageResElement(item, element, 1024, 768, playbackPercentage, unplayedCount, "jpg", "JPEG_MED");
+ AddImageResElement(item, element, 640, 480, playbackPercentage, unplayedCount, "jpg", "JPEG_SM");
+ AddImageResElement(item, element, 4096, 4096, playbackPercentage, unplayedCount, "png", "PNG_LRG");
+ AddImageResElement(item, element, 160, 160, playbackPercentage, unplayedCount, "png", "PNG_TN");
}
}
@@ -851,6 +868,7 @@ namespace MediaBrowser.Dlna.Didl
int maxWidth,
int maxHeight,
int playbackPercentage,
+ int unplayedCount,
string format,
string org_Pn)
{
@@ -863,7 +881,7 @@ namespace MediaBrowser.Dlna.Didl
var result = element.OwnerDocument;
- var albumartUrlInfo = GetImageUrl(imageInfo, maxWidth, maxHeight, playbackPercentage, format);
+ var albumartUrlInfo = GetImageUrl(imageInfo, maxWidth, maxHeight, playbackPercentage, unplayedCount, format);
var res = result.CreateElement(string.Empty, "res", NS_DIDL);
@@ -1004,9 +1022,9 @@ namespace MediaBrowser.Dlna.Didl
return id;
}
- private ImageUrlInfo GetImageUrl(ImageDownloadInfo info, int maxWidth, int maxHeight, int playbackPercentage, string format)
+ private ImageUrlInfo GetImageUrl(ImageDownloadInfo info, int maxWidth, int maxHeight, int playbackPercentage, int unplayedCount, string format)
{
- var url = string.Format("{0}/Items/{1}/Images/{2}/0/{3}/{4}/{5}/{6}/{7}",
+ var url = string.Format("{0}/Items/{1}/Images/{2}/0/{3}/{4}/{5}/{6}/{7}/{8}",
_serverAddress,
info.ItemId,
info.Type,
@@ -1014,7 +1032,8 @@ namespace MediaBrowser.Dlna.Didl
format,
maxWidth.ToString(CultureInfo.InvariantCulture),
maxHeight.ToString(CultureInfo.InvariantCulture),
- playbackPercentage.ToString(CultureInfo.InvariantCulture)
+ playbackPercentage.ToString(CultureInfo.InvariantCulture),
+ unplayedCount.ToString(CultureInfo.InvariantCulture)
);
var width = info.Width;
diff --git a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj
index 2f4d44418..0cbe36398 100644
--- a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj
+++ b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj
@@ -94,7 +94,6 @@
<Compile Include="PlayTo\uParserObject.cs" />
<Compile Include="Profiles\Foobar2000Profile.cs" />
<Compile Include="Profiles\MediaMonkeyProfile.cs" />
- <Compile Include="Profiles\WindowsMediaCenterProfile.cs" />
<Compile Include="ContentDirectory\ContentDirectory.cs" />
<Compile Include="ContentDirectory\ControlHandler.cs" />
<Compile Include="ContentDirectory\ServiceActionListBuilder.cs" />
@@ -167,7 +166,9 @@
<EmbeddedResource Include="Profiles\Xml\Sony Bravia %282013%29.xml" />
<EmbeddedResource Include="Profiles\Xml\Sony PlayStation 3.xml" />
<EmbeddedResource Include="Profiles\Xml\WDTV Live.xml" />
- <EmbeddedResource Include="Profiles\Xml\Xbox 360.xml" />
+ <EmbeddedResource Include="Profiles\Xml\Xbox 360.xml">
+ <SubType>Designer</SubType>
+ </EmbeddedResource>
<EmbeddedResource Include="Profiles\Xml\Xbox One.xml" />
</ItemGroup>
<ItemGroup>
diff --git a/MediaBrowser.Dlna/PlayTo/PlayToController.cs b/MediaBrowser.Dlna/PlayTo/PlayToController.cs
index 5b129243c..66cdc51af 100644
--- a/MediaBrowser.Dlna/PlayTo/PlayToController.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlayToController.cs
@@ -478,7 +478,7 @@ namespace MediaBrowser.Dlna.PlayTo
playlistItem.StreamUrl = playlistItem.StreamInfo.ToDlnaUrl(_serverAddress, _accessToken);
- var itemXml = new DidlBuilder(profile, user, _imageProcessor, _serverAddress, _accessToken, _userDataManager, _localization, _mediaSourceManager)
+ var itemXml = new DidlBuilder(profile, user, _imageProcessor, _serverAddress, _accessToken, _userDataManager, _localization, _mediaSourceManager, _logger)
.GetItemDidl(item, null, _session.DeviceId, new Filter(), playlistItem.StreamInfo);
playlistItem.Didl = itemXml;
@@ -542,7 +542,7 @@ namespace MediaBrowser.Dlna.PlayTo
{
return new PlaylistItem
{
- StreamInfo = new StreamBuilder().BuildVideoItem(new VideoOptions
+ StreamInfo = new StreamBuilder(_logger).BuildVideoItem(new VideoOptions
{
ItemId = item.Id.ToString("N"),
MediaSources = mediaSources,
@@ -562,7 +562,7 @@ namespace MediaBrowser.Dlna.PlayTo
{
return new PlaylistItem
{
- StreamInfo = new StreamBuilder().BuildAudioItem(new AudioOptions
+ StreamInfo = new StreamBuilder(_logger).BuildAudioItem(new AudioOptions
{
ItemId = item.Id.ToString("N"),
MediaSources = mediaSources,
@@ -892,7 +892,7 @@ namespace MediaBrowser.Dlna.PlayTo
request.MediaSource = hasMediaSources == null ?
null :
- mediaSourceManager.GetStaticMediaSource(hasMediaSources, request.MediaSourceId, false);
+ mediaSourceManager.GetMediaSource(hasMediaSources, request.MediaSourceId, false).Result;
diff --git a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
index ba6d656dd..77c98f9b9 100644
--- a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
@@ -114,7 +114,7 @@ namespace MediaBrowser.Dlna.PlayTo
_mediaSourceManager);
controller.Init(device);
-
+
var profile = _dlnaManager.GetProfile(device.Properties.ToDeviceIdentification()) ??
_dlnaManager.GetDefaultProfile();
diff --git a/MediaBrowser.Dlna/Profiles/DishHopperJoeyProfile.cs b/MediaBrowser.Dlna/Profiles/DishHopperJoeyProfile.cs
index 07936688d..ab887a3bf 100644
--- a/MediaBrowser.Dlna/Profiles/DishHopperJoeyProfile.cs
+++ b/MediaBrowser.Dlna/Profiles/DishHopperJoeyProfile.cs
@@ -95,6 +95,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
Type = CodecType.Video,
+ Codec = "h264",
Conditions = new []
{
new ProfileCondition
@@ -138,7 +139,6 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
Type = CodecType.Video,
- Codec = "mpeg2video",
Conditions = new []
{
new ProfileCondition
diff --git a/MediaBrowser.Dlna/Profiles/PopcornHourProfile.cs b/MediaBrowser.Dlna/Profiles/PopcornHourProfile.cs
index 6cf06d41f..883af57d2 100644
--- a/MediaBrowser.Dlna/Profiles/PopcornHourProfile.cs
+++ b/MediaBrowser.Dlna/Profiles/PopcornHourProfile.cs
@@ -93,8 +93,10 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
Type = CodecType.Video,
+ Codec="h264",
Conditions = new []
{
+ new ProfileCondition(ProfileConditionType.EqualsAny, ProfileConditionValue.VideoProfile, "baseline|constrained baseline"),
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
@@ -120,10 +122,27 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
Type = CodecType.Video,
- Codec="h264",
Conditions = new []
{
- new ProfileCondition(ProfileConditionType.EqualsAny, ProfileConditionValue.VideoProfile, "baseline|constrained baseline")
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.Width,
+ Value = "1920"
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.Height,
+ Value = "1080"
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.NotEquals,
+ Property = ProfileConditionValue.IsAnamorphic,
+ Value = "true",
+ IsRequired = false
+ }
}
},
diff --git a/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs
index 6f175ccd6..46549040f 100644
--- a/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs
+++ b/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs
@@ -209,6 +209,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
Type = CodecType.Video,
+ Codec = "h264",
Conditions = new []
{
new ProfileCondition
@@ -222,16 +223,7 @@ namespace MediaBrowser.Dlna.Profiles
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
- }
- }
- },
-
- new CodecProfile
- {
- Type = CodecType.Video,
- Codec = "h264",
- Conditions = new []
- {
+ },
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
@@ -262,6 +254,18 @@ namespace MediaBrowser.Dlna.Profiles
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.Width,
+ Value = "1920"
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.Height,
+ Value = "1080"
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
},
@@ -276,6 +280,26 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
+ Type = CodecType.Video,
+ Conditions = new []
+ {
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.Width,
+ Value = "1920"
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.Height,
+ Value = "1080"
+ }
+ }
+ },
+
+ new CodecProfile
+ {
Type = CodecType.VideoAudio,
Codec = "ac3",
diff --git a/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs
index 32cf8b554..d9891e87b 100644
--- a/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs
+++ b/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs
@@ -226,6 +226,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
Type = CodecType.Video,
+ Codec = "h264",
Conditions = new []
{
new ProfileCondition
@@ -239,16 +240,7 @@ namespace MediaBrowser.Dlna.Profiles
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
- }
- }
- },
-
- new CodecProfile
- {
- Type = CodecType.Video,
- Codec = "h264",
- Conditions = new []
- {
+ },
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
@@ -279,6 +271,18 @@ namespace MediaBrowser.Dlna.Profiles
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.Width,
+ Value = "1920"
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.Height,
+ Value = "1080"
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
},
@@ -293,6 +297,26 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
+ Type = CodecType.Video,
+ Conditions = new []
+ {
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.Width,
+ Value = "1920"
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.Height,
+ Value = "1080"
+ }
+ }
+ },
+
+ new CodecProfile
+ {
Type = CodecType.VideoAudio,
Codec = "ac3",
diff --git a/MediaBrowser.Dlna/Profiles/WindowsMediaCenterProfile.cs b/MediaBrowser.Dlna/Profiles/WindowsMediaCenterProfile.cs
deleted file mode 100644
index a318b193b..000000000
--- a/MediaBrowser.Dlna/Profiles/WindowsMediaCenterProfile.cs
+++ /dev/null
@@ -1,274 +0,0 @@
-using System.Xml.Serialization;
-using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Dlna.Profiles;
-
-namespace MediaBrowser.Dlna.Profiles
-{
- [XmlRoot("Profile")]
- public class WindowsMediaCenterProfile : DefaultProfile
- {
- public WindowsMediaCenterProfile()
- {
- Name = "Windows Media Center";
-
- TranscodingProfiles = new[]
- {
- new TranscodingProfile
- {
- Container = "mp3",
- AudioCodec = "mp3",
- Type = DlnaProfileType.Audio
- },
- new TranscodingProfile
- {
- Container = "asf",
- VideoCodec = "msmpeg4",
- AudioCodec = "wmav2",
- Type = DlnaProfileType.Video
- }
- };
-
- DirectPlayProfiles = new[]
- {
- new DirectPlayProfile
- {
- Container = "avi",
- VideoCodec = "mpeg4",
- AudioCodec = "ac3,mp3",
- Type = DlnaProfileType.Video
- },
- new DirectPlayProfile
- {
- Container = "avi",
- VideoCodec = "h264",
- AudioCodec = "aac",
- Type = DlnaProfileType.Video
- },
- new DirectPlayProfile
- {
- Container = "mp4,mov",
- VideoCodec = "h264,mpeg4",
- AudioCodec = "aac,ac3",
- Type = DlnaProfileType.Video
- },
- new DirectPlayProfile
- {
- Container = "asf",
- VideoCodec = "wmv2,wmv3,vc1",
- AudioCodec = "wmav2,wmapro",
- Type = DlnaProfileType.Video
- },
- new DirectPlayProfile
- {
- Container = "asf",
- AudioCodec = "wmav2,wmapro,wmavoice",
- Type = DlnaProfileType.Audio
- },
- new DirectPlayProfile
- {
- Container = "mp3",
- AudioCodec = "mp3",
- Type = DlnaProfileType.Audio
- },
- new DirectPlayProfile
- {
- Container = "jpeg",
- Type = DlnaProfileType.Photo
- }
- };
-
- ResponseProfiles = new[]
- {
- new ResponseProfile
- {
- Container = "avi",
- MimeType = "video/avi",
- Type = DlnaProfileType.Video
- }
- };
-
- ContainerProfiles = new[]
- {
- new ContainerProfile
- {
- Type = DlnaProfileType.Video,
- Container = "mp4,mov",
-
- Conditions = new []
- {
- new ProfileCondition
- {
- Condition = ProfileConditionType.Equals,
- Property = ProfileConditionValue.Has64BitOffsets,
- Value = "false",
- IsRequired = false
- }
- }
- }
- };
-
- CodecProfiles = new[]
- {
- new CodecProfile
- {
- Type = CodecType.Video,
- Codec = "mpeg4",
- Conditions = new []
- {
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.Width,
- Value = "1280"
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.Height,
- Value = "720"
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.VideoFramerate,
- Value = "30",
- IsRequired = false
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.VideoBitrate,
- Value = "5120000",
- IsRequired = false
- }
- }
- },
-
- new CodecProfile
- {
- Type = CodecType.Video,
- Codec = "h264",
- Conditions = new []
- {
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.Width,
- Value = "1920"
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.Height,
- Value = "1080"
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.VideoLevel,
- Value = "41",
- IsRequired = false
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.VideoBitrate,
- Value = "10240000",
- IsRequired = false
- }
- }
- },
-
- new CodecProfile
- {
- Type = CodecType.Video,
- Codec = "wmv2,wmv3,vc1",
- Conditions = new []
- {
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.Width,
- Value = "1920"
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.Height,
- Value = "1080"
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.VideoFramerate,
- Value = "30",
- IsRequired = false
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.VideoBitrate,
- Value = "15360000",
- IsRequired = false
- }
- }
- },
-
- new CodecProfile
- {
- Type = CodecType.VideoAudio,
- Codec = "ac3",
- Conditions = new []
- {
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.AudioChannels,
- Value = "6",
- IsRequired = false
- }
- }
- },
-
- new CodecProfile
- {
- Type = CodecType.VideoAudio,
- Codec = "wmav2,wmapro",
- Conditions = new []
- {
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.AudioChannels,
- Value = "2",
- IsRequired = false
- }
- }
- },
-
- new CodecProfile
- {
- Type = CodecType.VideoAudio,
- Codec = "aac",
- Conditions = new []
- {
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.AudioChannels,
- Value = "2",
- IsRequired = false
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.Equals,
- Property = ProfileConditionValue.AudioProfile,
- Value = "lc",
- IsRequired = false
- }
- }
- }
- };
- }
- }
-}
diff --git a/MediaBrowser.Dlna/Profiles/XboxOneProfile.cs b/MediaBrowser.Dlna/Profiles/XboxOneProfile.cs
index 4399462cf..3427d75f7 100644
--- a/MediaBrowser.Dlna/Profiles/XboxOneProfile.cs
+++ b/MediaBrowser.Dlna/Profiles/XboxOneProfile.cs
@@ -12,18 +12,27 @@ namespace MediaBrowser.Dlna.Profiles
Name = "Xbox One";
TimelineOffsetSeconds = 40;
-
+
Identification = new DeviceIdentification
{
- ModelName = "Xbox One",
- FriendlyName = "Xbox-SystemOS",
+ FriendlyName = "XboxOne",
Headers = new[]
{
- new HttpHeaderInfo {Name = "User-Agent", Value = "NSPlayer", Match = HeaderMatchType.Substring}
+ new HttpHeaderInfo
+ {
+ Name = "FriendlyName.DLNA.ORG", Value = "XboxOne", Match = HeaderMatchType.Substring
+ },
+ new HttpHeaderInfo
+ {
+ Name = "User-Agent", Value = "NSPlayer/12", Match = HeaderMatchType.Substring
+ }
}
};
+ var videoProfile = "high|main|baseline|constrained baseline";
+ var videoLevel = "41";
+
TranscodingProfiles = new[]
{
new TranscodingProfile
@@ -43,8 +52,7 @@ namespace MediaBrowser.Dlna.Profiles
Container = "ts",
VideoCodec = "h264",
AudioCodec = "aac",
- Type = DlnaProfileType.Video,
- EstimateContentLength = true
+ Type = DlnaProfileType.Video
}
};
@@ -129,6 +137,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
Type = CodecType.Video,
+ Codec = "mpeg4",
Conditions = new []
{
new ProfileCondition
@@ -144,16 +153,7 @@ namespace MediaBrowser.Dlna.Profiles
Property = ProfileConditionValue.VideoBitDepth,
Value = "8",
IsRequired = false
- }
- }
- },
-
- new CodecProfile
- {
- Type = CodecType.Video,
- Codec = "mpeg4",
- Conditions = new []
- {
+ },
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
@@ -191,6 +191,20 @@ namespace MediaBrowser.Dlna.Profiles
{
new ProfileCondition
{
+ Condition = ProfileConditionType.NotEquals,
+ Property = ProfileConditionValue.IsAnamorphic,
+ Value = "true",
+ IsRequired = false
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.VideoBitDepth,
+ Value = "8",
+ IsRequired = false
+ },
+ new ProfileCondition
+ {
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
@@ -200,6 +214,20 @@ namespace MediaBrowser.Dlna.Profiles
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.VideoLevel,
+ Value = videoLevel,
+ IsRequired = false
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.EqualsAny,
+ Property = ProfileConditionValue.VideoProfile,
+ Value = videoProfile,
+ IsRequired = false
}
}
},
@@ -212,6 +240,20 @@ namespace MediaBrowser.Dlna.Profiles
{
new ProfileCondition
{
+ Condition = ProfileConditionType.NotEquals,
+ Property = ProfileConditionValue.IsAnamorphic,
+ Value = "true",
+ IsRequired = false
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.VideoBitDepth,
+ Value = "8",
+ IsRequired = false
+ },
+ new ProfileCondition
+ {
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
@@ -241,6 +283,28 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile
{
+ Type = CodecType.Video,
+ Conditions = new []
+ {
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.NotEquals,
+ Property = ProfileConditionValue.IsAnamorphic,
+ Value = "true",
+ IsRequired = false
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.VideoBitDepth,
+ Value = "8",
+ IsRequired = false
+ }
+ }
+ },
+
+ new CodecProfile
+ {
Type = CodecType.VideoAudio,
Codec = "ac3,wmav2,wmapro",
Conditions = new []
@@ -278,7 +342,7 @@ namespace MediaBrowser.Dlna.Profiles
}
}
};
-
+
ResponseProfiles = new[]
{
new ResponseProfile
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Dish Hopper-Joey.xml b/MediaBrowser.Dlna/Profiles/Xml/Dish Hopper-Joey.xml
index d7ad1ac30..21f2b1ad5 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Dish Hopper-Joey.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Dish Hopper-Joey.xml
@@ -49,7 +49,7 @@
</TranscodingProfiles>
<ContainerProfiles />
<CodecProfiles>
- <CodecProfile type="Video">
+ <CodecProfile type="Video" codec="h264">
<Conditions>
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
@@ -58,7 +58,7 @@
<ProfileCondition condition="LessThanEqual" property="VideoLevel" value="41" isRequired="true" />
</Conditions>
</CodecProfile>
- <CodecProfile type="Video" codec="mpeg2video">
+ <CodecProfile type="Video">
<Conditions>
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Popcorn Hour.xml b/MediaBrowser.Dlna/Profiles/Xml/Popcorn Hour.xml
index 8470f601a..2df2da98b 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Popcorn Hour.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Popcorn Hour.xml
@@ -44,16 +44,19 @@
</TranscodingProfiles>
<ContainerProfiles />
<CodecProfiles>
- <CodecProfile type="Video">
+ <CodecProfile type="Video" codec="h264">
<Conditions>
+ <ProfileCondition condition="EqualsAny" property="VideoProfile" value="baseline|constrained baseline" isRequired="false" />
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
<ProfileCondition condition="NotEquals" property="IsAnamorphic" value="true" isRequired="false" />
</Conditions>
</CodecProfile>
- <CodecProfile type="Video" codec="h264">
+ <CodecProfile type="Video">
<Conditions>
- <ProfileCondition condition="EqualsAny" property="VideoProfile" value="baseline|constrained baseline" isRequired="false" />
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ <ProfileCondition condition="NotEquals" property="IsAnamorphic" value="true" isRequired="false" />
</Conditions>
</CodecProfile>
<CodecProfile type="VideoAudio" codec="aac">
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml
index ba993ca3e..19cb5670a 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml
@@ -58,14 +58,10 @@
</ContainerProfile>
</ContainerProfiles>
<CodecProfiles>
- <CodecProfile type="Video">
+ <CodecProfile type="Video" codec="h264">
<Conditions>
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
- </Conditions>
- </CodecProfile>
- <CodecProfile type="Video" codec="h264">
- <Conditions>
<ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
<ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="20000000" isRequired="true" />
<ProfileCondition condition="LessThanEqual" property="VideoLevel" value="41" isRequired="true" />
@@ -73,10 +69,18 @@
</CodecProfile>
<CodecProfile type="Video" codec="mpeg2video">
<Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
<ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
<ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="20000000" isRequired="true" />
</Conditions>
</CodecProfile>
+ <CodecProfile type="Video">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
<CodecProfile type="VideoAudio" codec="ac3">
<Conditions>
<ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="true" />
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml
index 271cf1132..78c99d366 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml
@@ -61,14 +61,10 @@
</ContainerProfile>
</ContainerProfiles>
<CodecProfiles>
- <CodecProfile type="Video">
+ <CodecProfile type="Video" codec="h264">
<Conditions>
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
- </Conditions>
- </CodecProfile>
- <CodecProfile type="Video" codec="h264">
- <Conditions>
<ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
<ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="20000000" isRequired="true" />
<ProfileCondition condition="LessThanEqual" property="VideoLevel" value="41" isRequired="true" />
@@ -76,10 +72,18 @@
</CodecProfile>
<CodecProfile type="Video" codec="mpeg2video">
<Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
<ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
<ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="20000000" isRequired="true" />
</Conditions>
</CodecProfile>
+ <CodecProfile type="Video">
+ <Conditions>
+ <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ </Conditions>
+ </CodecProfile>
<CodecProfile type="VideoAudio" codec="ac3">
<Conditions>
<ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="true" />
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml b/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml
index 2595ffbdf..d22356646 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml
@@ -2,10 +2,10 @@
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Xbox One</Name>
<Identification>
- <FriendlyName>Xbox-SystemOS</FriendlyName>
- <ModelName>Xbox One</ModelName>
+ <FriendlyName>XboxOne</FriendlyName>
<Headers>
- <HttpHeaderInfo name="User-Agent" value="NSPlayer" match="Substring" />
+ <HttpHeaderInfo name="FriendlyName.DLNA.ORG" value="XboxOne" match="Substring" />
+ <HttpHeaderInfo name="User-Agent" value="NSPlayer/12" match="Substring" />
</Headers>
</Identification>
<FriendlyName>Emby</FriendlyName>
@@ -48,7 +48,7 @@
<TranscodingProfiles>
<TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" context="Streaming" />
<TranscodingProfile container="jpeg" type="Photo" videoCodec="jpeg" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="true" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" context="Streaming" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" context="Streaming" />
</TranscodingProfiles>
<ContainerProfiles>
<ContainerProfile type="Video" container="mp4,mov">
@@ -58,14 +58,10 @@
</ContainerProfile>
</ContainerProfiles>
<CodecProfiles>
- <CodecProfile type="Video">
+ <CodecProfile type="Video" codec="mpeg4">
<Conditions>
<ProfileCondition condition="NotEquals" property="IsAnamorphic" value="true" isRequired="false" />
<ProfileCondition condition="LessThanEqual" property="VideoBitDepth" value="8" isRequired="false" />
- </Conditions>
- </CodecProfile>
- <CodecProfile type="Video" codec="mpeg4">
- <Conditions>
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
<ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="false" />
@@ -74,18 +70,30 @@
</CodecProfile>
<CodecProfile type="Video" codec="h264">
<Conditions>
+ <ProfileCondition condition="NotEquals" property="IsAnamorphic" value="true" isRequired="false" />
+ <ProfileCondition condition="LessThanEqual" property="VideoBitDepth" value="8" isRequired="false" />
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+ <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="41" isRequired="false" />
+ <ProfileCondition condition="EqualsAny" property="VideoProfile" value="high|main|baseline|constrained baseline" isRequired="false" />
</Conditions>
</CodecProfile>
<CodecProfile type="Video" codec="wmv2,wmv3,vc1">
<Conditions>
+ <ProfileCondition condition="NotEquals" property="IsAnamorphic" value="true" isRequired="false" />
+ <ProfileCondition condition="LessThanEqual" property="VideoBitDepth" value="8" isRequired="false" />
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
<ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="false" />
<ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="15360000" isRequired="false" />
</Conditions>
</CodecProfile>
+ <CodecProfile type="Video">
+ <Conditions>
+ <ProfileCondition condition="NotEquals" property="IsAnamorphic" value="true" isRequired="false" />
+ <ProfileCondition condition="LessThanEqual" property="VideoBitDepth" value="8" isRequired="false" />
+ </Conditions>
+ </CodecProfile>
<CodecProfile type="VideoAudio" codec="ac3,wmav2,wmapro">
<Conditions>
<ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="false" />
diff --git a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs
index 8ca16832d..73bc4984c 100644
--- a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs
+++ b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs
@@ -62,16 +62,22 @@ namespace MediaBrowser.Dlna.Ssdp
{
if (string.Equals(args.Method, "M-SEARCH", StringComparison.OrdinalIgnoreCase))
{
- TimeSpan delay = GetSearchDelay(args.Headers);
+ var headers = args.Headers;
+
+ TimeSpan delay = GetSearchDelay(headers);
if (_config.GetDlnaConfiguration().EnableDebugLogging)
{
_logger.Debug("Delaying search response by {0} seconds", delay.TotalSeconds);
}
- await Task.Delay(delay).ConfigureAwait(false);
+ await Task.Delay(delay).ConfigureAwait(false);
- RespondToSearch(args.EndPoint, args.Headers["st"]);
+ string st;
+ if (headers.TryGetValue("st", out st))
+ {
+ RespondToSearch(args.EndPoint, st);
+ }
}
EventHelper.FireEventIfNotNull(MessageReceived, this, args, _logger);
diff --git a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs
index 31329e6d7..0089a71d5 100644
--- a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs
+++ b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs
@@ -10,7 +10,7 @@ using System.Linq;
namespace MediaBrowser.LocalMetadata.Images
{
- public class EpisodeLocalLocalImageProvider : ILocalImageFileProvider
+ public class EpisodeLocalLocalImageProvider : ILocalImageFileProvider, IHasOrder
{
private readonly IFileSystem _fileSystem;
@@ -24,6 +24,11 @@ namespace MediaBrowser.LocalMetadata.Images
get { return "Local Images"; }
}
+ public int Order
+ {
+ get { return 0; }
+ }
+
public bool Supports(IHasImages item)
{
return item is Episode && item.SupportsLocalMetadata;
diff --git a/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs b/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs
index 60533797a..f118c2763 100644
--- a/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs
+++ b/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs
@@ -26,6 +26,11 @@ namespace MediaBrowser.LocalMetadata.Images
public bool Supports(IHasImages item)
{
+ if (item is Photo)
+ {
+ return false;
+ }
+
if (!item.IsSaveLocalMetadataEnabled())
{
return true;
diff --git a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
index 6083c88de..ba87b3c43 100644
--- a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
+++ b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
@@ -12,7 +12,7 @@ using System.Linq;
namespace MediaBrowser.LocalMetadata.Images
{
- public class LocalImageProvider : ILocalImageFileProvider
+ public class LocalImageProvider : ILocalImageFileProvider, IHasOrder
{
private readonly IFileSystem _fileSystem;
diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
index 78ac92f25..c30ceb62d 100644
--- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
@@ -70,10 +70,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
encodingJob.OutputFilePath = GetOutputFilePath(encodingJob);
Directory.CreateDirectory(Path.GetDirectoryName(encodingJob.OutputFilePath));
- if (options.Context == EncodingContext.Static && encodingJob.IsInputVideo)
- {
- encodingJob.ReadInputAtNativeFramerate = true;
- }
+ encodingJob.ReadInputAtNativeFramerate = options.ReadInputAtNativeFramerate;
await AcquireResources(encodingJob, cancellationToken).ConfigureAwait(false);
@@ -305,19 +302,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// <returns>System.Int32.</returns>
protected int GetNumberOfThreads(EncodingJob job, bool isWebm)
{
- // Only need one thread for sync
- if (job.Options.Context == EncodingContext.Static)
- {
- return 1;
- }
-
- if (isWebm)
- {
- // Recommended per docs
- return Math.Max(Environment.ProcessorCount - 1, 2);
- }
-
- return 0;
+ return job.Options.CpuCoreLimit ?? 0;
}
protected EncodingQuality GetQualitySetting()
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
index 8d8201074..ea3cc6d89 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
@@ -59,7 +59,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
- var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(request.ItemId, false, cancellationToken).ConfigureAwait(false);
+ var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(request.ItemId, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false);
var mediaSource = string.IsNullOrEmpty(request.MediaSourceId)
? mediaSources.First()
@@ -124,10 +124,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
state.InputContainer = mediaSource.Container;
state.InputFileSize = mediaSource.Size;
state.InputBitrate = mediaSource.Bitrate;
- state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate;
state.RunTimeTicks = mediaSource.RunTimeTicks;
state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders;
+ if (mediaSource.ReadAtNativeFramerate)
+ {
+ state.ReadInputAtNativeFramerate = true;
+ }
+
if (mediaSource.VideoType.HasValue)
{
state.VideoType = mediaSource.VideoType.Value;
@@ -148,7 +152,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders;
state.InputBitrate = mediaSource.Bitrate;
state.InputFileSize = mediaSource.Size;
- state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate;
if (state.ReadInputAtNativeFramerate ||
mediaSource.Protocol == MediaProtocol.File && string.Equals(mediaSource.Container, "wtv", StringComparison.OrdinalIgnoreCase))
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index 425889807..d076a5b6b 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -5,12 +5,15 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Session;
+using MediaBrowser.MediaEncoding.Probing;
+using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Serialization;
using System;
+using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
@@ -72,6 +75,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
protected readonly Func<ISubtitleEncoder> SubtitleEncoder;
protected readonly Func<IMediaSourceManager> MediaSourceManager;
+ private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>();
+
public MediaEncoder(ILogger logger, IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, string version, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, Func<ISubtitleEncoder> subtitleEncoder, Func<IMediaSourceManager> mediaSourceManager)
{
_logger = logger;
@@ -102,16 +107,19 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// <summary>
/// Gets the media info.
/// </summary>
- /// <param name="inputFiles">The input files.</param>
- /// <param name="protocol">The protocol.</param>
- /// <param name="isAudio">if set to <c>true</c> [is audio].</param>
+ /// <param name="request">The request.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- public Task<InternalMediaInfoResult> GetMediaInfo(string[] inputFiles, MediaProtocol protocol, bool isAudio,
- CancellationToken cancellationToken)
+ public Task<Model.MediaInfo.MediaInfo> GetMediaInfo(MediaInfoRequest request, CancellationToken cancellationToken)
{
- return GetMediaInfoInternal(GetInputArgument(inputFiles, protocol), !isAudio,
- GetProbeSizeArgument(inputFiles, protocol), cancellationToken);
+ var extractChapters = request.MediaType == DlnaProfileType.Video && request.ExtractChapters;
+
+ var inputFiles = MediaEncoderHelpers.GetInputArgument(request.InputPath, request.Protocol, request.MountedIso, request.PlayableStreamFileNames);
+
+ var extractKeyFrameInterval = request.ExtractKeyFrameInterval && request.Protocol == MediaProtocol.File && request.VideoType == VideoType.VideoFile;
+
+ return GetMediaInfoInternal(GetInputArgument(inputFiles, request.Protocol), request.InputPath, request.Protocol, extractChapters, extractKeyFrameInterval,
+ GetProbeSizeArgument(inputFiles, request.Protocol), request.MediaType == DlnaProfileType.Audio, cancellationToken);
}
/// <summary>
@@ -141,13 +149,22 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// Gets the media info internal.
/// </summary>
/// <param name="inputPath">The input path.</param>
+ /// <param name="primaryPath">The primary path.</param>
+ /// <param name="protocol">The protocol.</param>
/// <param name="extractChapters">if set to <c>true</c> [extract chapters].</param>
+ /// <param name="extractKeyFrameInterval">if set to <c>true</c> [extract key frame interval].</param>
/// <param name="probeSizeArgument">The probe size argument.</param>
+ /// <param name="isAudio">if set to <c>true</c> [is audio].</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{MediaInfoResult}.</returns>
/// <exception cref="System.ApplicationException"></exception>
- private async Task<InternalMediaInfoResult> GetMediaInfoInternal(string inputPath, bool extractChapters,
+ private async Task<Model.MediaInfo.MediaInfo> GetMediaInfoInternal(string inputPath,
+ string primaryPath,
+ MediaProtocol protocol,
+ bool extractChapters,
+ bool extractKeyFrameInterval,
string probeSizeArgument,
+ bool isAudio,
CancellationToken cancellationToken)
{
var args = extractChapters
@@ -164,6 +181,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
// Must consume both or ffmpeg may hang due to deadlocks. See comments below.
RedirectStandardOutput = true,
RedirectStandardError = true,
+ RedirectStandardInput = true,
FileName = FFProbePath,
Arguments = string.Format(args,
probeSizeArgument, inputPath).Trim(),
@@ -177,15 +195,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
_logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
- process.Exited += ProcessExited;
-
await _ffProbeResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
- InternalMediaInfoResult result;
+ var processWrapper = new ProcessWrapper(process, this);
try
{
- process.Start();
+ StartProcess(processWrapper);
}
catch (Exception ex)
{
@@ -200,19 +216,57 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
process.BeginErrorReadLine();
- result = _jsonSerializer.DeserializeFromStream<InternalMediaInfoResult>(process.StandardOutput.BaseStream);
+ var result = _jsonSerializer.DeserializeFromStream<InternalMediaInfoResult>(process.StandardOutput.BaseStream);
+
+ if (result != null)
+ {
+ if (result.streams != null)
+ {
+ // Normalize aspect ratio if invalid
+ foreach (var stream in result.streams)
+ {
+ if (string.Equals(stream.display_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
+ {
+ stream.display_aspect_ratio = string.Empty;
+ }
+ if (string.Equals(stream.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
+ {
+ stream.sample_aspect_ratio = string.Empty;
+ }
+ }
+ }
+
+ var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, isAudio, primaryPath, protocol);
+
+ if (extractKeyFrameInterval && mediaInfo.RunTimeTicks.HasValue)
+ {
+ foreach (var stream in mediaInfo.MediaStreams)
+ {
+ if (stream.Type == MediaStreamType.Video && string.Equals(stream.Codec, "h264", StringComparison.OrdinalIgnoreCase))
+ {
+ try
+ {
+ //stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken)
+ // .ConfigureAwait(false);
+ }
+ catch (OperationCanceledException)
+ {
+
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error getting key frame interval", ex);
+ }
+ }
+ }
+ }
+
+ return mediaInfo;
+ }
}
catch
{
- // Hate having to do this
- try
- {
- process.Kill();
- }
- catch (Exception ex1)
- {
- _logger.ErrorException("Error killing ffprobe", ex1);
- }
+ StopProcess(processWrapper, 100, true);
throw;
}
@@ -221,30 +275,102 @@ namespace MediaBrowser.MediaEncoding.Encoder
_ffProbeResourcePool.Release();
}
- if (result == null)
+ throw new ApplicationException(string.Format("FFProbe failed for {0}", inputPath));
+ }
+
+ private async Task<List<int>> GetKeyFrames(string inputPath, int videoStreamIndex, CancellationToken cancellationToken)
+ {
+ const string args = "-i {0} -select_streams v:{1} -show_frames -show_entries frame=pkt_dts,key_frame -print_format compact";
+
+ var process = new Process
{
- throw new ApplicationException(string.Format("FFProbe failed for {0}", inputPath));
+ StartInfo = new ProcessStartInfo
+ {
+ CreateNoWindow = true,
+ UseShellExecute = false,
+
+ // Must consume both or ffmpeg may hang due to deadlocks. See comments below.
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ RedirectStandardInput = true,
+ FileName = FFProbePath,
+ Arguments = string.Format(args, inputPath, videoStreamIndex.ToString(CultureInfo.InvariantCulture)).Trim(),
+
+ WindowStyle = ProcessWindowStyle.Hidden,
+ ErrorDialog = false
+ },
+
+ EnableRaisingEvents = true
+ };
+
+ _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
+
+ var processWrapper = new ProcessWrapper(process, this);
+
+ StartProcess(processWrapper);
+
+ var lines = new List<int>();
+
+ try
+ {
+ process.BeginErrorReadLine();
+
+ await StartReadingOutput(process.StandardOutput.BaseStream, lines, 120000, cancellationToken).ConfigureAwait(false);
+ }
+ catch (OperationCanceledException)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ throw;
+ }
+ }
+ finally
+ {
+ StopProcess(processWrapper, 100, true);
}
- cancellationToken.ThrowIfCancellationRequested();
+ return lines;
+ }
- if (result.streams != null)
+ private async Task StartReadingOutput(Stream source, List<int> lines, int timeoutMs, CancellationToken cancellationToken)
+ {
+ try
{
- // Normalize aspect ratio if invalid
- foreach (var stream in result.streams)
+ using (var reader = new StreamReader(source))
{
- if (string.Equals(stream.display_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
+ while (!reader.EndOfStream)
{
- stream.display_aspect_ratio = string.Empty;
- }
- if (string.Equals(stream.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
- {
- stream.sample_aspect_ratio = string.Empty;
+ cancellationToken.ThrowIfCancellationRequested();
+
+ var line = await reader.ReadLineAsync().ConfigureAwait(false);
+
+ var values = (line ?? string.Empty).Split('|')
+ .Where(i => !string.IsNullOrWhiteSpace(i))
+ .Select(i => i.Split('='))
+ .Where(i => i.Length == 2)
+ .ToDictionary(i => i[0], i => i[1]);
+
+ string pktDts;
+ int frameMs;
+ if (values.TryGetValue("pkt_dts", out pktDts) && int.TryParse(pktDts, NumberStyles.Any, CultureInfo.InvariantCulture, out frameMs))
+ {
+ string keyFrame;
+ if (values.TryGetValue("key_frame", out keyFrame) && string.Equals(keyFrame, "1", StringComparison.OrdinalIgnoreCase))
+ {
+ lines.Add(frameMs);
+ }
+ }
}
}
}
-
- return result;
+ catch (OperationCanceledException)
+ {
+ throw;
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error reading ffprobe output", ex);
+ }
}
/// <summary>
@@ -252,16 +378,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// </summary>
protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
- /// <summary>
- /// Processes the exited.
- /// </summary>
- /// <param name="sender">The sender.</param>
- /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
- private void ProcessExited(object sender, EventArgs e)
- {
- ((Process)sender).Dispose();
- }
-
public Task<Stream> ExtractAudioImage(string path, CancellationToken cancellationToken)
{
return ExtractImage(new[] { path }, MediaProtocol.File, true, null, null, cancellationToken);
@@ -286,6 +402,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
return await ExtractImageInternal(inputArgument, protocol, threedFormat, offset, true, resourcePool, cancellationToken).ConfigureAwait(false);
}
+ catch (ArgumentException)
+ {
+ throw;
+ }
catch
{
_logger.Error("I-frame image extraction failed, will attempt standard way. Input: {0}", inputArgument);
@@ -368,41 +488,37 @@ namespace MediaBrowser.MediaEncoding.Encoder
await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
- process.Start();
+ var processWrapper = new ProcessWrapper(process, this);
+ bool ranToCompletion;
var memoryStream = new MemoryStream();
+ try
+ {
+ StartProcess(processWrapper);
+
#pragma warning disable 4014
- // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
- process.StandardOutput.BaseStream.CopyToAsync(memoryStream);
+ // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
+ process.StandardOutput.BaseStream.CopyToAsync(memoryStream);
#pragma warning restore 4014
- // MUST read both stdout and stderr asynchronously or a deadlock may occurr
- process.BeginErrorReadLine();
-
- var ranToCompletion = process.WaitForExit(10000);
-
- if (!ranToCompletion)
- {
- try
- {
- _logger.Info("Killing ffmpeg process");
+ // MUST read both stdout and stderr asynchronously or a deadlock may occurr
+ process.BeginErrorReadLine();
- process.StandardInput.WriteLine("q");
+ ranToCompletion = process.WaitForExit(10000);
- process.WaitForExit(1000);
- }
- catch (Exception ex)
+ if (!ranToCompletion)
{
- _logger.ErrorException("Error killing process", ex);
+ StopProcess(processWrapper, 1000, false);
}
- }
- resourcePool.Release();
-
- var exitCode = ranToCompletion ? process.ExitCode : -1;
+ }
+ finally
+ {
+ resourcePool.Release();
+ }
- process.Dispose();
+ var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
if (exitCode == -1 || memoryStream.Length == 0)
{
@@ -419,31 +535,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
return memoryStream;
}
- public Task<Stream> EncodeImage(ImageEncodingOptions options, CancellationToken cancellationToken)
- {
- throw new NotImplementedException();
- }
-
- /// <summary>
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- /// </summary>
- public void Dispose()
- {
- Dispose(true);
- }
-
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources.
- /// </summary>
- /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool dispose)
- {
- if (dispose)
- {
- _videoImageResourcePool.Dispose();
- }
- }
-
public string GetTimeParameter(long ticks)
{
var time = TimeSpan.FromTicks(ticks);
@@ -508,11 +599,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
- bool ranToCompletion;
+ bool ranToCompletion = false;
+
+ var processWrapper = new ProcessWrapper(process, this);
try
{
- process.Start();
+ StartProcess(processWrapper);
// Need to give ffmpeg enough time to make all the thumbnails, which could be a while,
// but we still need to detect if the process hangs.
@@ -521,33 +614,26 @@ namespace MediaBrowser.MediaEncoding.Encoder
bool isResponsive = true;
int lastCount = 0;
- while (isResponsive && !process.WaitForExit(30000))
+ while (isResponsive)
{
+ if (process.WaitForExit(30000))
+ {
+ ranToCompletion = true;
+ break;
+ }
+
cancellationToken.ThrowIfCancellationRequested();
- int jpegCount = Directory.GetFiles(targetDirectory)
+ var jpegCount = Directory.GetFiles(targetDirectory)
.Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase));
isResponsive = (jpegCount > lastCount);
lastCount = jpegCount;
}
- ranToCompletion = process.HasExited;
-
if (!ranToCompletion)
{
- try
- {
- _logger.Info("Killing ffmpeg process");
-
- process.StandardInput.WriteLine("q");
-
- process.WaitForExit(1000);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error killing process", ex);
- }
+ StopProcess(processWrapper, 1000, false);
}
}
finally
@@ -555,9 +641,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
resourcePool.Release();
}
- var exitCode = ranToCompletion ? process.ExitCode : -1;
-
- process.Dispose();
+ var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
if (exitCode == -1)
{
@@ -608,5 +692,122 @@ namespace MediaBrowser.MediaEncoding.Encoder
return job.OutputFilePath;
}
+
+ private void StartProcess(ProcessWrapper process)
+ {
+ process.Process.Start();
+
+ lock (_runningProcesses)
+ {
+ _runningProcesses.Add(process);
+ }
+ }
+ private void StopProcess(ProcessWrapper process, int waitTimeMs, bool enableForceKill)
+ {
+ try
+ {
+ _logger.Info("Killing ffmpeg process");
+
+ try
+ {
+ process.Process.StandardInput.WriteLine("q");
+ }
+ catch (Exception)
+ {
+ _logger.Error("Error sending q command to process");
+ }
+
+ try
+ {
+ if (process.Process.WaitForExit(waitTimeMs))
+ {
+ return;
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.Error("Error in WaitForExit", ex);
+ }
+
+ if (enableForceKill)
+ {
+ process.Process.Kill();
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error killing process", ex);
+ }
+ }
+
+ private void StopProcesses()
+ {
+ List<ProcessWrapper> proceses;
+ lock (_runningProcesses)
+ {
+ proceses = _runningProcesses.ToList();
+ }
+ _runningProcesses.Clear();
+
+ foreach (var process in proceses)
+ {
+ if (!process.HasExited)
+ {
+ StopProcess(process, 500, true);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ /// </summary>
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ /// <summary>
+ /// Releases unmanaged and - optionally - managed resources.
+ /// </summary>
+ /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
+ protected virtual void Dispose(bool dispose)
+ {
+ if (dispose)
+ {
+ _videoImageResourcePool.Dispose();
+ StopProcesses();
+ }
+ }
+
+ private class ProcessWrapper
+ {
+ public readonly Process Process;
+ public bool HasExited;
+ public int? ExitCode;
+ private readonly MediaEncoder _mediaEncoder;
+
+ public ProcessWrapper(Process process, MediaEncoder mediaEncoder)
+ {
+ Process = process;
+ this._mediaEncoder = mediaEncoder;
+ Process.Exited += Process_Exited;
+ }
+
+ void Process_Exited(object sender, EventArgs e)
+ {
+ var process = (Process)sender;
+
+ HasExited = true;
+
+ ExitCode = process.ExitCode;
+
+ lock (_mediaEncoder._runningProcesses)
+ {
+ _mediaEncoder._runningProcesses.Remove(this);
+ }
+
+ process.Dispose();
+ }
+ }
}
}
diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
index 72dc0feac..ad561c484 100644
--- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
+++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
@@ -68,6 +68,9 @@
<Compile Include="Encoder\JobLogger.cs" />
<Compile Include="Encoder\MediaEncoder.cs" />
<Compile Include="Encoder\VideoEncoder.cs" />
+ <Compile Include="Probing\FFProbeHelpers.cs" />
+ <Compile Include="Probing\InternalMediaInfoResult.cs" />
+ <Compile Include="Probing\ProbeResultNormalizer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Subtitles\ISubtitleParser.cs" />
<Compile Include="Subtitles\ISubtitleWriter.cs" />
@@ -91,6 +94,10 @@
<Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
<Name>MediaBrowser.Controller</Name>
</ProjectReference>
+ <ProjectReference Include="..\MediaBrowser.MediaInfo\MediaBrowser.MediaInfo.csproj">
+ <Project>{6e4145e4-c6d4-4e4d-94f2-87188db6e239}</Project>
+ <Name>MediaBrowser.MediaInfo</Name>
+ </ProjectReference>
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
<Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
<Name>MediaBrowser.Model</Name>
@@ -99,7 +106,9 @@
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
- <ItemGroup />
+ <ItemGroup>
+ <EmbeddedResource Include="Probing\whitelist.txt" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeHelpers.cs b/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs
index 2044979e4..859f38950 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeHelpers.cs
+++ b/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs
@@ -2,7 +2,7 @@
using System;
using System.Collections.Generic;
-namespace MediaBrowser.Providers.MediaInfo
+namespace MediaBrowser.MediaEncoding.Probing
{
public static class FFProbeHelpers
{
diff --git a/MediaBrowser.Controller/MediaEncoding/InternalMediaInfoResult.cs b/MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs
index 796fdb723..9b95e83e7 100644
--- a/MediaBrowser.Controller/MediaEncoding/InternalMediaInfoResult.cs
+++ b/MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
-namespace MediaBrowser.Controller.MediaEncoding
+namespace MediaBrowser.MediaEncoding.Probing
{
/// <summary>
/// Class MediaInfoResult
@@ -89,7 +89,7 @@ namespace MediaBrowser.Controller.MediaEncoding
/// </summary>
/// <value>The channel_layout.</value>
public string channel_layout { get; set; }
-
+
/// <summary>
/// Gets or sets the avg_frame_rate.
/// </summary>
@@ -317,7 +317,7 @@ namespace MediaBrowser.Controller.MediaEncoding
/// </summary>
/// <value>The probe_score.</value>
public int probe_score { get; set; }
-
+
/// <summary>
/// Gets or sets the tags.
/// </summary>
diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
new file mode 100644
index 000000000..267ff875a
--- /dev/null
+++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
@@ -0,0 +1,887 @@
+using MediaBrowser.Common.IO;
+using MediaBrowser.MediaInfo;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Extensions;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.MediaInfo;
+
+namespace MediaBrowser.MediaEncoding.Probing
+{
+ public class ProbeResultNormalizer
+ {
+ private readonly CultureInfo _usCulture = new CultureInfo("en-US");
+ private readonly ILogger _logger;
+ private readonly IFileSystem _fileSystem;
+
+ public ProbeResultNormalizer(ILogger logger, IFileSystem fileSystem)
+ {
+ _logger = logger;
+ _fileSystem = fileSystem;
+ }
+
+ public Model.MediaInfo.MediaInfo GetMediaInfo(InternalMediaInfoResult data, bool isAudio, string path, MediaProtocol protocol)
+ {
+ var info = new Model.MediaInfo.MediaInfo
+ {
+ Path = path,
+ Protocol = protocol
+ };
+
+ FFProbeHelpers.NormalizeFFProbeResult(data);
+ SetSize(data, info);
+
+ var internalStreams = data.streams ?? new MediaStreamInfo[] { };
+
+ info.MediaStreams = internalStreams.Select(s => GetMediaStream(s, data.format))
+ .Where(i => i != null)
+ .ToList();
+
+ if (data.format != null)
+ {
+ info.Container = data.format.format_name;
+
+ if (!string.IsNullOrEmpty(data.format.bit_rate))
+ {
+ info.Bitrate = int.Parse(data.format.bit_rate, _usCulture);
+ }
+ }
+
+ if (isAudio)
+ {
+ SetAudioRuntimeTicks(data, info);
+
+ if (data.format != null && data.format.tags != null)
+ {
+ SetAudioInfoFromTags(info, data.format.tags);
+ }
+ }
+ else
+ {
+ if (data.format != null && !string.IsNullOrEmpty(data.format.duration))
+ {
+ info.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.format.duration, _usCulture)).Ticks;
+ }
+
+ FetchWtvInfo(info, data);
+
+ if (data.Chapters != null)
+ {
+ info.Chapters = data.Chapters.Select(GetChapterInfo).ToList();
+ }
+
+ ExtractTimestamp(info);
+
+ var videoStream = info.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
+
+ if (videoStream != null)
+ {
+ UpdateFromMediaInfo(info, videoStream);
+ }
+ }
+
+ return info;
+ }
+
+ /// <summary>
+ /// Converts ffprobe stream info to our MediaStream class
+ /// </summary>
+ /// <param name="streamInfo">The stream info.</param>
+ /// <param name="formatInfo">The format info.</param>
+ /// <returns>MediaStream.</returns>
+ private MediaStream GetMediaStream(MediaStreamInfo streamInfo, MediaFormatInfo formatInfo)
+ {
+ var stream = new MediaStream
+ {
+ Codec = streamInfo.codec_name,
+ Profile = streamInfo.profile,
+ Level = streamInfo.level,
+ Index = streamInfo.index,
+ PixelFormat = streamInfo.pix_fmt
+ };
+
+ if (streamInfo.tags != null)
+ {
+ stream.Language = GetDictionaryValue(streamInfo.tags, "language");
+ }
+
+ if (string.Equals(streamInfo.codec_type, "audio", StringComparison.OrdinalIgnoreCase))
+ {
+ stream.Type = MediaStreamType.Audio;
+
+ stream.Channels = streamInfo.channels;
+
+ if (!string.IsNullOrEmpty(streamInfo.sample_rate))
+ {
+ stream.SampleRate = int.Parse(streamInfo.sample_rate, _usCulture);
+ }
+
+ stream.ChannelLayout = ParseChannelLayout(streamInfo.channel_layout);
+ }
+ else if (string.Equals(streamInfo.codec_type, "subtitle", StringComparison.OrdinalIgnoreCase))
+ {
+ stream.Type = MediaStreamType.Subtitle;
+ }
+ else if (string.Equals(streamInfo.codec_type, "video", StringComparison.OrdinalIgnoreCase))
+ {
+ stream.Type = (streamInfo.codec_name ?? string.Empty).IndexOf("mjpeg", StringComparison.OrdinalIgnoreCase) != -1
+ ? MediaStreamType.EmbeddedImage
+ : MediaStreamType.Video;
+
+ stream.Width = streamInfo.width;
+ stream.Height = streamInfo.height;
+ stream.AspectRatio = GetAspectRatio(streamInfo);
+
+ stream.AverageFrameRate = GetFrameRate(streamInfo.avg_frame_rate);
+ stream.RealFrameRate = GetFrameRate(streamInfo.r_frame_rate);
+
+ stream.BitDepth = GetBitDepth(stream.PixelFormat);
+
+ //stream.IsAnamorphic = string.Equals(streamInfo.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase) ||
+ // string.Equals(stream.AspectRatio, "2.35:1", StringComparison.OrdinalIgnoreCase) ||
+ // string.Equals(stream.AspectRatio, "2.40:1", StringComparison.OrdinalIgnoreCase);
+
+ stream.IsAnamorphic = string.Equals(streamInfo.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase);
+ }
+ else
+ {
+ return null;
+ }
+
+ // Get stream bitrate
+ var bitrate = 0;
+
+ if (!string.IsNullOrEmpty(streamInfo.bit_rate))
+ {
+ bitrate = int.Parse(streamInfo.bit_rate, _usCulture);
+ }
+ else if (formatInfo != null && !string.IsNullOrEmpty(formatInfo.bit_rate) && stream.Type == MediaStreamType.Video)
+ {
+ // If the stream info doesn't have a bitrate get the value from the media format info
+ bitrate = int.Parse(formatInfo.bit_rate, _usCulture);
+ }
+
+ if (bitrate > 0)
+ {
+ stream.BitRate = bitrate;
+ }
+
+ if (streamInfo.disposition != null)
+ {
+ var isDefault = GetDictionaryValue(streamInfo.disposition, "default");
+ var isForced = GetDictionaryValue(streamInfo.disposition, "forced");
+
+ stream.IsDefault = string.Equals(isDefault, "1", StringComparison.OrdinalIgnoreCase);
+
+ stream.IsForced = string.Equals(isForced, "1", StringComparison.OrdinalIgnoreCase);
+ }
+
+ return stream;
+ }
+
+ private int? GetBitDepth(string pixelFormat)
+ {
+ var eightBit = new List<string>
+ {
+ "yuv420p",
+ "yuv411p",
+ "yuvj420p",
+ "uyyvyy411",
+ "nv12",
+ "nv21",
+ "rgb444le",
+ "rgb444be",
+ "bgr444le",
+ "bgr444be",
+ "yuvj411p"
+ };
+
+ if (!string.IsNullOrEmpty(pixelFormat))
+ {
+ if (eightBit.Contains(pixelFormat, StringComparer.OrdinalIgnoreCase))
+ {
+ return 8;
+ }
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Gets a string from an FFProbeResult tags dictionary
+ /// </summary>
+ /// <param name="tags">The tags.</param>
+ /// <param name="key">The key.</param>
+ /// <returns>System.String.</returns>
+ private string GetDictionaryValue(Dictionary<string, string> tags, string key)
+ {
+ if (tags == null)
+ {
+ return null;
+ }
+
+ string val;
+
+ tags.TryGetValue(key, out val);
+ return val;
+ }
+
+ private string ParseChannelLayout(string input)
+ {
+ if (string.IsNullOrEmpty(input))
+ {
+ return input;
+ }
+
+ return input.Split('(').FirstOrDefault();
+ }
+
+ private string GetAspectRatio(MediaStreamInfo info)
+ {
+ var original = info.display_aspect_ratio;
+
+ int height;
+ int width;
+
+ var parts = (original ?? string.Empty).Split(':');
+ if (!(parts.Length == 2 &&
+ int.TryParse(parts[0], NumberStyles.Any, _usCulture, out width) &&
+ int.TryParse(parts[1], NumberStyles.Any, _usCulture, out height) &&
+ width > 0 &&
+ height > 0))
+ {
+ width = info.width;
+ height = info.height;
+ }
+
+ if (width > 0 && height > 0)
+ {
+ double ratio = width;
+ ratio /= height;
+
+ if (IsClose(ratio, 1.777777778, .03))
+ {
+ return "16:9";
+ }
+
+ if (IsClose(ratio, 1.3333333333, .05))
+ {
+ return "4:3";
+ }
+
+ if (IsClose(ratio, 1.41))
+ {
+ return "1.41:1";
+ }
+
+ if (IsClose(ratio, 1.5))
+ {
+ return "1.5:1";
+ }
+
+ if (IsClose(ratio, 1.6))
+ {
+ return "1.6:1";
+ }
+
+ if (IsClose(ratio, 1.66666666667))
+ {
+ return "5:3";
+ }
+
+ if (IsClose(ratio, 1.85, .02))
+ {
+ return "1.85:1";
+ }
+
+ if (IsClose(ratio, 2.35, .025))
+ {
+ return "2.35:1";
+ }
+
+ if (IsClose(ratio, 2.4, .025))
+ {
+ return "2.40:1";
+ }
+ }
+
+ return original;
+ }
+
+ private bool IsClose(double d1, double d2, double variance = .005)
+ {
+ return Math.Abs(d1 - d2) <= variance;
+ }
+
+ /// <summary>
+ /// Gets a frame rate from a string value in ffprobe output
+ /// This could be a number or in the format of 2997/125.
+ /// </summary>
+ /// <param name="value">The value.</param>
+ /// <returns>System.Nullable{System.Single}.</returns>
+ private float? GetFrameRate(string value)
+ {
+ if (!string.IsNullOrEmpty(value))
+ {
+ var parts = value.Split('/');
+
+ float result;
+
+ if (parts.Length == 2)
+ {
+ result = float.Parse(parts[0], _usCulture) / float.Parse(parts[1], _usCulture);
+ }
+ else
+ {
+ result = float.Parse(parts[0], _usCulture);
+ }
+
+ return float.IsNaN(result) ? (float?)null : result;
+ }
+
+ return null;
+ }
+
+ private void SetAudioRuntimeTicks(InternalMediaInfoResult result, Model.MediaInfo.MediaInfo data)
+ {
+ if (result.streams != null)
+ {
+ // Get the first audio stream
+ var stream = result.streams.FirstOrDefault(s => string.Equals(s.codec_type, "audio", StringComparison.OrdinalIgnoreCase));
+
+ if (stream != null)
+ {
+ // Get duration from stream properties
+ var duration = stream.duration;
+
+ // If it's not there go into format properties
+ if (string.IsNullOrEmpty(duration))
+ {
+ duration = result.format.duration;
+ }
+
+ // If we got something, parse it
+ if (!string.IsNullOrEmpty(duration))
+ {
+ data.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(duration, _usCulture)).Ticks;
+ }
+ }
+ }
+ }
+
+ private void SetSize(InternalMediaInfoResult data, Model.MediaInfo.MediaInfo info)
+ {
+ if (data.format != null)
+ {
+ if (!string.IsNullOrEmpty(data.format.size))
+ {
+ info.Size = long.Parse(data.format.size, _usCulture);
+ }
+ else
+ {
+ info.Size = null;
+ }
+ }
+ }
+
+ private void SetAudioInfoFromTags(Model.MediaInfo.MediaInfo audio, Dictionary<string, string> tags)
+ {
+ var title = FFProbeHelpers.GetDictionaryValue(tags, "title");
+
+ // Only set Name if title was found in the dictionary
+ if (!string.IsNullOrEmpty(title))
+ {
+ audio.Title = title;
+ }
+
+ var composer = FFProbeHelpers.GetDictionaryValue(tags, "composer");
+
+ if (!string.IsNullOrWhiteSpace(composer))
+ {
+ foreach (var person in Split(composer, false))
+ {
+ audio.People.Add(new BaseItemPerson { Name = person, Type = PersonType.Composer });
+ }
+ }
+
+ audio.Album = FFProbeHelpers.GetDictionaryValue(tags, "album");
+
+ var artists = FFProbeHelpers.GetDictionaryValue(tags, "artists");
+
+ if (!string.IsNullOrWhiteSpace(artists))
+ {
+ audio.Artists = artists.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries)
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .ToList();
+ }
+ else
+ {
+ var artist = FFProbeHelpers.GetDictionaryValue(tags, "artist");
+ if (string.IsNullOrWhiteSpace(artist))
+ {
+ audio.Artists.Clear();
+ }
+ else
+ {
+ audio.Artists = SplitArtists(artist)
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .ToList();
+ }
+ }
+
+ var albumArtist = FFProbeHelpers.GetDictionaryValue(tags, "albumartist");
+ if (string.IsNullOrWhiteSpace(albumArtist))
+ {
+ albumArtist = FFProbeHelpers.GetDictionaryValue(tags, "album artist");
+ }
+ if (string.IsNullOrWhiteSpace(albumArtist))
+ {
+ albumArtist = FFProbeHelpers.GetDictionaryValue(tags, "album_artist");
+ }
+
+ if (string.IsNullOrWhiteSpace(albumArtist))
+ {
+ audio.AlbumArtists = new List<string>();
+ }
+ else
+ {
+ audio.AlbumArtists = SplitArtists(albumArtist)
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .ToList();
+
+ }
+
+ // Track number
+ audio.IndexNumber = GetDictionaryDiscValue(tags, "track");
+
+ // Disc number
+ audio.ParentIndexNumber = GetDictionaryDiscValue(tags, "disc");
+
+ 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") ??
+ FFProbeHelpers.GetDictionaryDateTime(tags, "date");
+
+ // If we don't have a ProductionYear try and get it from PremiereDate
+ if (audio.PremiereDate.HasValue && !audio.ProductionYear.HasValue)
+ {
+ audio.ProductionYear = audio.PremiereDate.Value.ToLocalTime().Year;
+ }
+
+ FetchGenres(audio, tags);
+
+ // There's several values in tags may or may not be present
+ FetchStudios(audio, tags, "organization");
+ FetchStudios(audio, tags, "ensemble");
+ FetchStudios(audio, tags, "publisher");
+
+ // These support mulitple values, but for now we only store the first.
+ audio.SetProviderId(MetadataProviders.MusicBrainzAlbumArtist, GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Album Artist Id")));
+ audio.SetProviderId(MetadataProviders.MusicBrainzArtist, GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Artist Id")));
+
+ audio.SetProviderId(MetadataProviders.MusicBrainzAlbum, GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Album Id")));
+ audio.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Release Group Id")));
+ audio.SetProviderId(MetadataProviders.MusicBrainzTrack, GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Release Track Id")));
+ }
+
+ private string GetMultipleMusicBrainzId(string value)
+ {
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ return null;
+ }
+
+ return value.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries)
+ .Select(i => i.Trim())
+ .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i));
+ }
+
+ private readonly char[] _nameDelimiters = { '/', '|', ';', '\\' };
+
+ /// <summary>
+ /// Splits the specified val.
+ /// </summary>
+ /// <param name="val">The val.</param>
+ /// <param name="allowCommaDelimiter">if set to <c>true</c> [allow comma delimiter].</param>
+ /// <returns>System.String[][].</returns>
+ private IEnumerable<string> Split(string val, bool allowCommaDelimiter)
+ {
+ // 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 :
+ new[] { ',' };
+
+ return val.Split(delimeter, StringSplitOptions.RemoveEmptyEntries)
+ .Where(i => !string.IsNullOrWhiteSpace(i))
+ .Select(i => i.Trim());
+ }
+
+ private const string ArtistReplaceValue = " | ";
+
+ private IEnumerable<string> SplitArtists(string val)
+ {
+ val = val.Replace(" featuring ", ArtistReplaceValue, StringComparison.OrdinalIgnoreCase)
+ .Replace(" feat. ", ArtistReplaceValue, StringComparison.OrdinalIgnoreCase);
+
+ var artistsFound = new List<string>();
+
+ foreach (var whitelistArtist in GetSplitWhitelist())
+ {
+ var originalVal = val;
+ val = val.Replace(whitelistArtist, "|", StringComparison.OrdinalIgnoreCase);
+
+ if (!string.Equals(originalVal, val, StringComparison.OrdinalIgnoreCase))
+ {
+ artistsFound.Add(whitelistArtist);
+ }
+ }
+
+ // 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 = _nameDelimiters;
+
+ var artists = val.Split(delimeter, StringSplitOptions.RemoveEmptyEntries)
+ .Where(i => !string.IsNullOrWhiteSpace(i))
+ .Select(i => i.Trim());
+
+ artistsFound.AddRange(artists);
+ return artistsFound;
+ }
+
+
+ private List<string> _splitWhiteList = null;
+
+ private IEnumerable<string> GetSplitWhitelist()
+ {
+ if (_splitWhiteList == null)
+ {
+ var file = GetType().Namespace + ".whitelist.txt";
+
+ using (var stream = GetType().Assembly.GetManifestResourceStream(file))
+ {
+ using (var reader = new StreamReader(stream))
+ {
+ var list = new List<string>();
+
+ while (!reader.EndOfStream)
+ {
+ var val = reader.ReadLine();
+
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ list.Add(val);
+ }
+ }
+
+ _splitWhiteList = list;
+ }
+ }
+ }
+
+ return _splitWhiteList;
+ }
+
+ /// <summary>
+ /// Gets the studios from the tags collection
+ /// </summary>
+ /// <param name="audio">The audio.</param>
+ /// <param name="tags">The tags.</param>
+ /// <param name="tagName">Name of the tag.</param>
+ private void FetchStudios(Model.MediaInfo.MediaInfo audio, Dictionary<string, string> tags, string tagName)
+ {
+ var val = FFProbeHelpers.GetDictionaryValue(tags, tagName);
+
+ if (!string.IsNullOrEmpty(val))
+ {
+ var studios = Split(val, true);
+
+ foreach (var studio in studios)
+ {
+ // Sometimes the artist name is listed here, account for that
+ if (audio.Artists.Contains(studio, StringComparer.OrdinalIgnoreCase))
+ {
+ continue;
+ }
+ if (audio.AlbumArtists.Contains(studio, StringComparer.OrdinalIgnoreCase))
+ {
+ continue;
+ }
+
+ audio.Studios.Add(studio);
+ }
+
+ audio.Studios = audio.Studios
+ .Where(i => !string.IsNullOrWhiteSpace(i))
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .ToList();
+ }
+ }
+
+ /// <summary>
+ /// Gets the genres from the tags collection
+ /// </summary>
+ /// <param name="info">The information.</param>
+ /// <param name="tags">The tags.</param>
+ private void FetchGenres(Model.MediaInfo.MediaInfo info, Dictionary<string, string> tags)
+ {
+ var val = FFProbeHelpers.GetDictionaryValue(tags, "genre");
+
+ if (!string.IsNullOrEmpty(val))
+ {
+ foreach (var genre in Split(val, true))
+ {
+ info.Genres.Add(genre);
+ }
+
+ info.Genres = info.Genres
+ .Where(i => !string.IsNullOrWhiteSpace(i))
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .ToList();
+ }
+ }
+
+ /// <summary>
+ /// Gets the disc number, which is sometimes can be in the form of '1', or '1/3'
+ /// </summary>
+ /// <param name="tags">The tags.</param>
+ /// <param name="tagName">Name of the tag.</param>
+ /// <returns>System.Nullable{System.Int32}.</returns>
+ private int? GetDictionaryDiscValue(Dictionary<string, string> tags, string tagName)
+ {
+ var disc = FFProbeHelpers.GetDictionaryValue(tags, tagName);
+
+ if (!string.IsNullOrEmpty(disc))
+ {
+ disc = disc.Split('/')[0];
+
+ int num;
+
+ if (int.TryParse(disc, out num))
+ {
+ return num;
+ }
+ }
+
+ return null;
+ }
+
+ private ChapterInfo GetChapterInfo(MediaChapter chapter)
+ {
+ var info = new ChapterInfo();
+
+ if (chapter.tags != null)
+ {
+ string name;
+ if (chapter.tags.TryGetValue("title", out name))
+ {
+ info.Name = name;
+ }
+ }
+
+ // Limit accuracy to milliseconds to match xml saving
+ var secondsString = chapter.start_time;
+ double seconds;
+
+ if (double.TryParse(secondsString, NumberStyles.Any, CultureInfo.InvariantCulture, out seconds))
+ {
+ var ms = Math.Round(TimeSpan.FromSeconds(seconds).TotalMilliseconds);
+ info.StartPositionTicks = TimeSpan.FromMilliseconds(ms).Ticks;
+ }
+
+ return info;
+ }
+
+ private const int MaxSubtitleDescriptionExtractionLength = 100; // When extracting subtitles, the maximum length to consider (to avoid invalid filenames)
+
+ private void FetchWtvInfo(Model.MediaInfo.MediaInfo video, InternalMediaInfoResult data)
+ {
+ if (data.format == null || data.format.tags == null)
+ {
+ return;
+ }
+
+ var genres = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/Genre");
+
+ if (!string.IsNullOrWhiteSpace(genres))
+ {
+ //genres = FFProbeHelpers.GetDictionaryValue(data.format.tags, "genre");
+ }
+
+ if (!string.IsNullOrWhiteSpace(genres))
+ {
+ video.Genres = genres.Split(new[] { ';', '/', ',' }, StringSplitOptions.RemoveEmptyEntries)
+ .Where(i => !string.IsNullOrWhiteSpace(i))
+ .Select(i => i.Trim())
+ .ToList();
+ }
+
+ var officialRating = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/ParentalRating");
+
+ if (!string.IsNullOrWhiteSpace(officialRating))
+ {
+ video.OfficialRating = officialRating;
+ }
+
+ var people = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/MediaCredits");
+
+ if (!string.IsNullOrEmpty(people))
+ {
+ video.People = people.Split(new[] { ';', '/' }, StringSplitOptions.RemoveEmptyEntries)
+ .Where(i => !string.IsNullOrWhiteSpace(i))
+ .Select(i => new BaseItemPerson { Name = i.Trim(), Type = PersonType.Actor })
+ .ToList();
+ }
+
+ var year = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/OriginalReleaseTime");
+ if (!string.IsNullOrWhiteSpace(year))
+ {
+ int val;
+
+ if (int.TryParse(year, NumberStyles.Integer, _usCulture, out val))
+ {
+ video.ProductionYear = val;
+ }
+ }
+
+ var premiereDateString = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/MediaOriginalBroadcastDateTime");
+ if (!string.IsNullOrWhiteSpace(premiereDateString))
+ {
+ DateTime val;
+
+ // Credit to MCEBuddy: https://mcebuddy2x.codeplex.com/
+ // DateTime is reported along with timezone info (typically Z i.e. UTC hence assume None)
+ if (DateTime.TryParse(year, null, DateTimeStyles.None, out val))
+ {
+ video.PremiereDate = val.ToUniversalTime();
+ }
+ }
+
+ var description = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/SubTitleDescription");
+
+ var subTitle = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/SubTitle");
+
+ // For below code, credit to MCEBuddy: https://mcebuddy2x.codeplex.com/
+
+ // Sometimes for TV Shows the Subtitle field is empty and the subtitle description contains the subtitle, extract if possible. See ticket https://mcebuddy2x.codeplex.com/workitem/1910
+ // The format is -> EPISODE/TOTAL_EPISODES_IN_SEASON. SUBTITLE: DESCRIPTION
+ // OR -> COMMENT. SUBTITLE: DESCRIPTION
+ // e.g. -> 4/13. The Doctor's Wife: Science fiction drama. When he follows a Time Lord distress signal, the Doctor puts Amy, Rory and his beloved TARDIS in grave danger. Also in HD. [AD,S]
+ // e.g. -> CBeebies Bedtime Hour. The Mystery: Animated adventures of two friends who live on an island in the middle of the big city. Some of Abney and Teal's favourite objects are missing. [S]
+ if (String.IsNullOrWhiteSpace(subTitle) && !String.IsNullOrWhiteSpace(description) && description.Substring(0, Math.Min(description.Length, MaxSubtitleDescriptionExtractionLength)).Contains(":")) // Check within the Subtitle size limit, otherwise from description it can get too long creating an invalid filename
+ {
+ string[] parts = description.Split(':');
+ if (parts.Length > 0)
+ {
+ string subtitle = parts[0];
+ try
+ {
+ if (subtitle.Contains("/")) // It contains a episode number and season number
+ {
+ string[] numbers = subtitle.Split(' ');
+ video.IndexNumber = int.Parse(numbers[0].Replace(".", "").Split('/')[0]);
+ int totalEpisodesInSeason = int.Parse(numbers[0].Replace(".", "").Split('/')[1]);
+
+ description = String.Join(" ", numbers, 1, numbers.Length - 1).Trim(); // Skip the first, concatenate the rest, clean up spaces and save it
+ }
+ else
+ throw new Exception(); // Switch to default parsing
+ }
+ catch // Default parsing
+ {
+ if (subtitle.Contains(".")) // skip the comment, keep the subtitle
+ description = String.Join(".", subtitle.Split('.'), 1, subtitle.Split('.').Length - 1).Trim(); // skip the first
+ else
+ description = subtitle.Trim(); // Clean up whitespaces and save it
+ }
+ }
+ }
+
+ if (!string.IsNullOrWhiteSpace(description))
+ {
+ video.Overview = description;
+ }
+ }
+
+ private void ExtractTimestamp(Model.MediaInfo.MediaInfo video)
+ {
+ if (video.VideoType == VideoType.VideoFile)
+ {
+ if (string.Equals(video.Container, "mpeg2ts", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(video.Container, "m2ts", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(video.Container, "ts", StringComparison.OrdinalIgnoreCase))
+ {
+ try
+ {
+ video.Timestamp = GetMpegTimestamp(video.Path);
+
+ _logger.Debug("Video has {0} timestamp", video.Timestamp);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error extracting timestamp info from {0}", ex, video.Path);
+ video.Timestamp = null;
+ }
+ }
+ }
+ }
+
+ private TransportStreamTimestamp GetMpegTimestamp(string path)
+ {
+ var packetBuffer = new byte['Å'];
+
+ using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
+ {
+ fs.Read(packetBuffer, 0, packetBuffer.Length);
+ }
+
+ if (packetBuffer[0] == 71)
+ {
+ return TransportStreamTimestamp.None;
+ }
+
+ if ((packetBuffer[4] == 71) && (packetBuffer['Ä'] == 71))
+ {
+ if ((packetBuffer[0] == 0) && (packetBuffer[1] == 0) && (packetBuffer[2] == 0) && (packetBuffer[3] == 0))
+ {
+ return TransportStreamTimestamp.Zero;
+ }
+
+ return TransportStreamTimestamp.Valid;
+ }
+
+ return TransportStreamTimestamp.None;
+ }
+
+ private void UpdateFromMediaInfo(MediaSourceInfo video, MediaStream videoStream)
+ {
+ if (video.VideoType == VideoType.VideoFile && video.Protocol == MediaProtocol.File)
+ {
+ if (videoStream != null)
+ {
+ try
+ {
+ var result = new MediaInfoLib().GetVideoInfo(video.Path);
+
+ videoStream.IsCabac = result.IsCabac ?? videoStream.IsCabac;
+ videoStream.IsInterlaced = result.IsInterlaced ?? videoStream.IsInterlaced;
+ videoStream.BitDepth = result.BitDepth ?? videoStream.BitDepth;
+ videoStream.RefFrames = result.RefFrames;
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error running MediaInfo on {0}", ex, video.Path);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/MediaInfo/whitelist.txt b/MediaBrowser.MediaEncoding/Probing/whitelist.txt
index 1fd366551..1fd366551 100644
--- a/MediaBrowser.Providers/MediaInfo/whitelist.txt
+++ b/MediaBrowser.MediaEncoding/Probing/whitelist.txt
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
index 14d3e7284..60b70ad08 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
@@ -132,7 +132,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
int subtitleStreamIndex,
CancellationToken cancellationToken)
{
- var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(itemId, false, cancellationToken).ConfigureAwait(false);
+ var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(itemId, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false);
var mediaSource = mediaSources
.First(i => string.Equals(i.Id, mediaSourceId));
diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
index fdedc51a2..87378fd5a 100644
--- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
+++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
@@ -464,6 +464,9 @@
<Compile Include="..\MediaBrowser.Model\Dto\IHasServerId.cs">
<Link>Dto\IHasServerId.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Dto\IHasSyncInfo.cs">
+ <Link>Dto\IHasSyncInfo.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Dto\IItemDto.cs">
<Link>Dto\IItemDto.cs</Link>
</Compile>
@@ -485,6 +488,9 @@
<Compile Include="..\MediaBrowser.Model\Dto\ItemIndex.cs">
<Link>Dto\ItemIndex.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Dto\ItemLayout.cs">
+ <Link>Dto\ItemLayout.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Dto\MediaSourceInfo.cs">
<Link>Dto\MediaSourceInfo.cs</Link>
</Compile>
@@ -560,9 +566,6 @@
<Compile Include="..\MediaBrowser.Model\Entities\MBRegistrationRecord.cs">
<Link>Entities\MBRegistrationRecord.cs</Link>
</Compile>
- <Compile Include="..\MediaBrowser.Model\Entities\MediaInfo.cs">
- <Link>Entities\MediaInfo.cs</Link>
- </Compile>
<Compile Include="..\MediaBrowser.Model\Entities\MediaStream.cs">
<Link>Entities\MediaStream.cs</Link>
</Compile>
@@ -809,6 +812,9 @@
<Compile Include="..\MediaBrowser.Model\MediaInfo\LiveStreamResponse.cs">
<Link>MediaInfo\LiveStreamResponse.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\MediaInfo\MediaInfo.cs">
+ <Link>MediaInfo\MediaInfo.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\MediaInfo\MediaProtocol.cs">
<Link>MediaInfo\MediaProtocol.cs</Link>
</Compile>
diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
index 3618aa972..61057e5bb 100644
--- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
+++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
@@ -429,6 +429,9 @@
<Compile Include="..\MediaBrowser.Model\Dto\IHasServerId.cs">
<Link>Dto\IHasServerId.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Dto\IHasSyncInfo.cs">
+ <Link>Dto\IHasSyncInfo.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Dto\IItemDto.cs">
<Link>Dto\IItemDto.cs</Link>
</Compile>
@@ -450,6 +453,9 @@
<Compile Include="..\MediaBrowser.Model\Dto\ItemIndex.cs">
<Link>Dto\ItemIndex.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Dto\ItemLayout.cs">
+ <Link>Dto\ItemLayout.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Dto\MediaSourceInfo.cs">
<Link>Dto\MediaSourceInfo.cs</Link>
</Compile>
@@ -525,9 +531,6 @@
<Compile Include="..\MediaBrowser.Model\Entities\MBRegistrationRecord.cs">
<Link>Entities\MBRegistrationRecord.cs</Link>
</Compile>
- <Compile Include="..\MediaBrowser.Model\Entities\MediaInfo.cs">
- <Link>Entities\MediaInfo.cs</Link>
- </Compile>
<Compile Include="..\MediaBrowser.Model\Entities\MediaStream.cs">
<Link>Entities\MediaStream.cs</Link>
</Compile>
@@ -765,6 +768,9 @@
<Compile Include="..\MediaBrowser.Model\MediaInfo\LiveStreamResponse.cs">
<Link>MediaInfo\LiveStreamResponse.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\MediaInfo\MediaInfo.cs">
+ <Link>MediaInfo\MediaInfo.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\MediaInfo\MediaProtocol.cs">
<Link>MediaInfo\MediaProtocol.cs</Link>
</Compile>
diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs
index 9675de38b..8c7ca0ad9 100644
--- a/MediaBrowser.Model/ApiClient/IApiClient.cs
+++ b/MediaBrowser.Model/ApiClient/IApiClient.cs
@@ -1359,7 +1359,7 @@ namespace MediaBrowser.Model.ApiClient
/// <param name="job">The job.</param>
/// <returns>Task.</returns>
Task UpdateSyncJob(SyncJob job);
-
+
/// <summary>
/// Gets the synchronize jobs.
/// </summary>
@@ -1492,5 +1492,12 @@ namespace MediaBrowser.Model.ApiClient
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;LiveStreamResponse&gt;.</returns>
Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, CancellationToken cancellationToken);
+ /// <summary>
+ /// Cancels the synchronize library items.
+ /// </summary>
+ /// <param name="targetId">The target identifier.</param>
+ /// <param name="itemIds">The item ids.</param>
+ /// <returns>Task.</returns>
+ Task CancelSyncLibraryItems(string targetId, IEnumerable<string> itemIds);
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/ApiClient/ServerCredentials.cs b/MediaBrowser.Model/ApiClient/ServerCredentials.cs
index 6ba2a80c8..b5a1a7b49 100644
--- a/MediaBrowser.Model/ApiClient/ServerCredentials.cs
+++ b/MediaBrowser.Model/ApiClient/ServerCredentials.cs
@@ -98,7 +98,7 @@ namespace MediaBrowser.Model.ApiClient
{
var index = 0;
- foreach (var server in servers)
+ foreach (ServerInfo server in servers)
{
if (StringHelper.EqualsIgnoreCase(id, server.Id))
{
@@ -110,5 +110,18 @@ namespace MediaBrowser.Model.ApiClient
return -1;
}
+
+ public ServerInfo GetServer(string id)
+ {
+ foreach (ServerInfo server in Servers)
+ {
+ if (StringHelper.EqualsIgnoreCase(id, server.Id))
+ {
+ return server;
+ }
+ }
+
+ return null;
+ }
}
}
diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs
index afd67eb15..c44a7c94d 100644
--- a/MediaBrowser.Model/Configuration/EncodingOptions.cs
+++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs
@@ -17,7 +17,7 @@ namespace MediaBrowser.Model.Configuration
DownMixAudioBoost = 2;
EncodingQuality = EncodingQuality.Auto;
EnableThrottling = true;
- ThrottleThresholdSeconds = 120;
+ ThrottleThresholdSeconds = 90;
}
}
}
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index bc167333a..ac9bd6b08 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -208,6 +208,7 @@ namespace MediaBrowser.Model.Configuration
public bool EnableAudioArchiveFiles { get; set; }
public bool EnableVideoArchiveFiles { get; set; }
+ public int RemoteClientBitrateLimit { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs
index 9cd8c1067..9a76c69f6 100644
--- a/MediaBrowser.Model/Configuration/UserConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs
@@ -46,6 +46,7 @@ namespace MediaBrowser.Model.Configuration
public bool EnableCinemaMode { get; set; }
public string[] LatestItemsExcludes { get; set; }
+ public string[] PlainFolderViews { get; set; }
public bool HidePlayedInLatest { get; set; }
@@ -62,6 +63,7 @@ namespace MediaBrowser.Model.Configuration
DisplayChannelsWithinViews = new string[] { };
ExcludeFoldersFromGrouping = new string[] { };
+ PlainFolderViews = new string[] { };
DisplayCollectionsView = true;
IncludeTrailersInSuggestions = true;
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index bc9f07d04..30da8bb4c 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs
@@ -1,6 +1,7 @@
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Extensions;
+using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Session;
using System;
@@ -11,13 +12,16 @@ namespace MediaBrowser.Model.Dlna
public class StreamBuilder
{
private readonly ILocalPlayer _localPlayer;
+ private readonly ILogger _logger;
- public StreamBuilder(ILocalPlayer localPlayer)
+ public StreamBuilder(ILocalPlayer localPlayer, ILogger logger)
{
_localPlayer = localPlayer;
+ _logger = logger;
}
- public StreamBuilder()
- : this(new NullLocalPlayer())
+
+ public StreamBuilder(ILogger logger)
+ : this(new NullLocalPlayer(), logger)
{
}
@@ -273,7 +277,7 @@ namespace MediaBrowser.Model.Dlna
// The profile describes what the device supports
// If device requirements are satisfied then allow both direct stream and direct play
- if (IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options)))
+ if (item.SupportsDirectPlay && IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options)))
{
playMethods.Add(PlayMethod.DirectPlay);
}
@@ -353,6 +357,12 @@ namespace MediaBrowser.Model.Dlna
bool isEligibleForDirectPlay = IsEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options), subtitleStream, options);
bool isEligibleForDirectStream = IsEligibleForDirectPlay(item, options.GetMaxBitrate(), subtitleStream, options);
+ _logger.Debug("Profile: {0}, Path: {1}, isEligibleForDirectPlay: {2}, isEligibleForDirectStream: {3}",
+ options.Profile.Name ?? "Unknown Profile",
+ item.Path ?? "Unknown path",
+ isEligibleForDirectPlay,
+ isEligibleForDirectStream);
+
if (isEligibleForDirectPlay || isEligibleForDirectStream)
{
// See if it can be direct played
@@ -446,10 +456,8 @@ namespace MediaBrowser.Model.Dlna
playlistItem.MaxAudioChannels = Math.Min(options.MaxAudioChannels.Value, currentValue);
}
- if (!playlistItem.AudioBitrate.HasValue)
- {
- playlistItem.AudioBitrate = GetAudioBitrate(playlistItem.TargetAudioChannels, playlistItem.TargetAudioCodec);
- }
+ int audioBitrate = GetAudioBitrate(playlistItem.TargetAudioChannels, playlistItem.TargetAudioCodec);
+ playlistItem.AudioBitrate = Math.Min(playlistItem.AudioBitrate ?? audioBitrate, audioBitrate);
int? maxBitrateSetting = options.GetMaxBitrate();
// Honor max rate
@@ -462,9 +470,9 @@ namespace MediaBrowser.Model.Dlna
videoBitrate -= playlistItem.AudioBitrate.Value;
}
+ // Make sure the video bitrate is lower than bitrate settings but at least 64k
int currentValue = playlistItem.VideoBitrate ?? videoBitrate;
-
- playlistItem.VideoBitrate = Math.Min(videoBitrate, currentValue);
+ playlistItem.VideoBitrate = Math.Max(Math.Min(videoBitrate, currentValue), 64000);
}
}
@@ -504,6 +512,10 @@ namespace MediaBrowser.Model.Dlna
if (directPlay == null)
{
+ _logger.Debug("Profile: {0}, No direct play profiles found for Path: {1}",
+ profile.Name ?? "Unknown Profile",
+ mediaSource.Path ?? "Unknown path");
+
return null;
}
@@ -550,6 +562,8 @@ namespace MediaBrowser.Model.Dlna
{
if (!conditionProcessor.IsVideoConditionSatisfied(i, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
{
+ LogConditionFailure(profile, "VideoContainerProfile", i, mediaSource);
+
return null;
}
}
@@ -558,6 +572,10 @@ namespace MediaBrowser.Model.Dlna
if (string.IsNullOrEmpty(videoCodec))
{
+ _logger.Debug("Profile: {0}, DirectPlay=false. Reason=Unknown video codec. Path: {1}",
+ profile.Name ?? "Unknown Profile",
+ mediaSource.Path ?? "Unknown path");
+
return null;
}
@@ -577,6 +595,8 @@ namespace MediaBrowser.Model.Dlna
{
if (!conditionProcessor.IsVideoConditionSatisfied(i, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
{
+ LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource);
+
return null;
}
}
@@ -587,6 +607,10 @@ namespace MediaBrowser.Model.Dlna
if (string.IsNullOrEmpty(audioCodec))
{
+ _logger.Debug("Profile: {0}, DirectPlay=false. Reason=Unknown audio codec. Path: {1}",
+ profile.Name ?? "Unknown Profile",
+ mediaSource.Path ?? "Unknown path");
+
return null;
}
@@ -607,12 +631,14 @@ namespace MediaBrowser.Model.Dlna
bool? isSecondaryAudio = audioStream == null ? null : mediaSource.IsSecondaryAudio(audioStream);
if (!conditionProcessor.IsVideoAudioConditionSatisfied(i, audioChannels, audioBitrate, audioProfile, isSecondaryAudio))
{
+ LogConditionFailure(profile, "VideoAudioCodecProfile", i, mediaSource);
+
return null;
}
}
}
- if (isEligibleForDirectPlay)
+ if (isEligibleForDirectPlay && mediaSource.SupportsDirectPlay)
{
if (mediaSource.Protocol == MediaProtocol.Http)
{
@@ -631,17 +657,26 @@ namespace MediaBrowser.Model.Dlna
}
}
- if (isEligibleForDirectStream)
+ if (isEligibleForDirectStream && mediaSource.SupportsDirectStream)
{
- if (mediaSource.SupportsDirectStream)
- {
- return PlayMethod.DirectStream;
- }
+ return PlayMethod.DirectStream;
}
return null;
}
+ private void LogConditionFailure(DeviceProfile profile, string type, ProfileCondition condition, MediaSourceInfo mediaSource)
+ {
+ _logger.Debug("Profile: {0}, DirectPlay=false. Reason={1}.{2} Condition: {3}. ConditionValue: {4}. IsRequired: {5}. Path: {6}",
+ type,
+ profile.Name ?? "Unknown Profile",
+ condition.Property,
+ condition.Condition,
+ condition.Value ?? string.Empty,
+ condition.IsRequired,
+ mediaSource.Path ?? "Unknown path");
+ }
+
private bool IsEligibleForDirectPlay(MediaSourceInfo item,
int? maxBitrate,
MediaStream subtitleStream,
diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs
index a908c7850..b062bc240 100644
--- a/MediaBrowser.Model/Dlna/StreamInfo.cs
+++ b/MediaBrowser.Model/Dlna/StreamInfo.cs
@@ -70,6 +70,7 @@ namespace MediaBrowser.Model.Dlna
public string SubtitleFormat { get; set; }
public string PlaySessionId { get; set; }
+ public List<MediaSourceInfo> AllMediaSources { get; set; }
public string MediaSourceId
{
@@ -101,7 +102,7 @@ namespace MediaBrowser.Model.Dlna
}
List<string> list = new List<string>();
- foreach (NameValuePair pair in BuildParams(this, accessToken))
+ foreach (NameValuePair pair in BuildParams(this, accessToken, false))
{
if (string.IsNullOrEmpty(pair.Value))
{
@@ -172,7 +173,7 @@ namespace MediaBrowser.Model.Dlna
{
List<string> list = new List<string>();
- foreach (NameValuePair pair in BuildParams(item, accessToken))
+ foreach (NameValuePair pair in BuildParams(item, accessToken, true))
{
list.Add(pair.Value);
}
@@ -180,7 +181,7 @@ namespace MediaBrowser.Model.Dlna
return string.Format("Params={0}", string.Join(";", list.ToArray()));
}
- private static List<NameValuePair> BuildParams(StreamInfo item, string accessToken)
+ private static List<NameValuePair> BuildParams(StreamInfo item, string accessToken, bool isDlna)
{
List<NameValuePair> list = new List<NameValuePair>();
@@ -210,7 +211,17 @@ namespace MediaBrowser.Model.Dlna
list.Add(new NameValuePair("Level", item.VideoLevel.HasValue ? StringHelper.ToStringCultureInvariant(item.VideoLevel.Value) : string.Empty));
- list.Add(new NameValuePair("ClientTime", item.IsDirectStream ? string.Empty : DateTime.UtcNow.Ticks.ToString(CultureInfo.InvariantCulture)));
+ if (isDlna)
+ {
+ // The player may see it as separate resources due to url differences
+ // And then try to request more than one at playback
+ list.Add(new NameValuePair("ClientTime", string.Empty));
+ }
+ else
+ {
+ list.Add(new NameValuePair("ClientTime", item.IsDirectStream ? string.Empty : DateTime.UtcNow.Ticks.ToString(CultureInfo.InvariantCulture)));
+ }
+
list.Add(new NameValuePair("MaxRefFrames", item.MaxRefFrames.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxRefFrames.Value) : string.Empty));
list.Add(new NameValuePair("MaxVideoBitDepth", item.MaxVideoBitDepth.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxVideoBitDepth.Value) : string.Empty));
list.Add(new NameValuePair("Profile", item.VideoProfile ?? string.Empty));
diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs
index 7a1c78112..c772692a2 100644
--- a/MediaBrowser.Model/Dto/BaseItemDto.cs
+++ b/MediaBrowser.Model/Dto/BaseItemDto.cs
@@ -3,6 +3,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.Library;
using MediaBrowser.Model.Providers;
+using MediaBrowser.Model.Sync;
using System;
using System.Collections.Generic;
using System.ComponentModel;
@@ -16,7 +17,7 @@ namespace MediaBrowser.Model.Dto
/// This holds information about a BaseItem in a format that is convenient for the client.
/// </summary>
[DebuggerDisplay("Name = {Name}, ID = {Id}, Type = {Type}")]
- public class BaseItemDto : IHasProviderIds, IHasPropertyChangedEvent, IItemDto, IHasServerId
+ public class BaseItemDto : IHasProviderIds, IHasPropertyChangedEvent, IItemDto, IHasServerId, IHasSyncInfo
{
/// <summary>
/// Gets or sets the name.
@@ -29,19 +30,25 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The server identifier.</value>
public string ServerId { get; set; }
-
+
/// <summary>
/// Gets or sets the id.
/// </summary>
/// <value>The id.</value>
public string Id { get; set; }
+
+ /// <summary>
+ /// Gets or sets the etag.
+ /// </summary>
+ /// <value>The etag.</value>
+ public string Etag { get; set; }
/// <summary>
/// Gets or sets the playlist item identifier.
/// </summary>
/// <value>The playlist item identifier.</value>
public string PlaylistItemId { get; set; }
-
+
/// <summary>
/// Gets or sets the date created.
/// </summary>
@@ -50,7 +57,7 @@ namespace MediaBrowser.Model.Dto
public DateTime? DateLastMediaAdded { get; set; }
public ExtraType? ExtraType { get; set; }
-
+
public int? AirsBeforeSeasonNumber { get; set; }
public int? AirsAfterSeasonNumber { get; set; }
public int? AirsBeforeEpisodeNumber { get; set; }
@@ -63,6 +70,7 @@ namespace MediaBrowser.Model.Dto
public string PreferredMetadataCountryCode { get; set; }
public string AwardSummary { get; set; }
+ public string ShareUrl { get; set; }
public float? Metascore { get; set; }
@@ -71,8 +79,26 @@ namespace MediaBrowser.Model.Dto
public int? AnimeSeriesIndex { get; set; }
+ /// <summary>
+ /// Gets or sets a value indicating whether [supports synchronize].
+ /// </summary>
+ /// <value><c>null</c> if [supports synchronize] contains no value, <c>true</c> if [supports synchronize]; otherwise, <c>false</c>.</value>
public bool? SupportsSync { get; set; }
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance has synchronize job.
+ /// </summary>
+ /// <value><c>null</c> if [has synchronize job] contains no value, <c>true</c> if [has synchronize job]; otherwise, <c>false</c>.</value>
public bool? HasSyncJob { get; set; }
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is synced.
+ /// </summary>
+ /// <value><c>null</c> if [is synced] contains no value, <c>true</c> if [is synced]; otherwise, <c>false</c>.</value>
+ public bool? IsSynced { get; set; }
+ /// <summary>
+ /// Gets or sets the synchronize status.
+ /// </summary>
+ /// <value>The synchronize status.</value>
+ public SyncJobItemStatus? SyncStatus { get; set; }
/// <summary>
/// Gets or sets the DVD season number.
@@ -84,7 +110,7 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The DVD episode number.</value>
public float? DvdEpisodeNumber { get; set; }
-
+
/// <summary>
/// Gets or sets the name of the sort.
/// </summary>
@@ -97,7 +123,7 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The video3 D format.</value>
public Video3DFormat? Video3DFormat { get; set; }
-
+
/// <summary>
/// Gets or sets the premiere date.
/// </summary>
@@ -115,7 +141,7 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The media versions.</value>
public List<MediaSourceInfo> MediaSources { get; set; }
-
+
/// <summary>
/// Gets or sets the critic rating.
/// </summary>
@@ -127,7 +153,7 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The game system.</value>
public string GameSystem { get; set; }
-
+
/// <summary>
/// Gets or sets the critic rating summary.
/// </summary>
@@ -135,13 +161,13 @@ namespace MediaBrowser.Model.Dto
public string CriticRatingSummary { get; set; }
public List<string> MultiPartGameFiles { get; set; }
-
+
/// <summary>
/// Gets or sets the path.
/// </summary>
/// <value>The path.</value>
public string Path { get; set; }
-
+
/// <summary>
/// Gets or sets the official rating.
/// </summary>
@@ -178,7 +204,7 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The name of the TMDB collection.</value>
public string TmdbCollectionName { get; set; }
-
+
/// <summary>
/// Gets or sets the taglines.
/// </summary>
@@ -196,7 +222,7 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The series genres.</value>
public List<string> SeriesGenres { get; set; }
-
+
/// <summary>
/// Gets or sets the community rating.
/// </summary>
@@ -220,7 +246,7 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The original run time ticks.</value>
public long? OriginalRunTimeTicks { get; set; }
-
+
/// <summary>
/// Gets or sets the run time ticks.
/// </summary>
@@ -232,7 +258,7 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The play access.</value>
public PlayAccess PlayAccess { get; set; }
-
+
/// <summary>
/// Gets or sets the aspect ratio.
/// </summary>
@@ -250,7 +276,7 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The season count.</value>
public int? SeasonCount { get; set; }
-
+
/// <summary>
/// Gets or sets the players supported by a game.
/// </summary>
@@ -262,7 +288,7 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value><c>null</c> if [is place holder] contains no value, <c>true</c> if [is place holder]; otherwise, <c>false</c>.</value>
public bool? IsPlaceHolder { get; set; }
-
+
/// <summary>
/// Gets or sets the index number.
/// </summary>
@@ -292,7 +318,7 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The soundtrack ids.</value>
public string[] SoundtrackIds { get; set; }
-
+
/// <summary>
/// Gets or sets the provider ids.
/// </summary>
@@ -304,7 +330,7 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value><c>null</c> if [is HD] contains no value, <c>true</c> if [is HD]; otherwise, <c>false</c>.</value>
public bool? IsHD { get; set; }
-
+
/// <summary>
/// Gets or sets a value indicating whether this instance is folder.
/// </summary>
@@ -399,7 +425,7 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The season identifier.</value>
public string SeasonId { get; set; }
-
+
/// <summary>
/// Gets or sets the special feature count.
/// </summary>
@@ -447,7 +473,7 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The keywords.</value>
public List<string> Keywords { get; set; }
-
+
/// <summary>
/// Gets or sets the primary image aspect ratio, after image enhancements.
/// </summary>
@@ -483,13 +509,13 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The type of the collection.</value>
public string CollectionType { get; set; }
-
+
/// <summary>
/// Gets or sets the display order.
/// </summary>
/// <value>The display order.</value>
public string DisplayOrder { get; set; }
-
+
/// <summary>
/// Gets or sets the album id.
/// </summary>
@@ -506,7 +532,7 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The series primary image tag.</value>
public string SeriesPrimaryImageTag { get; set; }
-
+
/// <summary>
/// Gets or sets the album artist.
/// </summary>
@@ -518,13 +544,13 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The album artists.</value>
public List<NameIdPair> AlbumArtists { get; set; }
-
+
/// <summary>
/// Gets or sets the name of the season.
/// </summary>
/// <value>The name of the season.</value>
public string SeasonName { get; set; }
-
+
/// <summary>
/// Gets or sets the media streams.
/// </summary>
@@ -629,7 +655,7 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The series studio.</value>
public string SeriesStudio { get; set; }
-
+
/// <summary>
/// Gets or sets the parent thumb item id.
/// </summary>
@@ -749,7 +775,7 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The music video count.</value>
public int? MusicVideoCount { get; set; }
-
+
/// <summary>
/// Gets or sets a value indicating whether [enable internet providers].
/// </summary>
diff --git a/MediaBrowser.Model/Dto/BaseItemPerson.cs b/MediaBrowser.Model/Dto/BaseItemPerson.cs
index 46485316e..8e7750562 100644
--- a/MediaBrowser.Model/Dto/BaseItemPerson.cs
+++ b/MediaBrowser.Model/Dto/BaseItemPerson.cs
@@ -1,7 +1,7 @@
-using System.ComponentModel;
+using MediaBrowser.Model.Extensions;
+using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.Serialization;
-using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Model.Dto
{
diff --git a/MediaBrowser.Model/Dto/IHasSyncInfo.cs b/MediaBrowser.Model/Dto/IHasSyncInfo.cs
new file mode 100644
index 000000000..d2cf1f8cf
--- /dev/null
+++ b/MediaBrowser.Model/Dto/IHasSyncInfo.cs
@@ -0,0 +1,13 @@
+using MediaBrowser.Model.Sync;
+
+namespace MediaBrowser.Model.Dto
+{
+ public interface IHasSyncInfo
+ {
+ string Id { get; }
+ bool? SupportsSync { get; set; }
+ bool? HasSyncJob { get; set; }
+ bool? IsSynced { get; set; }
+ SyncJobItemStatus? SyncStatus { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/Dto/ItemLayout.cs b/MediaBrowser.Model/Dto/ItemLayout.cs
new file mode 100644
index 000000000..c85818390
--- /dev/null
+++ b/MediaBrowser.Model/Dto/ItemLayout.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Model.Dto
+{
+ public static class ItemLayout
+ {
+ public static double? GetDisplayAspectRatio(BaseItemDto item)
+ {
+ List<BaseItemDto> items = new List<BaseItemDto>();
+ items.Add(item);
+ return GetDisplayAspectRatio(items);
+ }
+
+ public static double? GetDisplayAspectRatio(List<BaseItemDto> items)
+ {
+ List<double> values = new List<double>();
+
+ foreach (BaseItemDto item in items)
+ {
+ if (item.PrimaryImageAspectRatio.HasValue)
+ {
+ values.Add(item.PrimaryImageAspectRatio.Value);
+ }
+ }
+
+ if (values.Count == 0)
+ {
+ return null;
+ }
+
+ values.Sort();
+
+ double halfDouble = values.Count;
+ halfDouble /= 2;
+ int half = Convert.ToInt32(Math.Floor(halfDouble));
+
+ double result;
+
+ if (values.Count % 2 > 0)
+ result = values[half];
+ else
+ result = (values[half - 1] + values[half]) / 2.0;
+
+ // If really close to 2:3 (poster image), just return 2:3
+ if (Math.Abs(0.66666666667 - result) <= .15)
+ {
+ return 0.66666666667;
+ }
+
+ // If really close to 16:9 (episode image), just return 16:9
+ if (Math.Abs(1.777777778 - result) <= .2)
+ {
+ return 1.777777778;
+ }
+
+ // If really close to 1 (square image), just return 1
+ if (Math.Abs(1 - result) <= .15)
+ {
+ return 1.0;
+ }
+
+ // If really close to 4:3 (poster image), just return 2:3
+ if (Math.Abs(1.33333333333 - result) <= .15)
+ {
+ return 1.33333333333;
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/MediaBrowser.Model/Dto/UserItemDataDto.cs b/MediaBrowser.Model/Dto/UserItemDataDto.cs
index 6ee9f1916..ce0c8fa99 100644
--- a/MediaBrowser.Model/Dto/UserItemDataDto.cs
+++ b/MediaBrowser.Model/Dto/UserItemDataDto.cs
@@ -69,6 +69,12 @@ namespace MediaBrowser.Model.Dto
/// <value>The key.</value>
public string Key { get; set; }
+ /// <summary>
+ /// Gets or sets the item identifier.
+ /// </summary>
+ /// <value>The item identifier.</value>
+ public string ItemId { get; set; }
+
public event PropertyChangedEventHandler PropertyChanged;
}
}
diff --git a/MediaBrowser.Model/Entities/CollectionType.cs b/MediaBrowser.Model/Entities/CollectionType.cs
index e51b2d311..a259f4c07 100644
--- a/MediaBrowser.Model/Entities/CollectionType.cs
+++ b/MediaBrowser.Model/Entities/CollectionType.cs
@@ -61,6 +61,7 @@
public const string MusicGenres = "MusicGenres";
public const string MusicGenre = "MusicGenre";
public const string MusicLatest = "MusicLatest";
+ public const string MusicPlaylists = "MusicPlaylists";
public const string MusicSongs = "MusicSongs";
public const string MusicFavorites = "MusicFavorites";
public const string MusicFavoriteArtists = "MusicFavoriteArtists";
diff --git a/MediaBrowser.Model/Entities/MediaInfo.cs b/MediaBrowser.Model/Entities/MediaInfo.cs
deleted file mode 100644
index ef26cfa14..000000000
--- a/MediaBrowser.Model/Entities/MediaInfo.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System.Collections.Generic;
-
-namespace MediaBrowser.Model.Entities
-{
- public class MediaInfo
- {
- /// <summary>
- /// Gets or sets the media streams.
- /// </summary>
- /// <value>The media streams.</value>
- public List<MediaStream> MediaStreams { get; set; }
-
- /// <summary>
- /// Gets or sets the format.
- /// </summary>
- /// <value>The format.</value>
- public string Format { get; set; }
-
- public int? TotalBitrate { get; set; }
-
- public MediaInfo()
- {
- MediaStreams = new List<MediaStream>();
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs
index 0f3435174..f842a9e3a 100644
--- a/MediaBrowser.Model/Entities/MediaStream.cs
+++ b/MediaBrowser.Model/Entities/MediaStream.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Model.Dlna;
+using System.Collections.Generic;
+using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Extensions;
using System.Diagnostics;
@@ -57,7 +58,7 @@ namespace MediaBrowser.Model.Entities
/// </summary>
/// <value>The length of the packet.</value>
public int? PacketLength { get; set; }
-
+
/// <summary>
/// Gets or sets the channels.
/// </summary>
diff --git a/MediaBrowser.Model/LiveTv/LiveTvTunerInfoDto.cs b/MediaBrowser.Model/LiveTv/LiveTvTunerInfoDto.cs
index 28e8c158a..fcb19427b 100644
--- a/MediaBrowser.Model/LiveTv/LiveTvTunerInfoDto.cs
+++ b/MediaBrowser.Model/LiveTv/LiveTvTunerInfoDto.cs
@@ -23,6 +23,12 @@ namespace MediaBrowser.Model.LiveTv
public string Id { get; set; }
/// <summary>
+ /// Gets or sets the URL.
+ /// </summary>
+ /// <value>The URL.</value>
+ public string Url { get; set; }
+
+ /// <summary>
/// Gets or sets the status.
/// </summary>
/// <value>The status.</value>
diff --git a/MediaBrowser.Model/LiveTv/RecordingInfoDto.cs b/MediaBrowser.Model/LiveTv/RecordingInfoDto.cs
index d6d698038..0988b11a6 100644
--- a/MediaBrowser.Model/LiveTv/RecordingInfoDto.cs
+++ b/MediaBrowser.Model/LiveTv/RecordingInfoDto.cs
@@ -2,6 +2,7 @@
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.Library;
+using MediaBrowser.Model.Sync;
using System;
using System.Collections.Generic;
using System.ComponentModel;
@@ -11,7 +12,7 @@ using System.Runtime.Serialization;
namespace MediaBrowser.Model.LiveTv
{
[DebuggerDisplay("Name = {Name}, ChannelName = {ChannelName}")]
- public class RecordingInfoDto : IHasPropertyChangedEvent, IItemDto, IHasServerId
+ public class RecordingInfoDto : IHasPropertyChangedEvent, IItemDto, IHasServerId, IHasSyncInfo
{
/// <summary>
/// Id of the recording.
@@ -35,6 +36,27 @@ namespace MediaBrowser.Model.LiveTv
/// </summary>
/// <value>The original primary image aspect ratio.</value>
public double? OriginalPrimaryImageAspectRatio { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether [supports synchronize].
+ /// </summary>
+ /// <value><c>null</c> if [supports synchronize] contains no value, <c>true</c> if [supports synchronize]; otherwise, <c>false</c>.</value>
+ public bool? SupportsSync { get; set; }
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance has synchronize job.
+ /// </summary>
+ /// <value><c>null</c> if [has synchronize job] contains no value, <c>true</c> if [has synchronize job]; otherwise, <c>false</c>.</value>
+ public bool? HasSyncJob { get; set; }
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is synced.
+ /// </summary>
+ /// <value><c>null</c> if [is synced] contains no value, <c>true</c> if [is synced]; otherwise, <c>false</c>.</value>
+ public bool? IsSynced { get; set; }
+ /// <summary>
+ /// Gets or sets the synchronize status.
+ /// </summary>
+ /// <value>The synchronize status.</value>
+ public SyncJobItemStatus? SyncStatus { get; set; }
/// <summary>
/// Gets or sets the series timer identifier.
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index 067309512..af0cbb166 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -138,6 +138,8 @@
<Compile Include="Dlna\SubtitleStreamInfo.cs" />
<Compile Include="Drawing\ImageOrientation.cs" />
<Compile Include="Dto\IHasServerId.cs" />
+ <Compile Include="Dto\IHasSyncInfo.cs" />
+ <Compile Include="Dto\ItemLayout.cs" />
<Compile Include="Dto\MetadataEditorInfo.cs" />
<Compile Include="Dto\NameIdPair.cs" />
<Compile Include="Dto\NameValuePair.cs" />
@@ -226,7 +228,7 @@
<Compile Include="Dto\RecommendationType.cs" />
<Compile Include="Dto\SubtitleDownloadOptions.cs" />
<Compile Include="Entities\IsoType.cs" />
- <Compile Include="Entities\MediaInfo.cs" />
+ <Compile Include="MediaInfo\MediaInfo.cs" />
<Compile Include="Entities\MediaStreamType.cs" />
<Compile Include="Entities\PackageReviewInfo.cs" />
<Compile Include="Entities\ProviderIdsExtensions.cs" />
diff --git a/MediaBrowser.Model/MediaInfo/MediaInfo.cs b/MediaBrowser.Model/MediaInfo/MediaInfo.cs
new file mode 100644
index 000000000..21f258693
--- /dev/null
+++ b/MediaBrowser.Model/MediaInfo/MediaInfo.cs
@@ -0,0 +1,66 @@
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Entities;
+using System;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Model.MediaInfo
+{
+ public class MediaInfo : MediaSourceInfo, IHasProviderIds
+ {
+ public List<ChapterInfo> Chapters { get; set; }
+
+ /// <summary>
+ /// Gets or sets the title.
+ /// </summary>
+ /// <value>The title.</value>
+ public string Title { get; set; }
+ /// <summary>
+ /// Gets or sets the album.
+ /// </summary>
+ /// <value>The album.</value>
+ public string Album { get; set; }
+ /// <summary>
+ /// Gets or sets the artists.
+ /// </summary>
+ /// <value>The artists.</value>
+ public List<string> Artists { get; set; }
+ /// <summary>
+ /// Gets or sets the album artists.
+ /// </summary>
+ /// <value>The album artists.</value>
+ public List<string> AlbumArtists { get; set; }
+ /// <summary>
+ /// Gets or sets the studios.
+ /// </summary>
+ /// <value>The studios.</value>
+ public List<string> Studios { get; set; }
+ public List<string> Genres { get; set; }
+ public int? IndexNumber { get; set; }
+ public int? ParentIndexNumber { get; set; }
+ public int? ProductionYear { get; set; }
+ public DateTime? PremiereDate { get; set; }
+ public List<BaseItemPerson> People { get; set; }
+ public Dictionary<string, string> ProviderIds { get; set; }
+ /// <summary>
+ /// Gets or sets the official rating.
+ /// </summary>
+ /// <value>The official rating.</value>
+ public string OfficialRating { get; set; }
+ /// <summary>
+ /// Gets or sets the overview.
+ /// </summary>
+ /// <value>The overview.</value>
+ public string Overview { get; set; }
+
+ public MediaInfo()
+ {
+ Chapters = new List<ChapterInfo>();
+ Artists = new List<string>();
+ AlbumArtists = new List<string>();
+ Studios = new List<string>();
+ Genres = new List<string>();
+ People = new List<BaseItemPerson>();
+ ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ }
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.Model/Querying/ItemFields.cs b/MediaBrowser.Model/Querying/ItemFields.cs
index 54c83ca15..77b3dc0ee 100644
--- a/MediaBrowser.Model/Querying/ItemFields.cs
+++ b/MediaBrowser.Model/Querying/ItemFields.cs
@@ -76,6 +76,11 @@
DisplayMediaType,
/// <summary>
+ /// The etag
+ /// </summary>
+ Etag,
+
+ /// <summary>
/// The external urls
/// </summary>
ExternalUrls,
diff --git a/MediaBrowser.Model/Session/ClientCapabilities.cs b/MediaBrowser.Model/Session/ClientCapabilities.cs
index 9361a60ea..f00b14545 100644
--- a/MediaBrowser.Model/Session/ClientCapabilities.cs
+++ b/MediaBrowser.Model/Session/ClientCapabilities.cs
@@ -19,12 +19,17 @@ namespace MediaBrowser.Model.Session
public bool SupportsOfflineAccess { get; set; }
public DeviceProfile DeviceProfile { get; set; }
+ public List<string> SupportedLiveMediaTypes { get; set; }
+
+ public string AppStoreUrl { get; set; }
+ public string IconUrl { get; set; }
public ClientCapabilities()
{
PlayableMediaTypes = new List<string>();
SupportedCommands = new List<string>();
SupportsPersistentIdentifier = true;
+ SupportedLiveMediaTypes = new List<string>();
}
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/Sync/LocalItem.cs b/MediaBrowser.Model/Sync/LocalItem.cs
index dbbecaf05..c5728ac97 100644
--- a/MediaBrowser.Model/Sync/LocalItem.cs
+++ b/MediaBrowser.Model/Sync/LocalItem.cs
@@ -26,6 +26,11 @@ namespace MediaBrowser.Model.Sync
/// <value>The unique identifier.</value>
public string Id { get; set; }
/// <summary>
+ /// Gets or sets the file identifier.
+ /// </summary>
+ /// <value>The file identifier.</value>
+ public string FileId { get; set; }
+ /// <summary>
/// Gets or sets the item identifier.
/// </summary>
/// <value>The item identifier.</value>
diff --git a/MediaBrowser.Model/Sync/SyncOptions.cs b/MediaBrowser.Model/Sync/SyncOptions.cs
index 294f7bcef..7f0c17b37 100644
--- a/MediaBrowser.Model/Sync/SyncOptions.cs
+++ b/MediaBrowser.Model/Sync/SyncOptions.cs
@@ -4,5 +4,13 @@ namespace MediaBrowser.Model.Sync
public class SyncOptions
{
public string TemporaryPath { get; set; }
+ public long UploadSpeedLimitBytes { get; set; }
+ public int TranscodingCpuCoreLimit { get; set; }
+ public bool EnableFullSpeedTranscoding { get; set; }
+
+ public SyncOptions()
+ {
+ TranscodingCpuCoreLimit = 1;
+ }
}
}
diff --git a/MediaBrowser.Model/Sync/SyncQualityOption.cs b/MediaBrowser.Model/Sync/SyncQualityOption.cs
index 597b98727..6eff4b9a4 100644
--- a/MediaBrowser.Model/Sync/SyncQualityOption.cs
+++ b/MediaBrowser.Model/Sync/SyncQualityOption.cs
@@ -23,5 +23,10 @@ namespace MediaBrowser.Model.Sync
/// </summary>
/// <value><c>true</c> if this instance is default; otherwise, <c>false</c>.</value>
public bool IsDefault { get; set; }
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is original quality.
+ /// </summary>
+ /// <value><c>true</c> if this instance is original quality; otherwise, <c>false</c>.</value>
+ public bool IsOriginalQuality { get; set; }
}
}
diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs
index 640f03e2a..b3040d6f8 100644
--- a/MediaBrowser.Model/Users/UserPolicy.cs
+++ b/MediaBrowser.Model/Users/UserPolicy.cs
@@ -39,6 +39,9 @@ namespace MediaBrowser.Model.Users
public bool EnableLiveTvAccess { get; set; }
public bool EnableMediaPlayback { get; set; }
+ public bool EnableAudioPlaybackTranscoding { get; set; }
+ public bool EnableVideoPlaybackTranscoding { get; set; }
+
public bool EnableContentDeletion { get; set; }
public bool EnableContentDownloading { get; set; }
@@ -47,6 +50,7 @@ namespace MediaBrowser.Model.Users
/// </summary>
/// <value><c>true</c> if [enable synchronize]; otherwise, <c>false</c>.</value>
public bool EnableSync { get; set; }
+ public bool EnableSyncTranscoding { get; set; }
public string[] EnabledDevices { get; set; }
public bool EnableAllDevices { get; set; }
@@ -58,13 +62,24 @@ namespace MediaBrowser.Model.Users
public bool EnableAllFolders { get; set; }
public int InvalidLoginAttemptCount { get; set; }
-
+
+ public bool EnablePublicSharing { get; set; }
+
+ public string[] BlockedMediaFolders { get; set; }
+ public string[] BlockedChannels { get; set; }
+
public UserPolicy()
{
EnableSync = true;
- EnableLiveTvManagement = true;
+ EnableSyncTranscoding = true;
+
EnableMediaPlayback = true;
+ EnableAudioPlaybackTranscoding = true;
+ EnableVideoPlaybackTranscoding = true;
+
+ EnableLiveTvManagement = true;
EnableLiveTvAccess = true;
+
EnableSharedDeviceControl = true;
BlockedTags = new string[] { };
@@ -84,6 +99,7 @@ namespace MediaBrowser.Model.Users
EnableAllDevices = true;
EnableContentDownloading = true;
+ EnablePublicSharing = true;
}
}
} \ No newline at end of file
diff --git a/MediaBrowser.Mono.sln b/MediaBrowser.Mono.sln
index c5c23fe7a..2e720d095 100644
--- a/MediaBrowser.Mono.sln
+++ b/MediaBrowser.Mono.sln
@@ -35,6 +35,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.MediaInfo", "M
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Server.Startup.Common", "MediaBrowser.Server.Startup.Common\MediaBrowser.Server.Startup.Common.csproj", "{B90AB8F2-1BFF-4568-A3FD-2A338A435A75}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Drawing", "Emby.Drawing\Emby.Drawing.csproj", "{08FFF49B-F175-4807-A2B5-73B0EBD9F716}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -203,6 +205,15 @@ Global
{B90AB8F2-1BFF-4568-A3FD-2A338A435A75}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B90AB8F2-1BFF-4568-A3FD-2A338A435A75}.Release|Any CPU.Build.0 = Release|Any CPU
{B90AB8F2-1BFF-4568-A3FD-2A338A435A75}.Release|x86.ActiveCfg = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release Mono|Any CPU.ActiveCfg = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release Mono|Any CPU.Build.0 = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release Mono|x86.ActiveCfg = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release|Any CPU.Build.0 = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs
index 3ac3cccb3..92327c9bc 100644
--- a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs
+++ b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs
@@ -3,7 +3,6 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
@@ -16,11 +15,8 @@ namespace MediaBrowser.Providers.BoxSets
{
public class BoxSetMetadataService : MetadataService<BoxSet, BoxSetInfo>
{
- private readonly ILocalizationManager _iLocalizationManager;
-
- public BoxSetMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILocalizationManager iLocalizationManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager)
+ public BoxSetMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager)
{
- _iLocalizationManager = iLocalizationManager;
}
/// <summary>
diff --git a/MediaBrowser.Providers/FolderImages/DefaultImageProvider.cs b/MediaBrowser.Providers/FolderImages/DefaultImageProvider.cs
deleted file mode 100644
index 3550ee688..000000000
--- a/MediaBrowser.Providers/FolderImages/DefaultImageProvider.cs
+++ /dev/null
@@ -1,153 +0,0 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Providers;
-using MediaBrowser.Providers.Genres;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Providers.FolderImages
-{
- public class DefaultImageProvider : IRemoteImageProvider, IHasItemChangeMonitor, IHasOrder
- {
- private readonly IHttpClient _httpClient;
-
- public DefaultImageProvider(IHttpClient httpClient)
- {
- _httpClient = httpClient;
- }
-
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
- {
- return new List<ImageType>
- {
- ImageType.Primary,
- ImageType.Thumb
- };
- }
-
- public Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
- {
- var view = item as UserView;
-
- if (view != null)
- {
- return GetImages(view.ViewType, view.ParentId != Guid.Empty, cancellationToken);
- }
-
- var folder = (ICollectionFolder)item;
- return GetImages(folder.CollectionType, false, cancellationToken);
- }
-
- private Task<IEnumerable<RemoteImageInfo>> GetImages(string viewType, bool isSubView, CancellationToken cancellationToken)
- {
- var url = GetImageUrl(viewType, isSubView);
- var list = new List<RemoteImageInfo>();
-
- if (!string.IsNullOrWhiteSpace(url))
- {
- list.AddRange(new List<RemoteImageInfo>
- {
- new RemoteImageInfo
- {
- ProviderName = Name,
- Url = url,
- Type = ImageType.Primary
- },
-
- new RemoteImageInfo
- {
- ProviderName = Name,
- Url = url,
- Type = ImageType.Thumb
- }
- });
- }
-
- return Task.FromResult<IEnumerable<RemoteImageInfo>>(list);
- }
-
- private string GetImageUrl(string viewType, bool isSubView)
- {
- const string urlPrefix = "https://raw.githubusercontent.com/MediaBrowser/MediaBrowser.Resources/master/images/folders/";
-
- if (string.Equals(viewType, CollectionType.Books, StringComparison.OrdinalIgnoreCase))
- {
- return null;
- }
- if (string.Equals(viewType, CollectionType.Games, StringComparison.OrdinalIgnoreCase))
- {
- return null;
- }
- if (string.Equals(viewType, CollectionType.Music, StringComparison.OrdinalIgnoreCase))
- {
- return null;
- }
- if (string.Equals(viewType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
- {
- return null;
- }
- if (string.Equals(viewType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
- {
- return null;
- }
- if (string.Equals(viewType, CollectionType.Channels, StringComparison.OrdinalIgnoreCase))
- {
- return null;
- }
- if (string.Equals(viewType, CollectionType.LiveTv, StringComparison.OrdinalIgnoreCase))
- {
- return null;
- }
- if (string.Equals(viewType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
- {
- return null;
- }
-
- if (isSubView)
- {
- return null;
- }
-
- return urlPrefix + "generic.png";
- }
-
- public string Name
- {
- get { return "Default Image Provider"; }
- }
-
- public bool Supports(IHasImages item)
- {
- return item is ICollectionFolder || item is UserView;
- }
-
- public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
- {
- return _httpClient.GetResponse(new HttpRequestOptions
- {
- CancellationToken = cancellationToken,
- Url = url,
- ResourcePool = GenreImageProvider.ImageDownloadResourcePool
- });
- }
-
- public bool HasChanged(IHasMetadata item, MetadataStatus status, IDirectoryService directoryService)
- {
- return GetSupportedImages(item).Any(i => !item.HasImage(i));
- }
-
- public int Order
- {
- get
- {
- // Run after the dynamic image provider
- return 1;
- }
- }
- }
-}
diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs
index 533e843ea..fc47b0259 100644
--- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs
+++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs
@@ -36,16 +36,15 @@ namespace MediaBrowser.Providers.Manager
public bool ValidateImages(IHasImages item, IEnumerable<IImageProvider> providers, IDirectoryService directoryService)
{
- var hasChanges = item.ValidateImages(directoryService);
+ var hasChanges = false;
- foreach (var provider in providers.OfType<ILocalImageFileProvider>())
- {
- var images = provider.GetImages(item, directoryService);
+ var images = providers.OfType<ILocalImageFileProvider>()
+ .SelectMany(i => i.GetImages(item, directoryService))
+ .ToList();
- if (MergeImages(item, images))
- {
- hasChanges = true;
- }
+ if (MergeImages(item, images))
+ {
+ hasChanges = true;
}
return hasChanges;
@@ -377,8 +376,7 @@ namespace MediaBrowser.Providers.Manager
item.SetImagePath(type, image.FileInfo);
changed = true;
}
- else if (!string.Equals(currentImage.Path, image.FileInfo.FullName,
- StringComparison.OrdinalIgnoreCase))
+ else if (!string.Equals(currentImage.Path, image.FileInfo.FullName, StringComparison.OrdinalIgnoreCase))
{
item.SetImagePath(type, image.FileInfo);
changed = true;
@@ -386,7 +384,15 @@ namespace MediaBrowser.Providers.Manager
else
{
currentImage.DateModified = _fileSystem.GetLastWriteTimeUtc(image.FileInfo);
- currentImage.Length = ((FileInfo) image.FileInfo).Length;
+ }
+ }
+ else
+ {
+ var existing = item.GetImageInfo(type, 0);
+ if (existing != null && !File.Exists(existing.Path))
+ {
+ item.RemoveImage(existing);
+ changed = true;
}
}
}
@@ -412,16 +418,16 @@ namespace MediaBrowser.Providers.Manager
{
var changed = false;
- var backdrops = images.Where(i => i.Type == type).ToList();
- if (backdrops.Count > 0)
+ var newImages = images.Where(i => i.Type == type).ToList();
+ if (newImages.Count > 0)
{
- var foundImages = images.Where(i => i.Type == type)
+ var newImageFileInfos = images.Where(i => i.Type == type)
.Select(i => i.FileInfo)
.ToList();
- if (foundImages.Count > 0)
+ if (newImageFileInfos.Count > 0)
{
- if (item.AddImages(type, foundImages))
+ if (item.AddImages(type, newImageFileInfos))
{
changed = true;
}
diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs
index 62def8b8b..334e14850 100644
--- a/MediaBrowser.Providers/Manager/MetadataService.cs
+++ b/MediaBrowser.Providers/Manager/MetadataService.cs
@@ -141,7 +141,6 @@ namespace MediaBrowser.Providers.Manager
updateType = updateType | result.UpdateType;
refreshResult.AddStatus(result.Status, result.ErrorMessage);
refreshResult.SetDateLastMetadataRefresh(DateTime.UtcNow);
- refreshResult.AddMetadataProvidersRefreshed(result.Providers);
MergeIdentities(itemOfType, id);
}
@@ -159,7 +158,6 @@ namespace MediaBrowser.Providers.Manager
updateType = updateType | result.UpdateType;
refreshResult.AddStatus(result.Status, result.ErrorMessage);
refreshResult.SetDateLastImagesRefresh(DateTime.UtcNow);
- refreshResult.AddImageProvidersRefreshed(result.Providers);
}
}
@@ -484,6 +482,11 @@ namespace MediaBrowser.Providers.Manager
protected virtual bool IsFullLocalMetadata(TItemType item)
{
+ if (string.IsNullOrWhiteSpace(item.Name))
+ {
+ return false;
+ }
+
return true;
}
diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs
index c9ae47ad0..01a89bf26 100644
--- a/MediaBrowser.Providers/Manager/ProviderManager.cs
+++ b/MediaBrowser.Providers/Manager/ProviderManager.cs
@@ -148,6 +148,13 @@ namespace MediaBrowser.Providers.Manager
return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, source, mimeType, type, imageIndex, internalCacheKey, cancellationToken);
}
+ public Task SaveImage(IHasImages item, string source, string mimeType, ImageType type, int? imageIndex, string internalCacheKey, CancellationToken cancellationToken)
+ {
+ var fileStream = _fileSystem.GetFileStream(source, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true);
+
+ return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, fileStream, mimeType, type, imageIndex, internalCacheKey, cancellationToken);
+ }
+
public async Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(IHasImages item, RemoteImageQuery query, CancellationToken cancellationToken)
{
var providers = GetRemoteImageProviders(item, query.IncludeDisabledProviders);
diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
index 3b5103f20..444567afa 100644
--- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj
+++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
@@ -83,7 +83,6 @@
<Compile Include="BoxSets\MovieDbBoxSetProvider.cs" />
<Compile Include="Channels\ChannelMetadataService.cs" />
<Compile Include="Chapters\ChapterManager.cs" />
- <Compile Include="FolderImages\DefaultImageProvider.cs" />
<Compile Include="Folders\FolderMetadataService.cs" />
<Compile Include="Channels\AudioChannelItemMetadataService.cs" />
<Compile Include="Folders\UserViewMetadataService.cs" />
@@ -102,7 +101,6 @@
<Compile Include="Manager\MetadataService.cs" />
<Compile Include="Manager\SeriesOrderManager.cs" />
<Compile Include="MediaInfo\FFProbeAudioInfo.cs" />
- <Compile Include="MediaInfo\FFProbeHelpers.cs" />
<Compile Include="MediaInfo\FFProbeProvider.cs" />
<Compile Include="MediaInfo\FFProbeVideoInfo.cs" />
<Compile Include="MediaInfo\SubtitleDownloader.cs" />
@@ -198,10 +196,6 @@
<Project>{17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}</Project>
<Name>MediaBrowser.Controller</Name>
</ProjectReference>
- <ProjectReference Include="..\MediaBrowser.MediaInfo\MediaBrowser.MediaInfo.csproj">
- <Project>{6e4145e4-c6d4-4e4d-94f2-87188db6e239}</Project>
- <Name>MediaBrowser.MediaInfo</Name>
- </ProjectReference>
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
<Project>{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}</Project>
<Name>MediaBrowser.Model</Name>
@@ -214,9 +208,6 @@
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
- <ItemGroup>
- <EmbeddedResource Include="MediaInfo\whitelist.txt" />
- </ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
index ea191dd08..d78f1b48e 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
@@ -1,15 +1,13 @@
using MediaBrowser.Common.Configuration;
-using MediaBrowser.Model.Extensions;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
@@ -49,18 +47,14 @@ namespace MediaBrowser.Providers.MediaInfo
cancellationToken.ThrowIfCancellationRequested();
- FFProbeHelpers.NormalizeFFProbeResult(result);
-
- cancellationToken.ThrowIfCancellationRequested();
-
await Fetch(item, cancellationToken, result).ConfigureAwait(false);
return ItemUpdateType.MetadataImport;
}
- private const string SchemaVersion = "1";
+ private const string SchemaVersion = "2";
- private async Task<InternalMediaInfoResult> GetMediaInfo(BaseItem item, CancellationToken cancellationToken)
+ private async Task<Model.MediaInfo.MediaInfo> GetMediaInfo(BaseItem item, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -71,7 +65,7 @@ namespace MediaBrowser.Providers.MediaInfo
try
{
- return _json.DeserializeFromFile<InternalMediaInfoResult>(cachePath);
+ return _json.DeserializeFromFile<Model.MediaInfo.MediaInfo>(cachePath);
}
catch (FileNotFoundException)
{
@@ -81,9 +75,13 @@ namespace MediaBrowser.Providers.MediaInfo
{
}
- var inputPath = new[] { item.Path };
+ var result = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest
+ {
+ InputPath = item.Path,
+ MediaType = DlnaProfileType.Audio,
+ Protocol = MediaProtocol.File
- var result = await _mediaEncoder.GetMediaInfo(inputPath, MediaProtocol.File, false, cancellationToken).ConfigureAwait(false);
+ }, cancellationToken).ConfigureAwait(false);
Directory.CreateDirectory(Path.GetDirectoryName(cachePath));
_json.SerializeToFile(result, cachePath);
@@ -96,61 +94,23 @@ namespace MediaBrowser.Providers.MediaInfo
/// </summary>
/// <param name="audio">The audio.</param>
/// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="data">The data.</param>
+ /// <param name="mediaInfo">The media information.</param>
/// <returns>Task.</returns>
- protected Task Fetch(Audio audio, CancellationToken cancellationToken, InternalMediaInfoResult data)
+ protected Task Fetch(Audio audio, CancellationToken cancellationToken, Model.MediaInfo.MediaInfo mediaInfo)
{
- var mediaInfo = MediaEncoderHelpers.GetMediaInfo(data);
var mediaStreams = mediaInfo.MediaStreams;
- audio.FormatName = mediaInfo.Format;
- audio.TotalBitrate = mediaInfo.TotalBitrate;
+ audio.FormatName = mediaInfo.Container;
+ audio.TotalBitrate = mediaInfo.Bitrate;
audio.HasEmbeddedImage = mediaStreams.Any(i => i.Type == MediaStreamType.EmbeddedImage);
- if (data.streams != null)
- {
- // Get the first audio stream
- var stream = data.streams.FirstOrDefault(s => string.Equals(s.codec_type, "audio", StringComparison.OrdinalIgnoreCase));
-
- if (stream != null)
- {
- // Get duration from stream properties
- var duration = stream.duration;
-
- // If it's not there go into format properties
- if (string.IsNullOrEmpty(duration))
- {
- duration = data.format.duration;
- }
-
- // If we got something, parse it
- if (!string.IsNullOrEmpty(duration))
- {
- audio.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(duration, _usCulture)).Ticks;
- }
- }
- }
-
- if (data.format != null)
- {
- var extension = (Path.GetExtension(audio.Path) ?? string.Empty).TrimStart('.');
-
- audio.Container = extension;
+ audio.RunTimeTicks = mediaInfo.RunTimeTicks;
+ audio.Size = mediaInfo.Size;
- if (!string.IsNullOrEmpty(data.format.size))
- {
- audio.Size = long.Parse(data.format.size, _usCulture);
- }
- else
- {
- audio.Size = null;
- }
+ var extension = (Path.GetExtension(audio.Path) ?? string.Empty).TrimStart('.');
+ audio.Container = extension;
- if (data.format.tags != null)
- {
- FetchDataFromTags(audio, data.format.tags);
- }
- }
+ FetchDataFromTags(audio, mediaInfo);
return _itemRepo.SaveMediaStreams(audio.Id, mediaStreams, cancellationToken);
}
@@ -159,92 +119,37 @@ namespace MediaBrowser.Providers.MediaInfo
/// Fetches data from the tags dictionary
/// </summary>
/// <param name="audio">The audio.</param>
- /// <param name="tags">The tags.</param>
- private void FetchDataFromTags(Audio audio, Dictionary<string, string> tags)
+ /// <param name="data">The data.</param>
+ private void FetchDataFromTags(Audio audio, Model.MediaInfo.MediaInfo data)
{
- var title = FFProbeHelpers.GetDictionaryValue(tags, "title");
-
// Only set Name if title was found in the dictionary
- if (!string.IsNullOrEmpty(title))
+ if (!string.IsNullOrEmpty(data.Title))
{
- audio.Name = title;
+ audio.Name = data.Title;
}
if (!audio.LockedFields.Contains(MetadataFields.Cast))
{
audio.People.Clear();
- var composer = FFProbeHelpers.GetDictionaryValue(tags, "composer");
-
- if (!string.IsNullOrWhiteSpace(composer))
+ foreach (var person in data.People)
{
- foreach (var person in Split(composer, false))
+ audio.AddPerson(new PersonInfo
{
- audio.AddPerson(new PersonInfo { Name = person, Type = PersonType.Composer });
- }
+ Name = person.Name,
+ Type = person.Type,
+ Role = person.Role
+ });
}
}
- audio.Album = FFProbeHelpers.GetDictionaryValue(tags, "album");
-
- var artists = FFProbeHelpers.GetDictionaryValue(tags, "artists");
-
- if (!string.IsNullOrWhiteSpace(artists))
- {
- audio.Artists = artists.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries)
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .ToList();
- }
- else
- {
- var artist = FFProbeHelpers.GetDictionaryValue(tags, "artist");
- if (string.IsNullOrWhiteSpace(artist))
- {
- audio.Artists.Clear();
- }
- else
- {
- audio.Artists = SplitArtists(artist)
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .ToList();
- }
- }
-
- var albumArtist = FFProbeHelpers.GetDictionaryValue(tags, "albumartist");
- if (string.IsNullOrWhiteSpace(albumArtist))
- {
- albumArtist = FFProbeHelpers.GetDictionaryValue(tags, "album artist");
- }
- if (string.IsNullOrWhiteSpace(albumArtist))
- {
- albumArtist = FFProbeHelpers.GetDictionaryValue(tags, "album_artist");
- }
-
- if (string.IsNullOrWhiteSpace(albumArtist))
- {
- audio.AlbumArtists = new List<string>();
- }
- else
- {
- audio.AlbumArtists = SplitArtists(albumArtist)
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .ToList();
-
- }
-
- // Track number
- audio.IndexNumber = GetDictionaryDiscValue(tags, "track");
-
- // Disc number
- audio.ParentIndexNumber = GetDictionaryDiscValue(tags, "disc");
-
- 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") ??
- FFProbeHelpers.GetDictionaryDateTime(tags, "date");
+ audio.Album = data.Album;
+ audio.Artists = data.Artists;
+ audio.AlbumArtists = data.AlbumArtists;
+ audio.IndexNumber = data.IndexNumber;
+ audio.ParentIndexNumber = data.ParentIndexNumber;
+ audio.ProductionYear = data.ProductionYear;
+ audio.PremiereDate = data.PremiereDate;
// If we don't have a ProductionYear try and get it from PremiereDate
if (audio.PremiereDate.HasValue && !audio.ProductionYear.HasValue)
@@ -254,192 +159,29 @@ namespace MediaBrowser.Providers.MediaInfo
if (!audio.LockedFields.Contains(MetadataFields.Genres))
{
- FetchGenres(audio, tags);
- }
-
- if (!audio.LockedFields.Contains(MetadataFields.Studios))
- {
- audio.Studios.Clear();
-
- // There's several values in tags may or may not be present
- FetchStudios(audio, tags, "organization");
- FetchStudios(audio, tags, "ensemble");
- FetchStudios(audio, tags, "publisher");
- }
-
- // These support mulitple values, but for now we only store the first.
- audio.SetProviderId(MetadataProviders.MusicBrainzAlbumArtist, GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Album Artist Id")));
- audio.SetProviderId(MetadataProviders.MusicBrainzArtist, GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Artist Id")));
-
- audio.SetProviderId(MetadataProviders.MusicBrainzAlbum, GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Album Id")));
- audio.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Release Group Id")));
- audio.SetProviderId(MetadataProviders.MusicBrainzTrack, GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Release Track Id")));
- }
-
- private string GetMultipleMusicBrainzId(string value)
- {
- if (string.IsNullOrWhiteSpace(value))
- {
- return null;
- }
-
- return value.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries)
- .Select(i => i.Trim())
- .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i));
- }
-
- private readonly char[] _nameDelimiters = { '/', '|', ';', '\\' };
-
- /// <summary>
- /// Splits the specified val.
- /// </summary>
- /// <param name="val">The val.</param>
- /// <param name="allowCommaDelimiter">if set to <c>true</c> [allow comma delimiter].</param>
- /// <returns>System.String[][].</returns>
- private IEnumerable<string> Split(string val, bool allowCommaDelimiter)
- {
- // 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 :
- new[] { ',' };
-
- return val.Split(delimeter, StringSplitOptions.RemoveEmptyEntries)
- .Where(i => !string.IsNullOrWhiteSpace(i))
- .Select(i => i.Trim());
- }
-
- private const string ArtistReplaceValue = " | ";
-
- private IEnumerable<string> SplitArtists(string val)
- {
- val = val.Replace(" featuring ", ArtistReplaceValue, StringComparison.OrdinalIgnoreCase)
- .Replace(" feat. ", ArtistReplaceValue, StringComparison.OrdinalIgnoreCase);
-
- var artistsFound = new List<string>();
-
- foreach (var whitelistArtist in GetSplitWhitelist())
- {
- var originalVal = val;
- val = val.Replace(whitelistArtist, "|", StringComparison.OrdinalIgnoreCase);
-
- if (!string.Equals(originalVal, val, StringComparison.OrdinalIgnoreCase))
- {
- artistsFound.Add(whitelistArtist);
- }
- }
-
- // 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 = _nameDelimiters;
-
- var artists = val.Split(delimeter, StringSplitOptions.RemoveEmptyEntries)
- .Where(i => !string.IsNullOrWhiteSpace(i))
- .Select(i => i.Trim());
-
- artistsFound.AddRange(artists);
- return artistsFound;
- }
-
-
- private List<string> _splitWhiteList = null;
-
- private IEnumerable<string> GetSplitWhitelist()
- {
- if (_splitWhiteList == null)
- {
- var file = GetType().Namespace + ".whitelist.txt";
-
- using (var stream = GetType().Assembly.GetManifestResourceStream(file))
- {
- using (var reader = new StreamReader(stream))
- {
- var list = new List<string>();
-
- while (!reader.EndOfStream)
- {
- var val = reader.ReadLine();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- list.Add(val);
- }
- }
-
- _splitWhiteList = list;
- }
- }
- }
-
- return _splitWhiteList;
- }
-
- /// <summary>
- /// Gets the studios from the tags collection
- /// </summary>
- /// <param name="audio">The audio.</param>
- /// <param name="tags">The tags.</param>
- /// <param name="tagName">Name of the tag.</param>
- private void FetchStudios(Audio audio, Dictionary<string, string> tags, string tagName)
- {
- var val = FFProbeHelpers.GetDictionaryValue(tags, tagName);
-
- if (!string.IsNullOrEmpty(val))
- {
- // Sometimes the artist name is listed here, account for that
- var studios = Split(val, true).Where(i => !audio.HasAnyArtist(i));
-
- foreach (var studio in studios)
- {
- audio.AddStudio(studio);
- }
- }
- }
-
- /// <summary>
- /// Gets the genres from the tags collection
- /// </summary>
- /// <param name="audio">The audio.</param>
- /// <param name="tags">The tags.</param>
- private void FetchGenres(Audio audio, Dictionary<string, string> tags)
- {
- var val = FFProbeHelpers.GetDictionaryValue(tags, "genre");
-
- if (!string.IsNullOrEmpty(val))
- {
audio.Genres.Clear();
- foreach (var genre in Split(val, true))
+ foreach (var genre in data.Genres)
{
audio.AddGenre(genre);
}
}
- }
-
- /// <summary>
- /// Gets the disc number, which is sometimes can be in the form of '1', or '1/3'
- /// </summary>
- /// <param name="tags">The tags.</param>
- /// <param name="tagName">Name of the tag.</param>
- /// <returns>System.Nullable{System.Int32}.</returns>
- private int? GetDictionaryDiscValue(Dictionary<string, string> tags, string tagName)
- {
- var disc = FFProbeHelpers.GetDictionaryValue(tags, tagName);
- if (!string.IsNullOrEmpty(disc))
+ if (!audio.LockedFields.Contains(MetadataFields.Studios))
{
- disc = disc.Split('/')[0];
-
- int num;
+ audio.Studios.Clear();
- if (int.TryParse(disc, out num))
+ foreach (var studio in data.Studios)
{
- return num;
+ audio.AddStudio(studio);
}
}
- return null;
+ audio.SetProviderId(MetadataProviders.MusicBrainzAlbumArtist, data.GetProviderId(MetadataProviders.MusicBrainzAlbumArtist));
+ audio.SetProviderId(MetadataProviders.MusicBrainzArtist, data.GetProviderId(MetadataProviders.MusicBrainzArtist));
+ audio.SetProviderId(MetadataProviders.MusicBrainzAlbum, data.GetProviderId(MetadataProviders.MusicBrainzAlbum));
+ audio.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, data.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup));
+ audio.SetProviderId(MetadataProviders.MusicBrainzTrack, data.GetProviderId(MetadataProviders.MusicBrainzTrack));
}
-
}
}
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
index ca11f858a..b53e31316 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
@@ -1,5 +1,6 @@
using DvdLib.Ifo;
using MediaBrowser.Common.Configuration;
+using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Chapters;
@@ -13,7 +14,6 @@ using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Subtitles;
-using MediaBrowser.MediaInfo;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
@@ -116,10 +116,6 @@ namespace MediaBrowser.Providers.MediaInfo
cancellationToken.ThrowIfCancellationRequested();
- FFProbeHelpers.NormalizeFFProbeResult(result);
-
- cancellationToken.ThrowIfCancellationRequested();
-
await Fetch(item, cancellationToken, result, isoMount, blurayDiscInfo, options).ConfigureAwait(false);
}
@@ -134,9 +130,9 @@ namespace MediaBrowser.Providers.MediaInfo
return ItemUpdateType.MetadataImport;
}
- private const string SchemaVersion = "1";
+ private const string SchemaVersion = "4";
- private async Task<InternalMediaInfoResult> GetMediaInfo(Video item,
+ private async Task<Model.MediaInfo.MediaInfo> GetMediaInfo(Video item,
IIsoMount isoMount,
CancellationToken cancellationToken)
{
@@ -149,7 +145,7 @@ namespace MediaBrowser.Providers.MediaInfo
try
{
- return _json.DeserializeFromFile<InternalMediaInfoResult>(cachePath);
+ return _json.DeserializeFromFile<Model.MediaInfo.MediaInfo>(cachePath);
}
catch (FileNotFoundException)
{
@@ -163,9 +159,18 @@ namespace MediaBrowser.Providers.MediaInfo
? MediaProtocol.Http
: MediaProtocol.File;
- var inputPath = MediaEncoderHelpers.GetInputArgument(item.Path, protocol, isoMount, item.PlayableStreamFileNames);
+ var result = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest
+ {
+ PlayableStreamFileNames = item.PlayableStreamFileNames,
+ MountedIso = isoMount,
+ ExtractChapters = true,
+ VideoType = item.VideoType,
+ MediaType = DlnaProfileType.Video,
+ InputPath = item.Path,
+ Protocol = protocol,
+ ExtractKeyFrameInterval = true
- var result = await _mediaEncoder.GetMediaInfo(inputPath, protocol, false, cancellationToken).ConfigureAwait(false);
+ }, cancellationToken).ConfigureAwait(false);
Directory.CreateDirectory(Path.GetDirectoryName(cachePath));
_json.SerializeToFile(result, cachePath);
@@ -175,52 +180,37 @@ namespace MediaBrowser.Providers.MediaInfo
protected async Task Fetch(Video video,
CancellationToken cancellationToken,
- InternalMediaInfoResult data,
+ Model.MediaInfo.MediaInfo mediaInfo,
IIsoMount isoMount,
BlurayDiscInfo blurayInfo,
MetadataRefreshOptions options)
{
- var mediaInfo = MediaEncoderHelpers.GetMediaInfo(data);
var mediaStreams = mediaInfo.MediaStreams;
- video.TotalBitrate = mediaInfo.TotalBitrate;
- video.FormatName = (mediaInfo.Format ?? string.Empty)
+ video.TotalBitrate = mediaInfo.Bitrate;
+ video.FormatName = (mediaInfo.Container ?? string.Empty)
.Replace("matroska", "mkv", StringComparison.OrdinalIgnoreCase);
- if (data.format != null)
- {
- // For dvd's this may not always be accurate, so don't set the runtime if the item already has one
- var needToSetRuntime = video.VideoType != VideoType.Dvd || video.RunTimeTicks == null || video.RunTimeTicks.Value == 0;
-
- if (needToSetRuntime && !string.IsNullOrEmpty(data.format.duration))
- {
- video.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.format.duration, _usCulture)).Ticks;
- }
+ // For dvd's this may not always be accurate, so don't set the runtime if the item already has one
+ var needToSetRuntime = video.VideoType != VideoType.Dvd || video.RunTimeTicks == null || video.RunTimeTicks.Value == 0;
- if (video.VideoType == VideoType.VideoFile)
- {
- var extension = (Path.GetExtension(video.Path) ?? string.Empty).TrimStart('.');
+ if (needToSetRuntime)
+ {
+ video.RunTimeTicks = mediaInfo.RunTimeTicks;
+ }
- video.Container = extension;
- }
- else
- {
- video.Container = null;
- }
+ if (video.VideoType == VideoType.VideoFile)
+ {
+ var extension = (Path.GetExtension(video.Path) ?? string.Empty).TrimStart('.');
- if (!string.IsNullOrEmpty(data.format.size))
- {
- video.Size = long.Parse(data.format.size, _usCulture);
- }
- else
- {
- video.Size = null;
- }
+ video.Container = extension;
+ }
+ else
+ {
+ video.Container = null;
}
- var mediaChapters = (data.Chapters ?? new MediaChapter[] { }).ToList();
- var chapters = mediaChapters.Select(GetChapterInfo).ToList();
-
+ var chapters = mediaInfo.Chapters ?? new List<ChapterInfo>();
if (video.VideoType == VideoType.BluRay || (video.IsoType.HasValue && video.IsoType.Value == IsoType.BluRay))
{
FetchBdInfo(video, chapters, mediaStreams, blurayInfo);
@@ -228,7 +218,7 @@ namespace MediaBrowser.Providers.MediaInfo
await AddExternalSubtitles(video, mediaStreams, options, cancellationToken).ConfigureAwait(false);
- FetchWtvInfo(video, data);
+ FetchEmbeddedInfo(video, mediaInfo, options);
video.IsHD = mediaStreams.Any(i => i.Type == MediaStreamType.Video && i.Width.HasValue && i.Width.Value >= 1270);
@@ -238,9 +228,7 @@ namespace MediaBrowser.Providers.MediaInfo
video.DefaultVideoStreamIndex = videoStream == null ? (int?)null : videoStream.Index;
video.HasSubtitles = mediaStreams.Any(i => i.Type == MediaStreamType.Subtitle);
-
- ExtractTimestamp(video);
- UpdateFromMediaInfo(video, videoStream);
+ video.Timestamp = mediaInfo.Timestamp;
await _itemRepo.SaveMediaStreams(video.Id, mediaStreams, cancellationToken).ConfigureAwait(false);
@@ -283,29 +271,6 @@ namespace MediaBrowser.Providers.MediaInfo
}
}
- private void UpdateFromMediaInfo(Video video, MediaStream videoStream)
- {
- if (video.VideoType == VideoType.VideoFile && video.LocationType != LocationType.Remote && video.LocationType != LocationType.Virtual)
- {
- if (videoStream != null)
- {
- try
- {
- var result = new MediaInfoLib().GetVideoInfo(video.Path);
-
- videoStream.IsCabac = result.IsCabac ?? videoStream.IsCabac;
- videoStream.IsInterlaced = result.IsInterlaced ?? videoStream.IsInterlaced;
- videoStream.BitDepth = result.BitDepth ?? videoStream.BitDepth;
- videoStream.RefFrames = result.RefFrames;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error running MediaInfo on {0}", ex, video.Path);
- }
- }
- }
- }
-
private void NormalizeChapterNames(List<ChapterInfo> chapters)
{
var index = 1;
@@ -325,32 +290,6 @@ namespace MediaBrowser.Providers.MediaInfo
}
}
- private ChapterInfo GetChapterInfo(MediaChapter chapter)
- {
- var info = new ChapterInfo();
-
- if (chapter.tags != null)
- {
- string name;
- if (chapter.tags.TryGetValue("title", out name))
- {
- info.Name = name;
- }
- }
-
- // Limit accuracy to milliseconds to match xml saving
- var secondsString = chapter.start_time;
- double seconds;
-
- if (double.TryParse(secondsString, NumberStyles.Any, CultureInfo.InvariantCulture, out seconds))
- {
- var ms = Math.Round(TimeSpan.FromSeconds(seconds).TotalMilliseconds);
- info.StartPositionTicks = TimeSpan.FromMilliseconds(ms).Ticks;
- }
-
- return info;
- }
-
private void FetchBdInfo(BaseItem item, List<ChapterInfo> chapters, List<MediaStream> mediaStreams, BlurayDiscInfo blurayInfo)
{
var video = (Video)item;
@@ -419,129 +358,102 @@ namespace MediaBrowser.Providers.MediaInfo
return _blurayExaminer.GetDiscInfo(path);
}
- public const int MaxSubtitleDescriptionExtractionLength = 100; // When extracting subtitles, the maximum length to consider (to avoid invalid filenames)
-
- private void FetchWtvInfo(Video video, InternalMediaInfoResult data)
+ private void FetchEmbeddedInfo(Video video, Model.MediaInfo.MediaInfo data, MetadataRefreshOptions options)
{
- if (data.format == null || data.format.tags == null)
+ var isFullRefresh = options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh;
+
+ if (!video.LockedFields.Contains(MetadataFields.OfficialRating))
{
- return;
+ if (!string.IsNullOrWhiteSpace(data.OfficialRating) || isFullRefresh)
+ {
+ video.OfficialRating = data.OfficialRating;
+ }
}
- if (!video.LockedFields.Contains(MetadataFields.Genres))
+ if (!video.LockedFields.Contains(MetadataFields.Cast))
{
- var genres = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/Genre");
-
- if (!string.IsNullOrWhiteSpace(genres))
+ if (video.People.Count == 0 || isFullRefresh)
{
- //genres = FFProbeHelpers.GetDictionaryValue(data.format.tags, "genre");
+ video.People.Clear();
+
+ foreach (var person in data.People)
+ {
+ video.AddPerson(new PersonInfo
+ {
+ Name = person.Name,
+ Type = person.Type,
+ Role = person.Role
+ });
+ }
}
+ }
- if (!string.IsNullOrWhiteSpace(genres))
+ if (!video.LockedFields.Contains(MetadataFields.Genres))
+ {
+ if (video.Genres.Count == 0 || isFullRefresh)
{
- video.Genres = genres.Split(new[] { ';', '/', ',' }, StringSplitOptions.RemoveEmptyEntries)
- .Where(i => !string.IsNullOrWhiteSpace(i))
- .Select(i => i.Trim())
- .ToList();
+ video.Genres.Clear();
+
+ foreach (var genre in data.Genres)
+ {
+ video.AddGenre(genre);
+ }
}
}
- if (!video.LockedFields.Contains(MetadataFields.OfficialRating))
+ if (!video.LockedFields.Contains(MetadataFields.Studios))
{
- var officialRating = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/ParentalRating");
-
- if (!string.IsNullOrWhiteSpace(officialRating))
+ if (video.Studios.Count == 0 || isFullRefresh)
{
- video.OfficialRating = officialRating;
+ video.Studios.Clear();
+
+ foreach (var studio in data.Studios)
+ {
+ video.AddStudio(studio);
+ }
}
}
- if (!video.LockedFields.Contains(MetadataFields.Cast))
+ if (data.ProductionYear.HasValue)
{
- var people = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/MediaCredits");
-
- if (!string.IsNullOrEmpty(people))
+ if (!video.ProductionYear.HasValue || isFullRefresh)
{
- video.People = people.Split(new[] { ';', '/' }, StringSplitOptions.RemoveEmptyEntries)
- .Where(i => !string.IsNullOrWhiteSpace(i))
- .Select(i => new PersonInfo { Name = i.Trim(), Type = PersonType.Actor })
- .ToList();
+ video.ProductionYear = data.ProductionYear;
}
}
-
- var year = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/OriginalReleaseTime");
- if (!string.IsNullOrWhiteSpace(year))
+ if (data.PremiereDate.HasValue)
{
- int val;
-
- if (int.TryParse(year, NumberStyles.Integer, _usCulture, out val))
+ if (!video.PremiereDate.HasValue || isFullRefresh)
{
- video.ProductionYear = val;
+ video.PremiereDate = data.PremiereDate;
}
}
-
- var premiereDateString = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/MediaOriginalBroadcastDateTime");
- if (!string.IsNullOrWhiteSpace(premiereDateString))
+ if (data.IndexNumber.HasValue)
{
- DateTime val;
-
- // Credit to MCEBuddy: https://mcebuddy2x.codeplex.com/
- // DateTime is reported along with timezone info (typically Z i.e. UTC hence assume None)
- if (DateTime.TryParse(year, null, DateTimeStyles.None, out val))
+ if (!video.IndexNumber.HasValue || isFullRefresh)
{
- video.PremiereDate = val.ToUniversalTime();
+ video.IndexNumber = data.IndexNumber;
}
}
-
- var description = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/SubTitleDescription");
-
- var episode = video as Episode;
- if (episode != null)
+ if (data.ParentIndexNumber.HasValue)
{
- var subTitle = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/SubTitle");
-
- // For below code, credit to MCEBuddy: https://mcebuddy2x.codeplex.com/
-
- // Sometimes for TV Shows the Subtitle field is empty and the subtitle description contains the subtitle, extract if possible. See ticket https://mcebuddy2x.codeplex.com/workitem/1910
- // The format is -> EPISODE/TOTAL_EPISODES_IN_SEASON. SUBTITLE: DESCRIPTION
- // OR -> COMMENT. SUBTITLE: DESCRIPTION
- // e.g. -> 4/13. The Doctor's Wife: Science fiction drama. When he follows a Time Lord distress signal, the Doctor puts Amy, Rory and his beloved TARDIS in grave danger. Also in HD. [AD,S]
- // e.g. -> CBeebies Bedtime Hour. The Mystery: Animated adventures of two friends who live on an island in the middle of the big city. Some of Abney and Teal's favourite objects are missing. [S]
- if (String.IsNullOrWhiteSpace(subTitle) && !String.IsNullOrWhiteSpace(description) && description.Substring(0, Math.Min(description.Length, MaxSubtitleDescriptionExtractionLength)).Contains(":")) // Check within the Subtitle size limit, otherwise from description it can get too long creating an invalid filename
+ if (!video.ParentIndexNumber.HasValue || isFullRefresh)
{
- string[] parts = description.Split(':');
- if (parts.Length > 0)
- {
- string subtitle = parts[0];
- try
- {
- if (subtitle.Contains("/")) // It contains a episode number and season number
- {
- string[] numbers = subtitle.Split(' ');
- episode.IndexNumber = int.Parse(numbers[0].Replace(".", "").Split('/')[0]);
- int totalEpisodesInSeason = int.Parse(numbers[0].Replace(".", "").Split('/')[1]);
-
- description = String.Join(" ", numbers, 1, numbers.Length - 1).Trim(); // Skip the first, concatenate the rest, clean up spaces and save it
- }
- else
- throw new Exception(); // Switch to default parsing
- }
- catch // Default parsing
- {
- if (subtitle.Contains(".")) // skip the comment, keep the subtitle
- description = String.Join(".", subtitle.Split('.'), 1, subtitle.Split('.').Length - 1).Trim(); // skip the first
- else
- description = subtitle.Trim(); // Clean up whitespaces and save it
- }
- }
+ video.ParentIndexNumber = data.ParentIndexNumber;
}
}
+ // If we don't have a ProductionYear try and get it from PremiereDate
+ if (video.PremiereDate.HasValue && !video.ProductionYear.HasValue)
+ {
+ video.ProductionYear = video.PremiereDate.Value.ToLocalTime().Year;
+ }
+
if (!video.LockedFields.Contains(MetadataFields.Overview))
{
- if (!string.IsNullOrWhiteSpace(description))
+ if (string.IsNullOrWhiteSpace(video.Overview) || isFullRefresh)
{
- video.Overview = description;
+ video.Overview = data.Overview;
}
}
}
@@ -709,56 +621,6 @@ namespace MediaBrowser.Providers.MediaInfo
}
}
- private void ExtractTimestamp(Video video)
- {
- if (video.VideoType == VideoType.VideoFile)
- {
- if (string.Equals(video.Container, "mpeg2ts", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(video.Container, "m2ts", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(video.Container, "ts", StringComparison.OrdinalIgnoreCase))
- {
- try
- {
- video.Timestamp = GetMpegTimestamp(video.Path);
-
- _logger.Debug("Video has {0} timestamp", video.Timestamp);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error extracting timestamp info from {0}", ex, video.Path);
- video.Timestamp = null;
- }
- }
- }
- }
-
- private TransportStreamTimestamp GetMpegTimestamp(string path)
- {
- var packetBuffer = new byte['Å'];
-
- using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
- {
- fs.Read(packetBuffer, 0, packetBuffer.Length);
- }
-
- if (packetBuffer[0] == 71)
- {
- return TransportStreamTimestamp.None;
- }
-
- if ((packetBuffer[4] == 71) && (packetBuffer['Ä'] == 71))
- {
- if ((packetBuffer[0] == 0) && (packetBuffer[1] == 0) && (packetBuffer[2] == 0) && (packetBuffer[3] == 0))
- {
- return TransportStreamTimestamp.Zero;
- }
-
- return TransportStreamTimestamp.Valid;
- }
-
- return TransportStreamTimestamp.None;
- }
-
private void FetchFromDvdLib(Video item, IIsoMount mount)
{
var path = mount == null ? item.Path : mount.MountedPath;
diff --git a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
index 7c3243225..bcea66662 100644
--- a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
@@ -6,6 +6,7 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
using System;
using System.Collections.Generic;
@@ -20,13 +21,15 @@ namespace MediaBrowser.Providers.MediaInfo
private readonly IMediaEncoder _mediaEncoder;
private readonly IServerConfigurationManager _config;
private readonly ILibraryManager _libraryManager;
+ private readonly ILogger _logger;
- public VideoImageProvider(IIsoManager isoManager, IMediaEncoder mediaEncoder, IServerConfigurationManager config, ILibraryManager libraryManager)
+ public VideoImageProvider(IIsoManager isoManager, IMediaEncoder mediaEncoder, IServerConfigurationManager config, ILibraryManager libraryManager, ILogger logger)
{
_isoManager = isoManager;
_mediaEncoder = mediaEncoder;
_config = config;
_libraryManager = libraryManager;
+ _logger = logger;
}
/// <summary>
@@ -74,6 +77,7 @@ namespace MediaBrowser.Providers.MediaInfo
// Can't extract if we didn't find a video stream in the file
if (!video.DefaultVideoStreamIndex.HasValue)
{
+ _logger.Debug("Skipping image extraction due to missing DefaultVideoStreamIndex for {0}.", video.Path ?? string.Empty);
return Task.FromResult(new DynamicImageResponse { HasImage = false });
}
diff --git a/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs b/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs
index 6e57ddb01..f133f74db 100644
--- a/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs
+++ b/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs
@@ -6,6 +6,7 @@ using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Providers.Music;
+using MediaBrowser.Providers.TV;
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -14,7 +15,6 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Providers.TV;
namespace MediaBrowser.Providers.Movies
{
diff --git a/MediaBrowser.Providers/Movies/MovieMetadataService.cs b/MediaBrowser.Providers/Movies/MovieMetadataService.cs
index 172ae6814..f886deb00 100644
--- a/MediaBrowser.Providers/Movies/MovieMetadataService.cs
+++ b/MediaBrowser.Providers/Movies/MovieMetadataService.cs
@@ -36,10 +36,6 @@ namespace MediaBrowser.Providers.Movies
protected override bool IsFullLocalMetadata(Movie item)
{
- if (string.IsNullOrWhiteSpace(item.Name))
- {
- return false;
- }
if (string.IsNullOrWhiteSpace(item.Overview))
{
return false;
diff --git a/MediaBrowser.Providers/Music/ArtistMetadataService.cs b/MediaBrowser.Providers/Music/ArtistMetadataService.cs
index 2497cc1ec..790529371 100644
--- a/MediaBrowser.Providers/Music/ArtistMetadataService.cs
+++ b/MediaBrowser.Providers/Music/ArtistMetadataService.cs
@@ -54,7 +54,7 @@ namespace MediaBrowser.Providers.Music
var currentList = item.Genres.ToList();
item.Genres = taggedItems.SelectMany(i => i.Genres)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.ToList();
if (currentList.Count != item.Genres.Count || !currentList.OrderBy(i => i).SequenceEqual(item.Genres.OrderBy(i => i), StringComparer.OrdinalIgnoreCase))
diff --git a/MediaBrowser.Providers/TV/SeriesMetadataService.cs b/MediaBrowser.Providers/TV/SeriesMetadataService.cs
index a5959f0b7..b0cd7382a 100644
--- a/MediaBrowser.Providers/TV/SeriesMetadataService.cs
+++ b/MediaBrowser.Providers/TV/SeriesMetadataService.cs
@@ -77,10 +77,6 @@ namespace MediaBrowser.Providers.TV
protected override bool IsFullLocalMetadata(Series item)
{
- if (string.IsNullOrWhiteSpace(item.Name))
- {
- return false;
- }
if (string.IsNullOrWhiteSpace(item.Overview))
{
return false;
diff --git a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs
index c644da0b8..a31cc1e0c 100644
--- a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs
@@ -10,6 +10,7 @@ using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Net;
using MediaBrowser.Model.Providers;
using System;
using System.Collections.Generic;
@@ -191,6 +192,27 @@ namespace MediaBrowser.Providers.TV
/// <returns>Task.</returns>
internal async Task DownloadSeriesZip(string seriesId, string seriesDataPath, long? lastTvDbUpdateTime, string preferredMetadataLanguage, CancellationToken cancellationToken)
{
+ try
+ {
+ await DownloadSeriesZip(seriesId, seriesDataPath, lastTvDbUpdateTime, preferredMetadataLanguage, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false);
+ return;
+ }
+ catch (HttpException ex)
+ {
+ if (!ex.StatusCode.HasValue || ex.StatusCode.Value != HttpStatusCode.NotFound)
+ {
+ throw;
+ }
+ }
+
+ if (!string.Equals(preferredMetadataLanguage, "en", StringComparison.OrdinalIgnoreCase))
+ {
+ await DownloadSeriesZip(seriesId, seriesDataPath, lastTvDbUpdateTime, "en", preferredMetadataLanguage, cancellationToken).ConfigureAwait(false);
+ }
+ }
+
+ private async Task DownloadSeriesZip(string seriesId, string seriesDataPath, long? lastTvDbUpdateTime, string preferredMetadataLanguage, string saveAsMetadataLanguage, CancellationToken cancellationToken)
+ {
var url = string.Format(SeriesGetZip, TVUtils.TvdbApiKey, seriesId, preferredMetadataLanguage);
using (var zipStream = await _httpClient.Get(new HttpRequestOptions
@@ -221,7 +243,15 @@ namespace MediaBrowser.Providers.TV
await SanitizeXmlFile(file).ConfigureAwait(false);
}
- await ExtractEpisodes(seriesDataPath, Path.Combine(seriesDataPath, preferredMetadataLanguage + ".xml"), lastTvDbUpdateTime).ConfigureAwait(false);
+ var downloadLangaugeXmlFile = Path.Combine(seriesDataPath, preferredMetadataLanguage + ".xml");
+ var saveAsLanguageXmlFile = Path.Combine(seriesDataPath, saveAsMetadataLanguage + ".xml");
+
+ if (!string.Equals(downloadLangaugeXmlFile, saveAsLanguageXmlFile, StringComparison.OrdinalIgnoreCase))
+ {
+ File.Copy(downloadLangaugeXmlFile, saveAsLanguageXmlFile, true);
+ }
+
+ await ExtractEpisodes(seriesDataPath, downloadLangaugeXmlFile, lastTvDbUpdateTime).ConfigureAwait(false);
}
public TvdbOptions GetTvDbOptions()
diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
index e22bf2e7f..6a0e1208a 100644
--- a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
+++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
@@ -330,7 +330,7 @@ namespace MediaBrowser.Server.Implementations.Channels
{
files = files.Where(i => _libraryManager.IsAudioFile(i.FullName));
}
-
+
var file = files
.FirstOrDefault(i => i.Name.StartsWith(filenamePrefix, StringComparison.OrdinalIgnoreCase));
@@ -1454,7 +1454,14 @@ namespace MediaBrowser.Server.Implementations.Channels
var host = new Uri(source.Path).Host.ToLower();
var channel = GetChannel(item.ChannelId);
var channelProvider = GetChannelProvider(channel);
- var limit = channelProvider.GetChannelFeatures().DailyDownloadLimit;
+ var features = channelProvider.GetChannelFeatures();
+
+ if (!features.SupportsContentDownloading)
+ {
+ throw new ArgumentException("The channel does not support downloading.");
+ }
+
+ var limit = features.DailyDownloadLimit;
if (!ValidateDownloadLimit(host, limit))
{
diff --git a/MediaBrowser.Server.Implementations/Collections/CollectionImageProvider.cs b/MediaBrowser.Server.Implementations/Collections/CollectionImageProvider.cs
index 80a7c50d1..f5ddbdb78 100644
--- a/MediaBrowser.Server.Implementations/Collections/CollectionImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/Collections/CollectionImageProvider.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies;
@@ -16,7 +17,7 @@ namespace MediaBrowser.Server.Implementations.Collections
{
public class CollectionImageProvider : BaseDynamicImageProvider<BoxSet>
{
- public CollectionImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths) : base(fileSystem, providerManager, applicationPaths)
+ public CollectionImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor) : base(fileSystem, providerManager, applicationPaths, imageProcessor)
{
}
diff --git a/MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs b/MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs
index bbe37cb50..8f5d8fe9b 100644
--- a/MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs
+++ b/MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs
@@ -14,9 +14,7 @@ namespace MediaBrowser.Server.Implementations.Collections
public override bool IsVisible(User user)
{
- return base.IsVisible(user) && GetChildren(user, false)
- .OfType<BoxSet>()
- .Any(i => i.IsVisible(user));
+ return base.IsVisible(user) && GetChildren(user, false).Any();
}
public override bool IsHidden
diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
index a7f8717a7..2d39f760e 100644
--- a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
+++ b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
@@ -517,7 +517,7 @@ namespace MediaBrowser.Server.Implementations.Connect
if (!connectUser.IsActive)
{
- throw new ArgumentException("The Emby account has been disabled.");
+ throw new ArgumentException("The Emby account is not active. Please ensure the account has been activated by following the instructions within the email confirmation.");
}
connectUserId = connectUser.Id;
@@ -1125,7 +1125,7 @@ namespace MediaBrowser.Server.Implementations.Connect
url += "?serverId=" + ConnectServerId;
url += "&supporterKey=" + _securityManager.SupporterKey;
url += "&userId=" + id;
-
+
var options = new HttpRequestOptions
{
Url = url,
@@ -1244,6 +1244,16 @@ namespace MediaBrowser.Server.Implementations.Connect
.FirstOrDefault(i => string.Equals(i.ConnectUserId, connectUserId, StringComparison.OrdinalIgnoreCase));
}
+ public User GetUserFromExchangeToken(string token)
+ {
+ if (string.IsNullOrWhiteSpace(token))
+ {
+ throw new ArgumentNullException("token");
+ }
+
+ return _userManager.Users.FirstOrDefault(u => string.Equals(token, u.ConnectAccessKey, StringComparison.OrdinalIgnoreCase));
+ }
+
public bool IsAuthorizationTokenValid(string token)
{
if (string.IsNullOrWhiteSpace(token))
diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
index 364a47945..f44b7b5a8 100644
--- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs
+++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
@@ -85,7 +85,7 @@ namespace MediaBrowser.Server.Implementations.Dto
public IEnumerable<BaseItemDto> GetBaseItemDtos(IEnumerable<BaseItem> items, DtoOptions options, User user = null, BaseItem owner = null)
{
- var itemIdsWithSyncJobs = GetItemIdsWithSyncJobs(options).ToList();
+ var tuple = GetItemIdsWithSyncJobs(options);
var list = new List<BaseItemDto>();
@@ -109,7 +109,7 @@ namespace MediaBrowser.Server.Implementations.Dto
}
}
- FillSyncInfo(dto, item, itemIdsWithSyncJobs, options, user);
+ FillSyncInfo(dto, item, tuple.Item1, tuple.Item2, options, user);
list.Add(dto);
}
@@ -145,29 +145,29 @@ namespace MediaBrowser.Server.Implementations.Dto
return dto;
}
- private IEnumerable<string> GetItemIdsWithSyncJobs(DtoOptions options)
+ private Tuple<IEnumerable<string>, IEnumerable<string>> GetItemIdsWithSyncJobs(DtoOptions options)
{
if (!options.Fields.Contains(ItemFields.SyncInfo))
{
- return new List<string>();
+ return new Tuple<IEnumerable<string>, IEnumerable<string>>(new List<string>(), new List<string>());
}
var deviceId = options.DeviceId;
if (string.IsNullOrWhiteSpace(deviceId))
{
- return new List<string>();
+ return new Tuple<IEnumerable<string>, IEnumerable<string>>(new List<string>(), new List<string>());
}
var caps = _deviceManager().GetCapabilities(deviceId);
if (caps == null || !caps.SupportsSync)
{
- return new List<string>();
+ return new Tuple<IEnumerable<string>, IEnumerable<string>>(new List<string>(), new List<string>());
}
- var result = _syncManager.GetLibraryItemIds(new SyncJobItemQuery
+ var result1 = _syncManager.GetLibraryItemIds(new SyncJobItemQuery
{
TargetId = deviceId,
- Statuses = new SyncJobItemStatus[]
+ Statuses = new[]
{
SyncJobItemStatus.Converting,
SyncJobItemStatus.Queued,
@@ -176,10 +176,34 @@ namespace MediaBrowser.Server.Implementations.Dto
}
});
- return result.Items;
+ var result2 = _syncManager.GetLibraryItemIds(new SyncJobItemQuery
+ {
+ TargetId = deviceId,
+ Statuses = new[]
+ {
+ SyncJobItemStatus.Synced
+ }
+ });
+
+ return new Tuple<IEnumerable<string>, IEnumerable<string>>(result1.Items, result2.Items);
+ }
+
+ public void FillSyncInfo(IEnumerable<IHasSyncInfo> dtos, DtoOptions options, User user)
+ {
+ if (options.Fields.Contains(ItemFields.SyncInfo))
+ {
+ var tuple = GetItemIdsWithSyncJobs(options);
+
+ foreach (var dto in dtos)
+ {
+ var item = _libraryManager.GetItemById(dto.Id);
+
+ FillSyncInfo(dto, item, tuple.Item1, tuple.Item2, options, user);
+ }
+ }
}
- private void FillSyncInfo(BaseItemDto dto, BaseItem item, DtoOptions options, User user)
+ private void FillSyncInfo(IHasSyncInfo dto, BaseItem item, DtoOptions options, User user)
{
if (options.Fields.Contains(ItemFields.SyncInfo))
{
@@ -189,11 +213,24 @@ namespace MediaBrowser.Server.Implementations.Dto
if (dto.SupportsSync ?? false)
{
- dto.HasSyncJob = GetItemIdsWithSyncJobs(options).Contains(dto.Id, StringComparer.OrdinalIgnoreCase);
+ var tuple = GetItemIdsWithSyncJobs(options);
+
+ dto.HasSyncJob = tuple.Item1.Contains(dto.Id, StringComparer.OrdinalIgnoreCase);
+ dto.IsSynced = tuple.Item2.Contains(dto.Id, StringComparer.OrdinalIgnoreCase);
+
+ if (dto.IsSynced.Value)
+ {
+ dto.SyncStatus = SyncJobItemStatus.Synced;
+ }
+
+ else if (dto.HasSyncJob.Value)
+ {
+ dto.SyncStatus = SyncJobItemStatus.Queued;
+ }
}
}
- private void FillSyncInfo(BaseItemDto dto, BaseItem item, IEnumerable<string> itemIdsWithSyncJobs, DtoOptions options, User user)
+ private void FillSyncInfo(IHasSyncInfo dto, BaseItem item, IEnumerable<string> itemIdsWithPendingSyncJobs, IEnumerable<string> syncedItemIds, DtoOptions options, User user)
{
if (options.Fields.Contains(ItemFields.SyncInfo))
{
@@ -203,7 +240,18 @@ namespace MediaBrowser.Server.Implementations.Dto
if (dto.SupportsSync ?? false)
{
- dto.HasSyncJob = itemIdsWithSyncJobs.Contains(dto.Id, StringComparer.OrdinalIgnoreCase);
+ dto.HasSyncJob = itemIdsWithPendingSyncJobs.Contains(dto.Id, StringComparer.OrdinalIgnoreCase);
+ dto.IsSynced = syncedItemIds.Contains(dto.Id, StringComparer.OrdinalIgnoreCase);
+
+ if (dto.IsSynced.Value)
+ {
+ dto.SyncStatus = SyncJobItemStatus.Synced;
+ }
+
+ else if (dto.HasSyncJob.Value)
+ {
+ dto.SyncStatus = SyncJobItemStatus.Queued;
+ }
}
}
@@ -269,7 +317,7 @@ namespace MediaBrowser.Server.Implementations.Dto
}
}
}
-
+
if (fields.Contains(ItemFields.Studios))
{
AttachStudios(dto, item);
@@ -309,6 +357,11 @@ namespace MediaBrowser.Server.Implementations.Dto
: item.CanDownload(user);
}
+ if (fields.Contains(ItemFields.Etag))
+ {
+ dto.Etag = item.GetEtag(user);
+ }
+
return dto;
}
@@ -775,14 +828,11 @@ namespace MediaBrowser.Server.Implementations.Dto
if (!string.IsNullOrEmpty(chapterInfo.ImagePath))
{
- var file = new FileInfo(chapterInfo.ImagePath);
-
dto.ImageTag = GetImageCacheTag(item, new ItemImageInfo
{
Path = chapterInfo.ImagePath,
Type = ImageType.Chapter,
- DateModified = _fileSystem.GetLastWriteTimeUtc(file),
- Length = file.Length
+ DateModified = _fileSystem.GetLastWriteTimeUtc(chapterInfo.ImagePath)
});
}
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
index 5c69db3e1..3fa0df760 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
@@ -47,7 +47,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
void _config_ConfigurationUpdated(object sender, EventArgs e)
{
_config.ConfigurationUpdated -= _config_ConfigurationUpdated;
-
+
if (!string.Equals(_lastConfigIdentifier, GetConfigIdentifier(), StringComparison.OrdinalIgnoreCase))
{
if (_isStarted)
@@ -88,7 +88,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
NatUtility.UnhandledException += NatUtility_UnhandledException;
NatUtility.StartDiscovery();
- _timer = new Timer(s => _createdRules = new List<string>(), null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
+ _timer = new Timer(s => _createdRules = new List<string>(), null, TimeSpan.FromMinutes(3), TimeSpan.FromMinutes(3));
_lastConfigIdentifier = GetConfigIdentifier();
@@ -119,7 +119,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
CreateRules(device);
}
- catch (Exception)
+ catch (Exception ex)
{
// I think it could be a good idea to log the exception because
// you are using permanent portmapping here (never expire) and that means that next time
@@ -128,7 +128,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
// It also can fail with others like 727-ExternalPortOnlySupportsWildcard, 728-NoPortMapsAvailable
// and those errors (upnp errors) could be useful for diagnosting.
- //_logger.ErrorException("Error creating port forwarding rules", ex);
+ _logger.ErrorException("Error creating port forwarding rules", ex);
}
}
@@ -152,7 +152,6 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
private void CreatePortMap(INatDevice device, int privatePort, int publicPort)
{
_logger.Debug("Creating port map on port {0}", privatePort);
-
device.CreatePortMap(new Mapping(Protocol.Tcp, privatePort, publicPort)
{
Description = _appHost.Name
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/MediaBrowser.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
index 090f1e756..03daa4c2a 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Channels;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Session;
@@ -69,7 +70,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
/// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
void libraryManager_ItemAdded(object sender, ItemChangeEventArgs e)
{
- if (e.Item.LocationType == LocationType.Virtual)
+ if (!FilterItem(e.Item))
{
return;
}
@@ -102,7 +103,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
/// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
void libraryManager_ItemUpdated(object sender, ItemChangeEventArgs e)
{
- if (e.Item.LocationType == LocationType.Virtual)
+ if (!FilterItem(e.Item))
{
return;
}
@@ -130,7 +131,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
/// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
void libraryManager_ItemRemoved(object sender, ItemChangeEventArgs e)
{
- if (e.Item.LocationType == LocationType.Virtual)
+ if (!FilterItem(e.Item))
{
return;
}
@@ -243,39 +244,39 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
{
var user = _userManager.GetUserById(userId);
- var collections = user.RootFolder.GetChildren(user, true).ToList();
-
- var allRecursiveChildren = user.RootFolder
- .GetRecursiveChildren(user)
- .Select(i => i.Id)
- .Distinct()
- .ToDictionary(i => i);
-
return new LibraryUpdateInfo
{
- ItemsAdded = itemsAdded.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user, collections, allRecursiveChildren)).Select(i => i.Id.ToString("N")).Distinct().ToList(),
+ ItemsAdded = itemsAdded.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToList(),
- ItemsUpdated = itemsUpdated.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user, collections, allRecursiveChildren)).Select(i => i.Id.ToString("N")).Distinct().ToList(),
+ ItemsUpdated = itemsUpdated.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToList(),
- ItemsRemoved = itemsRemoved.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user, collections, allRecursiveChildren, true)).Select(i => i.Id.ToString("N")).Distinct().ToList(),
+ ItemsRemoved = itemsRemoved.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user, true)).Select(i => i.Id.ToString("N")).Distinct().ToList(),
- FoldersAddedTo = foldersAddedTo.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user, collections, allRecursiveChildren)).Select(i => i.Id.ToString("N")).Distinct().ToList(),
+ FoldersAddedTo = foldersAddedTo.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToList(),
- FoldersRemovedFrom = foldersRemovedFrom.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user, collections, allRecursiveChildren)).Select(i => i.Id.ToString("N")).Distinct().ToList()
+ FoldersRemovedFrom = foldersRemovedFrom.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToList()
};
}
+ private bool FilterItem(BaseItem item)
+ {
+ if (item.LocationType == LocationType.Virtual)
+ {
+ return false;
+ }
+
+ return !(item is IChannelItem);
+ }
+
/// <summary>
/// Translates the physical item to user library.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="item">The item.</param>
/// <param name="user">The user.</param>
- /// <param name="collections">The collections.</param>
- /// <param name="allRecursiveChildren">All recursive children.</param>
/// <param name="includeIfNotFound">if set to <c>true</c> [include if not found].</param>
/// <returns>IEnumerable{``0}.</returns>
- private IEnumerable<T> TranslatePhysicalItemToUserLibrary<T>(T item, User user, IEnumerable<BaseItem> collections, Dictionary<Guid, Guid> allRecursiveChildren, bool includeIfNotFound = false)
+ private IEnumerable<T> TranslatePhysicalItemToUserLibrary<T>(T item, User user, bool includeIfNotFound = false)
where T : BaseItem
{
// If the physical root changed, return the user root
@@ -284,17 +285,8 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
return new[] { user.RootFolder as T };
}
- // Need to find what user collection folder this belongs to
- if (item.Parent is AggregateFolder)
- {
- if (item.LocationType == LocationType.FileSystem)
- {
- return collections.Where(i => i.PhysicalLocations.Contains(item.Path)).Cast<T>();
- }
- }
-
// Return it only if it's in the user's library
- if (includeIfNotFound || allRecursiveChildren.ContainsKey(item.Id) || (item.Parents.Any(i => i is BasePluginFolder) && item.IsVisibleStandalone(user)))
+ if (includeIfNotFound || item.IsVisibleStandalone(user))
{
return new[] { item };
}
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs b/MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
index ccd427a47..008363ca4 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
@@ -68,7 +68,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
}
keys.Add(e.Item);
-
+
var baseItem = e.Item as BaseItem;
// Go up one level for indicators
@@ -117,7 +117,12 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
var dtoList = pair.Value
.DistinctBy(i => i.Id)
- .Select(i => _userDataManager.GetUserDataDto(i, user))
+ .Select(i =>
+ {
+ var dto = _userDataManager.GetUserDataDto(i, user);
+ dto.ItemId = i.Id.ToString("N");
+ return dto;
+ })
.ToList();
var info = new UserDataChangeInfo
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
index f91054206..dc9656f80 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -305,7 +305,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer
var operationName = httpReq.OperationName;
var localPath = url.LocalPath;
- if (string.Equals(localPath, "/mediabrowser/", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(localPath, "/mediabrowser/", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(localPath, "/emby/", StringComparison.OrdinalIgnoreCase))
{
httpRes.RedirectToUrl(DefaultRedirectPath);
return Task.FromResult(true);
@@ -315,6 +316,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer
httpRes.RedirectToUrl("mediabrowser/" + DefaultRedirectPath);
return Task.FromResult(true);
}
+ if (string.Equals(localPath, "/emby", StringComparison.OrdinalIgnoreCase))
+ {
+ httpRes.RedirectToUrl("emby/" + DefaultRedirectPath);
+ return Task.FromResult(true);
+ }
if (string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase))
{
httpRes.RedirectToUrl(DefaultRedirectPath);
@@ -384,6 +390,12 @@ namespace MediaBrowser.Server.Implementations.HttpServer
foreach (var route in clone)
{
+ routes.Add(new RouteAttribute(NormalizeEmbyRoutePath(route.Path), route.Verbs)
+ {
+ Notes = route.Notes,
+ Priority = route.Priority,
+ Summary = route.Summary
+ });
routes.Add(new RouteAttribute(NormalizeRoutePath(route.Path), route.Verbs)
{
Notes = route.Notes,
@@ -398,11 +410,37 @@ namespace MediaBrowser.Server.Implementations.HttpServer
Priority = route.Priority,
Summary = route.Summary
});
+ routes.Add(new RouteAttribute(DoubleNormalizeEmbyRoutePath(route.Path), route.Verbs)
+ {
+ Notes = route.Notes,
+ Priority = route.Priority,
+ Summary = route.Summary
+ });
}
return routes.ToArray();
}
+ private string NormalizeEmbyRoutePath(string path)
+ {
+ if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase))
+ {
+ return "/emby" + path;
+ }
+
+ return "emby/" + path;
+ }
+
+ private string DoubleNormalizeEmbyRoutePath(string path)
+ {
+ if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase))
+ {
+ return "/emby/emby" + path;
+ }
+
+ return "emby/emby/" + path;
+ }
+
private string NormalizeRoutePath(string path)
{
if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase))
diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
index cd4d23f5c..9461143a8 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Net;
+using MediaBrowser.Controller.Connect;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Security;
using ServiceStack.Web;
using System;
@@ -10,10 +11,12 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
public class AuthorizationContext : IAuthorizationContext
{
private readonly IAuthenticationRepository _authRepo;
+ private readonly IConnectManager _connectManager;
- public AuthorizationContext(IAuthenticationRepository authRepo)
+ public AuthorizationContext(IAuthenticationRepository authRepo, IConnectManager connectManager)
{
_authRepo = authRepo;
+ _connectManager = connectManager;
}
public AuthorizationInfo GetAuthorizationInfo(object requestContext)
@@ -144,6 +147,14 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
info.DeviceId = tokenInfo.DeviceId;
}
}
+ else
+ {
+ var user = _connectManager.GetUserFromExchangeToken(token);
+ if (user != null)
+ {
+ info.UserId = user.Id.ToString("N");
+ }
+ }
httpReq.Items["OriginalAuthenticationInfo"] = tokenInfo;
}
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index f9fa1aae3..dcdf2aa7d 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -732,7 +732,12 @@ namespace MediaBrowser.Server.Implementations.Library
}
}
- folder = GetItemById(folder.Id) as BasePluginFolder ?? folder;
+ var dbItem = GetItemById(folder.Id) as BasePluginFolder;
+
+ if (dbItem != null && string.Equals(dbItem.Path, folder.Path, StringComparison.OrdinalIgnoreCase))
+ {
+ folder = dbItem;
+ }
rootFolder.AddVirtualChild(folder);
@@ -921,10 +926,8 @@ namespace MediaBrowser.Server.Implementations.Library
if (isArtist)
{
- var validFilename = _fileSystem.GetValidFilename(name).Trim();
-
var existing = RootFolder
- .GetRecursiveChildren(i => i is T && string.Equals(_fileSystem.GetValidFilename(i.Name).Trim(), validFilename, StringComparison.OrdinalIgnoreCase))
+ .GetRecursiveChildren(i => i is T && NameExtensions.AreEqual(i.Name, name))
.Cast<T>()
.FirstOrDefault();
@@ -1510,7 +1513,7 @@ namespace MediaBrowser.Server.Implementations.Library
return GetUserRootFolder().Children
.OfType<Folder>()
- .Where(i => 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, StringComparer.OrdinalIgnoreCase));
}
public string GetContentType(BaseItem item)
@@ -1599,7 +1602,7 @@ namespace MediaBrowser.Server.Implementations.Library
{
if (ConfigurationManager.Configuration.EnableUserSpecificUserViews)
{
- return await GetNamedViewInternal(user, name, null, viewType, sortName, cancellationToken)
+ return await GetNamedViewInternal(user, name, null, viewType, sortName, null, cancellationToken)
.ConfigureAwait(false);
}
@@ -1634,6 +1637,12 @@ namespace MediaBrowser.Server.Implementations.Library
refresh = true;
}
+ if (!string.Equals(viewType, item.ViewType, StringComparison.OrdinalIgnoreCase))
+ {
+ item.ViewType = viewType;
+ await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
+ }
+
if (!refresh && item != null)
{
refresh = (DateTime.UtcNow - item.DateLastSaved).TotalHours >= 24;
@@ -1653,6 +1662,7 @@ namespace MediaBrowser.Server.Implementations.Library
string parentId,
string viewType,
string sortName,
+ string uniqueId,
CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(parentId))
@@ -1660,7 +1670,7 @@ namespace MediaBrowser.Server.Implementations.Library
throw new ArgumentNullException("parentId");
}
- return GetNamedViewInternal(user, name, parentId, viewType, sortName, cancellationToken);
+ return GetNamedViewInternal(user, name, parentId, viewType, sortName, uniqueId, cancellationToken);
}
private async Task<UserView> GetNamedViewInternal(User user,
@@ -1668,6 +1678,7 @@ namespace MediaBrowser.Server.Implementations.Library
string parentId,
string viewType,
string sortName,
+ string uniqueId,
CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(name))
@@ -1675,12 +1686,13 @@ namespace MediaBrowser.Server.Implementations.Library
throw new ArgumentNullException("name");
}
- if (string.IsNullOrWhiteSpace(viewType))
+ var idValues = "37_namedview_" + name + user.Id.ToString("N") + (parentId ?? string.Empty);
+ if (!string.IsNullOrWhiteSpace(uniqueId))
{
- throw new ArgumentNullException("viewType");
+ idValues += uniqueId;
}
- var id = GetNewItemId("37_namedview_" + name + user.Id.ToString("N") + (parentId ?? string.Empty), typeof(UserView));
+ var id = GetNewItemId(idValues, typeof(UserView));
var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N"));
@@ -1713,7 +1725,13 @@ namespace MediaBrowser.Server.Implementations.Library
isNew = true;
}
- var refresh = isNew || (DateTime.UtcNow - item.DateLastSaved).TotalHours >= 12;
+ if (!string.Equals(viewType, item.ViewType, StringComparison.OrdinalIgnoreCase))
+ {
+ item.ViewType = viewType;
+ await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
+ }
+
+ var refresh = isNew || (DateTime.UtcNow - item.DateLastSaved).TotalHours >= 24;
if (refresh)
{
diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
index 27a7d4ea9..71fd4127b 100644
--- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
@@ -129,29 +129,19 @@ namespace MediaBrowser.Server.Implementations.Library
return list;
}
- public Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, bool enablePathSubstitution, CancellationToken cancellationToken)
- {
- return GetPlayackMediaSources(id, null, enablePathSubstitution, cancellationToken);
- }
-
- public async Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, string userId, bool enablePathSubstitution, CancellationToken cancellationToken)
+ public async Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, string userId, bool enablePathSubstitution, string[] supportedLiveMediaTypes, CancellationToken cancellationToken)
{
var item = _libraryManager.GetItemById(id);
- IEnumerable<MediaSourceInfo> mediaSources;
var hasMediaSources = (IHasMediaSources)item;
User user = null;
- if (string.IsNullOrWhiteSpace(userId))
- {
- mediaSources = hasMediaSources.GetMediaSources(enablePathSubstitution);
- }
- else
+ if (!string.IsNullOrWhiteSpace(userId))
{
user = _userManager.GetUserById(userId);
- mediaSources = GetStaticMediaSources(hasMediaSources, enablePathSubstitution, user);
}
+ var mediaSources = GetStaticMediaSources(hasMediaSources, enablePathSubstitution, user);
var dynamicMediaSources = await GetDynamicMediaSources(hasMediaSources, cancellationToken).ConfigureAwait(false);
var list = new List<MediaSourceInfo>();
@@ -166,9 +156,11 @@ namespace MediaBrowser.Server.Implementations.Library
}
if (source.Protocol == MediaProtocol.File)
{
- source.SupportsDirectStream = File.Exists(source.Path);
-
// TODO: Path substitution
+ if (!File.Exists(source.Path))
+ {
+ source.SupportsDirectStream = false;
+ }
}
else if (source.Protocol == MediaProtocol.Http)
{
@@ -183,6 +175,27 @@ namespace MediaBrowser.Server.Implementations.Library
list.Add(source);
}
+ foreach (var source in list)
+ {
+ if (user != null)
+ {
+ if (string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase))
+ {
+ if (!user.Policy.EnableAudioPlaybackTranscoding)
+ {
+ source.SupportsTranscoding = false;
+ }
+ }
+ else if (string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
+ {
+ if (!user.Policy.EnableVideoPlaybackTranscoding)
+ {
+ source.SupportsTranscoding = false;
+ }
+ }
+ }
+ }
+
return SortMediaSources(list).Where(i => i.Type != MediaSourceType.Placeholder);
}
@@ -230,9 +243,12 @@ namespace MediaBrowser.Server.Implementations.Library
}
}
- public MediaSourceInfo GetStaticMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution)
+ public async Task<MediaSourceInfo> GetMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution)
{
- return GetStaticMediaSources(item, enablePathSubstitution).FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));
+ var sources = await GetPlayackMediaSources(item.Id.ToString("N"), null, enablePathSubstitution, new[] { MediaType.Audio, MediaType.Video },
+ CancellationToken.None).ConfigureAwait(false);
+
+ return sources.FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));
}
public IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user = null)
@@ -343,6 +359,7 @@ namespace MediaBrowser.Server.Implementations.Library
}
var json = _jsonSerializer.SerializeToString(mediaSource);
+ _logger.Debug("Live stream opened: " + json);
var clone = _jsonSerializer.DeserializeFromString<MediaSourceInfo>(json);
if (!string.IsNullOrWhiteSpace(request.UserId))
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
index 71daf2b0c..f88293b2a 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
@@ -64,7 +64,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
if (string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
{
- return ResolveVideos<Video>(parent, files, directoryService, collectionType, false);
+ //return ResolveVideos<Video>(parent, files, directoryService, collectionType, false);
}
if (string.IsNullOrEmpty(collectionType))
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs
index acae5b801..e7f239780 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Drawing;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Model.Entities;
@@ -10,6 +11,12 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
{
public class PhotoAlbumResolver : FolderResolver<PhotoAlbum>
{
+ private readonly IImageProcessor _imageProcessor;
+ public PhotoAlbumResolver(IImageProcessor imageProcessor)
+ {
+ _imageProcessor = imageProcessor;
+ }
+
/// <summary>
/// Resolves the specified args.
/// </summary>
@@ -32,9 +39,9 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
return null;
}
- private static bool HasPhotos(ItemResolveArgs args)
+ private bool HasPhotos(ItemResolveArgs args)
{
- return args.FileSystemChildren.Any(i => ((i.Attributes & FileAttributes.Directory) != FileAttributes.Directory) && PhotoResolver.IsImageFile(i.FullName));
+ return args.FileSystemChildren.Any(i => ((i.Attributes & FileAttributes.Directory) != FileAttributes.Directory) && PhotoResolver.IsImageFile(i.FullName, _imageProcessor));
}
public override ResolverPriority Priority
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs
index b714e968b..407aac53d 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Drawing;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities;
using System;
@@ -9,6 +10,12 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
{
public class PhotoResolver : ItemResolver<Photo>
{
+ private readonly IImageProcessor _imageProcessor;
+ public PhotoResolver(IImageProcessor imageProcessor)
+ {
+ _imageProcessor = imageProcessor;
+ }
+
/// <summary>
/// Resolves the specified args.
/// </summary>
@@ -19,7 +26,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
// Must be an image file within a photo collection
if (string.Equals(args.GetCollectionType(), CollectionType.Photos, StringComparison.OrdinalIgnoreCase) &&
!args.IsDirectory &&
- IsImageFile(args.Path))
+ IsImageFile(args.Path, _imageProcessor))
{
return new Photo
{
@@ -30,9 +37,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
return null;
}
- // Some common file name extensions for RAW picture files include: .cr2, .crw, .dng, .nef, .orf, .rw2, .pef, .arw, .sr2, .srf, and .tif.
- protected static string[] ImageExtensions = { ".tiff", ".jpeg", ".jpg", ".png", ".aiff", ".cr2", ".crw", ".dng", ".nef", ".orf", ".pef", ".arw", ".webp" };
-
private static readonly string[] IgnoreFiles =
{
"folder",
@@ -43,12 +47,12 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
"poster"
};
- internal static bool IsImageFile(string path)
+ internal static bool IsImageFile(string path, IImageProcessor imageProcessor)
{
var filename = Path.GetFileNameWithoutExtension(path) ?? string.Empty;
return !IgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase)
- && ImageExtensions.Contains(Path.GetExtension(path) ?? string.Empty, StringComparer.OrdinalIgnoreCase);
+ && imageProcessor.SupportedInputFormats.Contains((Path.GetExtension(path) ?? string.Empty).TrimStart('.'), StringComparer.OrdinalIgnoreCase);
}
}
diff --git a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs
index 51cad7a35..72bbefae4 100644
--- a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs
+++ b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs
@@ -122,7 +122,7 @@ namespace MediaBrowser.Server.Implementations.Library
var artists = items.OfType<Audio>()
.SelectMany(i => i.AllArtists)
.Where(i => !string.IsNullOrWhiteSpace(i))
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.ToList();
foreach (var item in artists)
diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
index 757f08562..5cff9046a 100644
--- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
@@ -53,6 +53,7 @@ namespace MediaBrowser.Server.Implementations.Library
.ToList();
var excludeFolderIds = user.Configuration.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).ToList();
+ var plainFolderIds = user.Configuration.PlainFolderViews.Select(i => new Guid(i)).ToList();
var standaloneFolders = folders
.Where(i => UserView.IsExcludedFromGrouping(i) || excludeFolderIds.Contains(i.Id))
@@ -72,13 +73,17 @@ namespace MediaBrowser.Server.Implementations.Library
var collectionFolder = folder as ICollectionFolder;
var folderViewType = collectionFolder == null ? null : collectionFolder.CollectionType;
- if (string.IsNullOrWhiteSpace(folderViewType))
+ if (plainFolderIds.Contains(folder.Id))
{
- list.Add(folder);
+ list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, false, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ }
+ else if (!string.IsNullOrWhiteSpace(folderViewType))
+ {
+ list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, true, string.Empty, user, cancellationToken).ConfigureAwait(false));
}
else
{
- list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ list.Add(folder);
}
}
}
@@ -87,44 +92,57 @@ namespace MediaBrowser.Server.Implementations.Library
list.AddRange(standaloneFolders);
}
- if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase)) ||
- foldersWithViewTypes.Any(i => string.IsNullOrWhiteSpace(i.CollectionType)))
+ var parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.CollectionType))
+ .ToList();
+
+ if (parents.Count > 0)
{
- list.Add(await GetUserView(CollectionType.TvShows, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ list.Add(await GetUserView(parents, list, CollectionType.TvShows, string.Empty, user, cancellationToken).ConfigureAwait(false));
}
- if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase)) ||
- foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase)))
+ parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase) || string.Equals(i.CollectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.CollectionType))
+ .ToList();
+
+ if (parents.Count > 0)
{
- list.Add(await GetUserView(CollectionType.Music, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ list.Add(await GetUserView(parents, list, CollectionType.Music, string.Empty, user, cancellationToken).ConfigureAwait(false));
}
- if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase)) ||
- foldersWithViewTypes.Any(i => string.IsNullOrWhiteSpace(i.CollectionType)))
+ parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.CollectionType))
+ .ToList();
+
+ if (parents.Count > 0)
{
- list.Add(await GetUserView(CollectionType.Movies, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ list.Add(await GetUserView(parents, list, CollectionType.Movies, string.Empty, user, cancellationToken).ConfigureAwait(false));
}
- if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Games, StringComparison.OrdinalIgnoreCase)))
+ parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.Games, StringComparison.OrdinalIgnoreCase))
+ .ToList();
+
+ if (parents.Count > 0)
{
- list.Add(await GetUserView(CollectionType.Games, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ list.Add(await GetUserView(parents, list, CollectionType.Games, string.Empty, user, cancellationToken).ConfigureAwait(false));
}
- if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase)))
+ parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase))
+ .ToList();
+
+ if (parents.Count > 0)
{
- //list.Add(_collectionManager.GetCollectionsFolder(user.Id.ToString("N")));
- list.Add(await GetUserView(CollectionType.BoxSets, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ list.Add(await GetUserView(parents, list, CollectionType.BoxSets, string.Empty, user, cancellationToken).ConfigureAwait(false));
}
- if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase)))
+ parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))
+ .ToList();
+
+ if (parents.Count > 0)
{
- //list.Add(_playlists.GetPlaylistsFolder(user.Id.ToString("N")));
- list.Add(await GetUserView(CollectionType.Playlists, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ list.Add(await GetUserView(parents, list, CollectionType.Playlists, string.Empty, user, cancellationToken).ConfigureAwait(false));
}
if (user.Configuration.DisplayFoldersView)
{
- list.Add(await GetUserView(CollectionType.Folders, "zz_" + CollectionType.Folders, user, cancellationToken).ConfigureAwait(false));
+ list.Add(await GetUserView(new List<ICollectionFolder>(), list, CollectionType.Folders, "zz_" + CollectionType.Folders, user, cancellationToken).ConfigureAwait(false));
}
if (query.IncludeExternalContent)
@@ -151,7 +169,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (_liveTvManager.GetEnabledUsers().Select(i => i.Id.ToString("N")).Contains(query.UserId))
{
//list.Add(await _liveTvManager.GetInternalLiveTvFolder(query.UserId, cancellationToken).ConfigureAwait(false));
- list.Add(await GetUserView(CollectionType.LiveTv, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ list.Add(await GetUserView(new List<ICollectionFolder>(), list, CollectionType.LiveTv, string.Empty, user, cancellationToken).ConfigureAwait(false));
}
}
@@ -172,7 +190,9 @@ namespace MediaBrowser.Server.Implementations.Library
public Task<UserView> GetUserSubView(string name, string parentId, string type, User user, string sortName, CancellationToken cancellationToken)
{
- return _libraryManager.GetNamedView(user, name, parentId, type, sortName, cancellationToken);
+ var uniqueId = parentId + "subview" + type;
+
+ return _libraryManager.GetNamedView(user, name, parentId, type, sortName, uniqueId, cancellationToken);
}
public Task<UserView> GetUserSubView(string parentId, string type, User user, string sortName, CancellationToken cancellationToken)
@@ -182,16 +202,49 @@ namespace MediaBrowser.Server.Implementations.Library
return GetUserSubView(name, parentId, type, user, sortName, cancellationToken);
}
- public Task<UserView> GetUserView(string type, string sortName, User user, CancellationToken cancellationToken)
+ public async Task<UserView> GetUserView(List<ICollectionFolder> parents, List<Folder> currentViews, string viewType, string sortName, User user, CancellationToken cancellationToken)
{
- var name = _localizationManager.GetLocalizedString("ViewType" + type);
+ var name = _localizationManager.GetLocalizedString("ViewType" + viewType);
+
+ if (parents.Count == 1 && parents.All(i => string.Equals(i.CollectionType, viewType, StringComparison.OrdinalIgnoreCase)))
+ {
+ if (!string.IsNullOrWhiteSpace(parents[0].Name))
+ {
+ name = parents[0].Name;
+ }
+
+ var parentId = parents[0].Id;
+
+ var enableRichView = !user.Configuration.PlainFolderViews.Contains(parentId.ToString("N"), StringComparer.OrdinalIgnoreCase);
+
+ if (!enableRichView || currentViews.OfType<UserView>().Any(i => string.Equals(i.ViewType, viewType, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase)))
+ {
+ return await GetUserView(parentId, name, viewType, enableRichView, sortName, user, cancellationToken).ConfigureAwait(false);
+ }
+
+ if (_config.Configuration.EnableUserSpecificUserViews)
+ {
+ viewType = enableRichView ? viewType : null;
+ var view = await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false);
+
+ if (view.ParentId != parentId)
+ {
+ view.ParentId = parentId;
+ await view.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
+ }
+ return view;
+ }
+
+ return await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false);
+ }
- return _libraryManager.GetNamedView(user, name, type, sortName, cancellationToken);
+ return await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false);
}
- public Task<UserView> GetUserView(Guid parentId, string name, string type, string sortName, User user, CancellationToken cancellationToken)
+ public Task<UserView> GetUserView(Guid parentId, string name, string viewType, bool enableRichView, string sortName, User user, CancellationToken cancellationToken)
{
- return _libraryManager.GetNamedView(user, name, parentId.ToString("N"), type, sortName, cancellationToken);
+ viewType = enableRichView ? viewType : null;
+ return _libraryManager.GetNamedView(user, name, parentId.ToString("N"), viewType, sortName, null, cancellationToken);
}
public List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request)
@@ -317,7 +370,7 @@ namespace MediaBrowser.Server.Implementations.Library
.RootFolder
.GetRecursiveChildren(filter);
}
-
+
private IEnumerable<BaseItem> GetItemsConfiguredForLatest(User user, Func<BaseItem, bool> filter)
{
// Avoid implicitly captured closure
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs
index a964738e6..c9440bb27 100644
--- a/MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs
+++ b/MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs
@@ -49,7 +49,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
.ToList();
var allArtists = allSongs.SelectMany(i => i.AllArtists)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.ToList();
var numComplete = 0;
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs
index 757936aa7..fe2e6a114 100644
--- a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs
+++ b/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs
@@ -36,7 +36,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
{
var items = _libraryManager.RootFolder.GetRecursiveChildren(i => (i is Game))
.SelectMany(i => i.Genres)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.ToList();
var numComplete = 0;
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs
index 3a06fac1b..fac5cfc35 100644
--- a/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs
+++ b/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs
@@ -37,7 +37,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
{
var items = _libraryManager.RootFolder.GetRecursiveChildren(i => !(i is IHasMusicGenres) && !(i is Game))
.SelectMany(i => i.Genres)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.ToList();
var numComplete = 0;
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs
index 25eddb48a..e3be75e9b 100644
--- a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs
+++ b/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs
@@ -36,7 +36,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
{
var items = _libraryManager.RootFolder.GetRecursiveChildren(i => (i is IHasMusicGenres))
.SelectMany(i => i.Genres)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.ToList();
var numComplete = 0;
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs
index 5feebab9c..066b96853 100644
--- a/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs
+++ b/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs
@@ -35,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
{
var items = _libraryManager.RootFolder.GetRecursiveChildren()
.SelectMany(i => i.Studios)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.ToList();
var numComplete = 0;
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs
index 401cf8765..00c15fdfc 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs
@@ -8,12 +8,12 @@ using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Querying;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Model.Querying;
namespace MediaBrowser.Server.Implementations.LiveTv
{
@@ -293,7 +293,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
ProgramName = info.ProgramName,
SourceType = info.SourceType,
Status = info.Status,
- ChannelName = channelName
+ ChannelName = channelName,
+ Url = info.Url
};
if (!string.IsNullOrEmpty(info.ChannelId))
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
index cb9bb7711..6aea6fcaa 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -54,11 +54,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
new ConcurrentDictionary<string, LiveStreamData>();
private List<Guid> _channelIdList = new List<Guid>();
- private Dictionary<Guid, LiveTvProgram> _programs = new Dictionary<Guid, LiveTvProgram>();
+ private Dictionary<Guid, LiveTvProgram> _programs;
private readonly ConcurrentDictionary<Guid, bool> _refreshedPrograms = new ConcurrentDictionary<Guid, bool>();
- private readonly SemaphoreSlim _refreshSemaphore = new SemaphoreSlim(1, 1);
-
public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager)
{
_config = config;
@@ -109,6 +107,37 @@ namespace MediaBrowser.Server.Implementations.LiveTv
_taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>();
}
+ private readonly object _programsDataLock = new object();
+ private Dictionary<Guid, LiveTvProgram> GetProgramsDictionary()
+ {
+ if (_programs == null)
+ {
+ lock (_programsDataLock)
+ {
+ if (_programs == null)
+ {
+ var dict = new Dictionary<Guid, LiveTvProgram>();
+
+ foreach (var item in _itemRepo.GetItemsOfType(typeof (LiveTvProgram))
+ .Cast<LiveTvProgram>()
+ .ToList())
+ {
+ dict[item.Id] = item;
+ }
+
+ _programs = dict;
+ }
+ }
+ }
+
+ return _programs;
+ }
+
+ private IEnumerable<LiveTvProgram> GetPrograms()
+ {
+ return GetProgramsDictionary().Values;
+ }
+
public async Task<QueryResult<LiveTvChannel>> GetInternalChannels(LiveTvChannelQuery query, CancellationToken cancellationToken)
{
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
@@ -260,7 +289,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
LiveTvProgram obj = null;
- _programs.TryGetValue(guid, out obj);
+ GetProgramsDictionary().TryGetValue(guid, out obj);
if (obj != null)
{
@@ -597,7 +626,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
item.ProductionYear = info.ProductionYear;
item.PremiereDate = item.PremiereDate ?? info.OriginalAirDate;
-
+
await item.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false);
return item;
@@ -691,7 +720,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public async Task<QueryResult<ProgramInfoDto>> GetPrograms(ProgramQuery query, CancellationToken cancellationToken)
{
- IEnumerable<LiveTvProgram> programs = _programs.Values;
+ IEnumerable<LiveTvProgram> programs = GetPrograms();
if (query.MinEndDate.HasValue)
{
@@ -806,7 +835,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public async Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, CancellationToken cancellationToken)
{
- IEnumerable<LiveTvProgram> programs = _programs.Values;
+ IEnumerable<LiveTvProgram> programs = GetPrograms();
var user = _userManager.GetUserById(query.UserId);
@@ -839,7 +868,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var programList = programs.ToList();
var genres = programList.SelectMany(i => i.Genres)
- .Distinct(StringComparer.OrdinalIgnoreCase)
+ .DistinctNames()
.Select(i => _libraryManager.GetGenre(i))
.ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);
@@ -973,8 +1002,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv
List<TimerInfo> timerList;
if (!timers.TryGetValue(program.ServiceName, out timerList))
{
- var tempTimers = await GetService(program.ServiceName).GetTimersAsync(cancellationToken).ConfigureAwait(false);
- timers[program.ServiceName] = timerList = tempTimers.ToList();
+ try
+ {
+ var tempTimers = await GetService(program.ServiceName).GetTimersAsync(cancellationToken).ConfigureAwait(false);
+ timers[program.ServiceName] = timerList = tempTimers.ToList();
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error getting timer infos", ex);
+ timers[program.ServiceName] = timerList = new List<TimerInfo>();
+ }
}
var timer = timerList.FirstOrDefault(i => string.Equals(i.ProgramId, program.ExternalId, StringComparison.OrdinalIgnoreCase));
@@ -995,29 +1032,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv
internal async Task RefreshChannels(IProgress<double> progress, CancellationToken cancellationToken)
{
- await _refreshSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- try
- {
- var innerProgress = new ActionableProgress<double>();
- innerProgress.RegisterAction(p => progress.Report(p * .9));
- await RefreshChannelsInternal(innerProgress, cancellationToken).ConfigureAwait(false);
+ var innerProgress = new ActionableProgress<double>();
+ innerProgress.RegisterAction(p => progress.Report(p * .9));
+ await RefreshChannelsInternal(innerProgress, cancellationToken).ConfigureAwait(false);
- innerProgress = new ActionableProgress<double>();
- innerProgress.RegisterAction(p => progress.Report(90 + (p * .1)));
- await CleanDatabaseInternal(progress, cancellationToken).ConfigureAwait(false);
+ innerProgress = new ActionableProgress<double>();
+ innerProgress.RegisterAction(p => progress.Report(90 + (p * .1)));
+ await CleanDatabaseInternal(progress, cancellationToken).ConfigureAwait(false);
- foreach (var program in _programs.Values
- .Where(i => (i.StartDate - DateTime.UtcNow).TotalDays <= 1)
- .ToList())
- {
- RefreshIfNeeded(program);
- }
- }
- finally
- {
- _refreshSemaphore.Release();
- }
+ RefreshIfNeeded(GetPrograms().ToList());
}
private async Task RefreshChannelsInternal(IProgress<double> progress, CancellationToken cancellationToken)
@@ -1141,37 +1164,29 @@ namespace MediaBrowser.Server.Implementations.LiveTv
progress.Report(80 * percent + 10);
}
- _programs = programs.ToDictionary(i => i.Id);
+ lock (_programsDataLock)
+ {
+ _programs = programs.ToDictionary(i => i.Id);
+ }
+
_refreshedPrograms.Clear();
progress.Report(90);
// Load these now which will prefetch metadata
- await GetRecordings(new RecordingQuery(), cancellationToken).ConfigureAwait(false);
+ var dtoOptions = new DtoOptions();
+ dtoOptions.Fields.Remove(ItemFields.SyncInfo);
+ await GetRecordings(new RecordingQuery(), dtoOptions, cancellationToken).ConfigureAwait(false);
progress.Report(100);
}
- public async Task CleanDatabase(IProgress<double> progress, CancellationToken cancellationToken)
- {
- await _refreshSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- try
- {
- await DeleteOldPrograms(_programs.Keys.ToList(), progress, cancellationToken).ConfigureAwait(false);
- }
- finally
- {
- _refreshSemaphore.Release();
- }
- }
-
private Task CleanDatabaseInternal(IProgress<double> progress, CancellationToken cancellationToken)
{
- return DeleteOldPrograms(_programs.Keys.ToList(), progress, cancellationToken);
+ return DeleteOldPrograms(GetProgramsDictionary().Keys.ToList(), progress, cancellationToken);
}
private async Task DeleteOldPrograms(List<Guid> currentIdList, IProgress<double> progress, CancellationToken cancellationToken)
{
- var list = _itemRepo.GetItemsOfType(typeof(LiveTvProgram)).ToList();
+ var list = _itemRepo.GetItemIdsOfType(typeof(LiveTvProgram)).ToList();
var numComplete = 0;
@@ -1212,8 +1227,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var days = Math.Round(((double)maxPrograms) / programsPerDay);
- // No less than 2, no more than 7
- return Math.Max(2, Math.Min(days, 7));
+ return Math.Max(3, Math.Min(days, 14));
}
private async Task<IEnumerable<Tuple<string, ChannelInfo>>> GetChannels(ILiveTvService service, CancellationToken cancellationToken)
@@ -1321,7 +1335,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
};
}
- public async Task<QueryResult<RecordingInfoDto>> GetRecordings(RecordingQuery query, CancellationToken cancellationToken)
+ public async Task<QueryResult<RecordingInfoDto>> GetRecordings(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken)
{
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
@@ -1337,6 +1351,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
})
.ToArray();
+ if (user != null)
+ {
+ _dtoService.FillSyncInfo(returnArray, new DtoOptions(), user);
+ }
+
return new QueryResult<RecordingInfoDto>
{
Items = returnArray,
@@ -1409,7 +1428,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public async Task DeleteRecording(string recordingId)
{
- var recording = await GetRecording(recordingId, CancellationToken.None).ConfigureAwait(false);
+ var dtoOptions = new DtoOptions();
+ dtoOptions.Fields.Remove(ItemFields.SyncInfo);
+
+ var recording = await GetRecording(recordingId, dtoOptions, CancellationToken.None).ConfigureAwait(false);
if (recording == null)
{
@@ -1449,14 +1471,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
await service.CancelSeriesTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false);
}
- public async Task<RecordingInfoDto> GetRecording(string id, CancellationToken cancellationToken, User user = null)
+ public async Task<RecordingInfoDto> GetRecording(string id, DtoOptions options, CancellationToken cancellationToken, User user = null)
{
var results = await GetRecordings(new RecordingQuery
{
UserId = user == null ? null : user.Id.ToString("N"),
Id = id
- }, cancellationToken).ConfigureAwait(false);
+ }, options, cancellationToken).ConfigureAwait(false);
return results.Items.FirstOrDefault();
}
@@ -1545,7 +1567,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
var now = DateTime.UtcNow;
- var program = _programs.Values
+ var program = GetPrograms()
.Where(i => string.Equals(externalChannelId, i.ExternalChannelId, StringComparison.OrdinalIgnoreCase))
.OrderBy(i => i.StartDate)
.SkipWhile(i => now >= (i.EndDate ?? DateTime.MinValue))
@@ -1736,11 +1758,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public async Task<QueryResult<RecordingGroupDto>> GetRecordingGroups(RecordingGroupQuery query, CancellationToken cancellationToken)
{
+ var dtoOptions = new DtoOptions();
+ dtoOptions.Fields.Remove(ItemFields.SyncInfo);
+
var recordingResult = await GetRecordings(new RecordingQuery
{
UserId = query.UserId
- }, cancellationToken).ConfigureAwait(false);
+ }, dtoOptions, cancellationToken).ConfigureAwait(false);
var recordings = recordingResult.Items;
@@ -1848,13 +1873,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public GuideInfo GetGuideInfo()
{
- var programs = _programs.ToList();
+ var programs = GetPrograms().OrderBy(i => i.StartDate).ToList();
- var startDate = _programs.Count == 0 ? DateTime.MinValue :
- programs.Select(i => i.Value.StartDate).Min();
+ var startDate = programs.Count == 0 ?
+ DateTime.MinValue :
+ programs[0].StartDate;
- var endDate = programs.Count == 0 ? DateTime.MinValue :
- programs.Select(i => i.Value.StartDate).Max();
+ var endDate = programs.Count == 0 ?
+ DateTime.MinValue :
+ programs[programs.Count - 1].StartDate;
return new GuideInfo
{
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
index d549cad46..38c93a696 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
@@ -1,6 +1,8 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Controller.MediaEncoding;
+using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
@@ -18,12 +20,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private readonly IJsonSerializer _jsonSerializer;
private readonly ILogger _logger;
private readonly IMediaSourceManager _mediaSourceManager;
+ private readonly IMediaEncoder _mediaEncoder;
- public LiveTvMediaSourceProvider(ILiveTvManager liveTvManager, IJsonSerializer jsonSerializer, ILogManager logManager, IMediaSourceManager mediaSourceManager)
+ public LiveTvMediaSourceProvider(ILiveTvManager liveTvManager, IJsonSerializer jsonSerializer, ILogManager logManager, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder)
{
_liveTvManager = liveTvManager;
_jsonSerializer = jsonSerializer;
_mediaSourceManager = mediaSourceManager;
+ _mediaEncoder = mediaEncoder;
_logger = logManager.GetLogger(GetType().Name);
}
@@ -90,14 +94,98 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public async Task<MediaSourceInfo> OpenMediaSource(string openToken, CancellationToken cancellationToken)
{
+ MediaSourceInfo stream;
+ var isAudio = false;
+
var keys = openToken.Split(new[] { '|' }, 2);
if (string.Equals(keys[0], typeof(LiveTvChannel).Name, StringComparison.OrdinalIgnoreCase))
{
- return await _liveTvManager.GetChannelStream(keys[1], cancellationToken).ConfigureAwait(false);
+ stream = await _liveTvManager.GetChannelStream(keys[1], cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ stream = await _liveTvManager.GetRecordingStream(keys[1], cancellationToken).ConfigureAwait(false);
+ }
+
+ try
+ {
+ await AddMediaInfo(stream, isAudio, cancellationToken).ConfigureAwait(false);
}
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error probing live tv stream", ex);
+ }
+
+ return stream;
+ }
- return await _liveTvManager.GetRecordingStream(keys[1], cancellationToken).ConfigureAwait(false);
+ private async Task AddMediaInfo(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
+ {
+ var originalRuntime = mediaSource.RunTimeTicks;
+
+ var info = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest
+ {
+ InputPath = mediaSource.Path,
+ Protocol = mediaSource.Protocol,
+ MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video,
+ ExtractChapters = false
+
+ }, cancellationToken).ConfigureAwait(false);
+
+ mediaSource.Bitrate = info.Bitrate;
+ mediaSource.Container = info.Container;
+ mediaSource.Formats = info.Formats;
+ mediaSource.MediaStreams = info.MediaStreams;
+ mediaSource.RunTimeTicks = info.RunTimeTicks;
+ mediaSource.Size = info.Size;
+ mediaSource.Timestamp = info.Timestamp;
+ mediaSource.Video3DFormat = info.Video3DFormat;
+ mediaSource.VideoType = info.VideoType;
+
+ mediaSource.DefaultSubtitleStreamIndex = null;
+
+ // Null this out so that it will be treated like a live stream
+ if (!originalRuntime.HasValue)
+ {
+ mediaSource.RunTimeTicks = null;
+ }
+
+ var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Audio);
+
+ if (audioStream == null || audioStream.Index == -1)
+ {
+ mediaSource.DefaultAudioStreamIndex = null;
+ }
+ else
+ {
+ mediaSource.DefaultAudioStreamIndex = audioStream.Index;
+ }
+
+ // Try to estimate this
+ if (!mediaSource.Bitrate.HasValue)
+ {
+ var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Video);
+ if (videoStream != null)
+ {
+ var width = videoStream.Width ?? 1920;
+
+ if (width >= 1900)
+ {
+ mediaSource.Bitrate = 10000000;
+ }
+
+ else if (width >= 1260)
+ {
+ mediaSource.Bitrate = 6000000;
+ }
+
+ else if (width >= 700)
+ {
+ mediaSource.Bitrate = 4000000;
+ }
+ }
+ }
}
public Task CloseMediaSource(string liveStreamId, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs
index d29b67a8a..b01dddb94 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs
@@ -12,7 +12,7 @@ using System.Threading.Tasks;
namespace MediaBrowser.Server.Implementations.LiveTv
{
- public class ProgramImageProvider : IDynamicImageProvider, IHasItemChangeMonitor
+ public class ProgramImageProvider : IDynamicImageProvider, IHasItemChangeMonitor, IHasOrder
{
private readonly ILiveTvManager _liveTvManager;
private readonly IHttpClient _httpClient;
@@ -100,7 +100,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public int Order
{
- get { return 0; }
+ get
+ {
+ // Let the better providers run first
+ return 100;
+ }
}
public bool HasChanged(IHasMetadata item, MetadataStatus status, IDirectoryService directoryService)
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json
index 856a88501..07b0022c8 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirmation",
"MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
"MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "Live TV",
"TitleSync": "Sync",
+ "ButtonDonate": "Donate",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "Notifications",
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -118,7 +123,7 @@
"LabelFree": "Free",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Select Audio",
@@ -174,6 +179,9 @@
"OptionThursday": "\u0627\u0644\u062e\u0645\u064a\u0633",
"OptionFriday": "\u0627\u0644\u062c\u0645\u0639\u0629",
"OptionSaturday": "\u0627\u0644\u0633\u0628\u062a",
+ "OptionEveryday": "Every day",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Confirm Deletion",
"MessageConfirmPathSubstitutionDeletion": "Are you sure you wish to delete this path substitution?",
"LiveTvUpdateAvailable": "(Update available)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Split Media Apart",
"MessageConfirmSplitMedia": "Are you sure you wish to split the media sources into separate items?",
"HeaderError": "Error",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Please select at least one item.",
"MessagePleaseSelectTwoItems": "Please select at least two items.",
"MessageTheFollowingItemsWillBeGrouped": "The following titles will be grouped into one item:",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/bg_BG.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/bg_BG.json
index 5b036d4d0..e7cad3695 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/bg_BG.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/bg_BG.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirmation",
"MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
"MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
+ "HeaderSupportTheTeam": "\u041f\u043e\u0434\u043a\u0440\u0435\u043f\u0435\u0442\u0435 Emby \u041e\u0442\u0431\u043e\u0440\u044a\u0442",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "\u0422V \u043d\u0430 \u0436\u0438\u0432\u043e",
"TitleSync": "Sync",
+ "ButtonDonate": "Donate",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "\u0418\u0437\u0432\u0435\u0441\u0442\u0438\u044f",
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -118,7 +123,7 @@
"LabelFree": "Free",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Select Audio",
@@ -174,6 +179,9 @@
"OptionThursday": "\u0427\u0435\u0442\u0432\u044a\u0440\u0442\u044a\u043a",
"OptionFriday": "\u041f\u0435\u0442\u044a\u043a",
"OptionSaturday": "\u0421\u044a\u0431\u043e\u0442\u0430",
+ "OptionEveryday": "Every day",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Confirm Deletion",
"MessageConfirmPathSubstitutionDeletion": "Are you sure you wish to delete this path substitution?",
"LiveTvUpdateAvailable": "(Update available)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Split Media Apart",
"MessageConfirmSplitMedia": "Are you sure you wish to split the media sources into separate items?",
"HeaderError": "Error",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Please select at least one item.",
"MessagePleaseSelectTwoItems": "Please select at least two items.",
"MessageTheFollowingItemsWillBeGrouped": "The following titles will be grouped into one item:",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json
index ecf55bdb0..335dbd3df 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirmation",
"MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
"MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "Live TV",
"TitleSync": "Sync",
+ "ButtonDonate": "Donate",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "Notifications",
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -118,7 +123,7 @@
"LabelFree": "Free",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Select Audio",
@@ -174,6 +179,9 @@
"OptionThursday": "Thursday",
"OptionFriday": "Friday",
"OptionSaturday": "Saturday",
+ "OptionEveryday": "Every day",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Confirm Deletion",
"MessageConfirmPathSubstitutionDeletion": "Are you sure you wish to delete this path substitution?",
"LiveTvUpdateAvailable": "(Update available)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Split Media Apart",
"MessageConfirmSplitMedia": "Are you sure you wish to split the media sources into separate items?",
"HeaderError": "Error",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Please select at least one item.",
"MessagePleaseSelectTwoItems": "Please select at least two items.",
"MessageTheFollowingItemsWillBeGrouped": "The following titles will be grouped into one item:",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json
index 67b9ca26f..ea141645c 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Potvrzen\u00ed",
"MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
"MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "\u017div\u00e1 TV",
"TitleSync": "Sync",
+ "ButtonDonate": "Donate",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "Notifications",
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -118,7 +123,7 @@
"LabelFree": "Free",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Select Audio",
@@ -174,6 +179,9 @@
"OptionThursday": "\u010ctvrtek",
"OptionFriday": "P\u00e1tek",
"OptionSaturday": "Sobota",
+ "OptionEveryday": "Every day",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Potvrdit smaz\u00e1n\u00ed",
"MessageConfirmPathSubstitutionDeletion": "Are you sure you wish to delete this path substitution?",
"LiveTvUpdateAvailable": "(Aktualizace dostupn\u00e1)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Split Media Apart",
"MessageConfirmSplitMedia": "Are you sure you wish to split the media sources into separate items?",
"HeaderError": "Chyba",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Please select at least one item.",
"MessagePleaseSelectTwoItems": "Please select at least two items.",
"MessageTheFollowingItemsWillBeGrouped": "The following titles will be grouped into one item:",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/da.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/da.json
index 0d4d1bbfa..f4983f8dd 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/da.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/da.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirmation",
"MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
"MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "Direkte TV",
"TitleSync": "Sync",
+ "ButtonDonate": "Donate",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "Notifications",
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -62,10 +67,10 @@
"LabelMovie": "Movie",
"LabelMusicVideo": "Music Video",
"LabelEpisode": "Episode",
- "LabelSeries": "Series",
+ "LabelSeries": "Serier",
"LabelStopping": "Stopping",
"LabelCancelled": "(cancelled)",
- "LabelFailed": "(failed)",
+ "LabelFailed": "(fejlede)",
"ButtonHelp": "Help",
"ButtonSave": "Gem",
"ButtonDownload": "Download",
@@ -79,8 +84,8 @@
"SyncJobStatusCompletedWithError": "Synced with errors",
"SyncJobItemStatusReadyToTransfer": "Ready to Transfer",
"LabelCollection": "Collection",
- "HeaderAddToCollection": "Add to Collection",
- "NewCollectionNameExample": "Example: Star Wars Collection",
+ "HeaderAddToCollection": "Tilf\u00f8j til samling",
+ "NewCollectionNameExample": "Eksempel: Star Wars Collection",
"OptionSearchForInternetMetadata": "Search the internet for artwork and metadata",
"LabelSelectCollection": "Select collection:",
"HeaderDevices": "Devices",
@@ -118,7 +123,7 @@
"LabelFree": "Free",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Select Audio",
@@ -138,7 +143,7 @@
"ButtonPlay": "Afspil",
"ButtonEdit": "Rediger",
"ButtonQueue": "Queue",
- "ButtonPlayTrailer": "Play trailer",
+ "ButtonPlayTrailer": "Afspil trailer",
"ButtonPlaylist": "Playlist",
"ButtonPreviousTrack": "Previous Track",
"LabelEnabled": "Enabled",
@@ -174,6 +179,9 @@
"OptionThursday": "Torsdag",
"OptionFriday": "Fredag",
"OptionSaturday": "L\u00f8rdag",
+ "OptionEveryday": "Every day",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Confirm Deletion",
"MessageConfirmPathSubstitutionDeletion": "Are you sure you wish to delete this path substitution?",
"LiveTvUpdateAvailable": "(Update available)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Split Media Apart",
"MessageConfirmSplitMedia": "Are you sure you wish to split the media sources into separate items?",
"HeaderError": "Error",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Please select at least one item.",
"MessagePleaseSelectTwoItems": "Please select at least two items.",
"MessageTheFollowingItemsWillBeGrouped": "The following titles will be grouped into one item:",
@@ -394,7 +403,7 @@
"TabAdvanced": "Advanceret",
"TabHelp": "Help",
"TabScheduledTasks": "Scheduled Tasks",
- "ButtonFullscreen": "Fullscreen",
+ "ButtonFullscreen": "Fuld sk\u00e6rm",
"ButtonAudioTracks": "Audio Tracks",
"ButtonSubtitles": "Undertekster",
"ButtonScenes": "Scener",
@@ -467,7 +476,7 @@
"PersonTypePerson": "Person",
"LabelTitleDisplayOrder": "Title display order:",
"OptionSortName": "Sort name",
- "OptionReleaseDate": "Release date",
+ "OptionReleaseDate": "Udgivelsesdato",
"LabelSeasonNumber": "Season number:",
"LabelDiscNumber": "Disc number",
"LabelParentNumber": "Parent number",
@@ -496,14 +505,14 @@
"LabelContentTypeValue": "Content type: {0}",
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
"FolderTypeUnset": "Unset (mixed content)",
- "FolderTypeMovies": "Movies",
- "FolderTypeMusic": "Music",
- "FolderTypeAdultVideos": "Adult videos",
- "FolderTypePhotos": "Photos",
- "FolderTypeMusicVideos": "Music videos",
- "FolderTypeHomeVideos": "Home videos",
- "FolderTypeGames": "Games",
- "FolderTypeBooks": "Books",
+ "FolderTypeMovies": "FIlm",
+ "FolderTypeMusic": "Musik",
+ "FolderTypeAdultVideos": "Voksenfilm",
+ "FolderTypePhotos": "Fotos",
+ "FolderTypeMusicVideos": "Musikvideoer",
+ "FolderTypeHomeVideos": "Hjemmevideoer",
+ "FolderTypeGames": "Spil",
+ "FolderTypeBooks": "B\u00f8ger",
"FolderTypeTvShows": "TV",
"TabMovies": "Film",
"TabSeries": "Serier",
@@ -611,7 +620,7 @@
"HeaderAlbums": "Albums",
"HeaderGames": "Games",
"HeaderBooks": "Books",
- "HeaderEpisodes": "Episodes",
+ "HeaderEpisodes": "Afsnit",
"HeaderSeasons": "Seasons",
"HeaderTracks": "Tracks",
"HeaderItems": "Items",
@@ -649,7 +658,7 @@
"MediaInfoStreamTypeEmbeddedImage": "Embedded Image",
"MediaInfoRefFrames": "Ref frames",
"TabPlayback": "Playback",
- "TabNotifications": "Notifications",
+ "TabNotifications": "Notifikationer",
"TabExpert": "Expert",
"HeaderSelectCustomIntrosPath": "Select Custom Intros Path",
"HeaderRateAndReview": "Rate and Review",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/de.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/de.json
index 9431bf07f..1a68eed35 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/de.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/de.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Best\u00e4tigung",
"MessageKeyUpdated": "Danke. Dein Unterst\u00fctzerschl\u00fcssel wurde aktualisiert.",
"MessageKeyRemoved": "Danke. Ihr Unterst\u00fctzerschl\u00fcssel wurde entfernt.",
+ "HeaderSupportTheTeam": "Unterst\u00fctzen Sie das Emby Team",
+ "TextEnjoyBonusFeatures": "Erleben Sie Bonus Funktionen",
"TitleLiveTV": "Live-TV",
"TitleSync": "Synchronisation",
+ "ButtonDonate": "Spenden",
+ "HeaderMyMedia": "Meine Medien",
+ "TitleNotifications": "Benachrichtigungen",
"ErrorLaunchingChromecast": "W\u00e4hrend des startens von Chromecast ist ein Fehler aufgetreten. Bitte stelle sicher, dass dein Ger\u00e4te mit dem WLAN verbunden ist.",
"MessageErrorLoadingSupporterInfo": "Es trat ein Fehler beim laden der Unterst\u00fctzer-Informationen auf. Bitte versuchen Sie es sp\u00e4ter erneut.",
"MessageLinkYourSupporterKey": "Verbinden Sie Ihren Unterst\u00fctzer-Schl\u00fcssel mit bis zu {0} Emby Connect Benutzern um kostenfreien Zugriff auf die folgenden Apps zu erhalten:",
@@ -120,7 +125,7 @@
"MessagePlaybackErrorNotAllowed": "Sie sind nicht befugt diese Inhalte wiederzugeben. Bitte kontaktieren Sie Ihren Systemadministrator f\u00fcr weitere Details.",
"MessagePlaybackErrorNoCompatibleStream": "Es sind aktuell keine kompatiblen Streams verf\u00fcgbar. Bitte versuchen Sie es sp\u00e4ter erneut.",
"MessagePlaybackErrorRateLimitExceeded": "Ihr Wiedergabelimit wurde \u00fcberschritten. Bitte kontaktieren Sie Ihren Systemadministrator f\u00fcr weitere Details.",
- "MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
+ "MessagePlaybackErrorPlaceHolder": "Der gew\u00e4hlte Inhalt kann auf diesem Ger\u00e4t nicht abgespielt werden.",
"HeaderSelectAudio": "W\u00e4hle Audio",
"HeaderSelectSubtitles": "W\u00f6hle Untertitel",
"ButtonMarkForRemoval": "Entferne von Ger\u00e4t",
@@ -174,6 +179,9 @@
"OptionThursday": "Donnerstag",
"OptionFriday": "Freitag",
"OptionSaturday": "Samstag",
+ "OptionEveryday": "T\u00e4glich",
+ "OptionWeekend": "Wochenenden",
+ "OptionWeekday": "Wochentage",
"HeaderConfirmDeletion": "Best\u00e4tige L\u00f6schung",
"MessageConfirmPathSubstitutionDeletion": "Bist du dir sicher die Pfadsubstitution l\u00f6schen zu wollen?",
"LiveTvUpdateAvailable": "(Update verf\u00fcgbar)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Trenne Medien ab",
"MessageConfirmSplitMedia": "Bist du dir sicher, dass du die Medienquellen in separate Elemente aufteilen m\u00f6chtest?",
"HeaderError": "Fehler",
+ "MessageChromecastConnectionError": "Ihr Chromecast kann keine Verbindung mit dem Emby Server herstellen. Bitte \u00fcberpr\u00fcfen Sie die Verbindung und probieren Sie es erneut.",
"MessagePleaseSelectOneItem": "Bitte w\u00e4hle mindestens eine Option aus.",
"MessagePleaseSelectTwoItems": "Bitte w\u00e4hle mindestens zwei Optionen aus.",
"MessageTheFollowingItemsWillBeGrouped": "Die folgenden Titel werden zu einem Element gruppiert:",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/el.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/el.json
index 336e311e6..70fdf8e25 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/el.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/el.json
@@ -23,8 +23,8 @@
"PasswordSaved": "\u039f \u03ba\u03c9\u03b4\u03b9\u03ba\u03cc\u03c2 \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7\u03c2 \u03b1\u03c0\u03bf\u03b8\u03b7\u03ba\u03b5\u03cd\u03c4\u03b7\u03ba\u03b5",
"PasswordMatchError": "\u039f \u03ba\u03c9\u03b4\u03b9\u03ba\u03cc\u03c2 \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7\u03c2 \u03ba\u03b1\u03b9 \u03c4\u03bf\u03bd \u03ba\u03c9\u03b4\u03b9\u03ba\u03cc \u03b5\u03c0\u03b9\u03b2\u03b5\u03b2\u03b1\u03af\u03c9\u03c3\u03b7\u03c2 \u03c0\u03c1\u03ad\u03c0\u03b5\u03b9 \u03bd\u03b1 \u03c4\u03b1\u03b9\u03c1\u03b9\u03ac\u03b6\u03bf\u03c5\u03bd",
"OptionRelease": "\u0397 \u03b5\u03c0\u03af\u03c3\u03b7\u03bc\u03b7 \u03ad\u03ba\u03b4\u03bf\u03c3\u03b7",
- "OptionBeta": "\u03b2\u03ae\u03c4\u03b1",
- "OptionDev": "\u03b1\u03bd\u03ac\u03c0\u03c4\u03c5\u03be\u03b7 (\u03b1\u03c3\u03c4\u03b1\u03b8\u03ae\u03c2)",
+ "OptionBeta": "\u0394\u03bf\u03ba\u03b9\u03bc\u03b1\u03c3\u03c4\u03b9\u03ba\u03ae",
+ "OptionDev": "\u0391\u03bd\u03ac\u03c0\u03c4\u03c5\u03be\u03b7 (\u03b1\u03c3\u03c4\u03b1\u03b8\u03ae\u03c2)",
"UninstallPluginHeader": "\u03b1\u03c0\u03b5\u03b3\u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b7\u03c3\u03b5\u03c4\u03b5 \u03c4\u03bf plugin",
"UninstallPluginConfirmation": "\u0395\u03af\u03c3\u03c4\u03b5 \u03c3\u03af\u03b3\u03bf\u03c5\u03c1\u03bf\u03b9 \u03cc\u03c4\u03b9 \u03b8\u03ad\u03bb\u03b5\u03c4\u03b5 \u03bd\u03b1 \u03b1\u03c0\u03b5\u03b3\u03ba\u03b1\u03c4\u03b1\u03c3\u03c4\u03ae\u03c3\u03b5\u03c4\u03b5;",
"NoPluginConfigurationMessage": "\u0391\u03c5\u03c4\u03cc \u03c4\u03bf plugin \u03ad\u03c7\u03b5\u03b9 \u03c4\u03af\u03c0\u03bf\u03c4\u03b1 \u03bd\u03b1 \u03b4\u03b9\u03b1\u03bc\u03bf\u03c1\u03c6\u03ce\u03c3\u03b5\u03c4\u03b5",
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirmation",
"MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
"MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "Live TV",
"TitleSync": "Sync",
+ "ButtonDonate": "Donate",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "\u0395\u03b9\u03b4\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03b5\u03b9\u03c2",
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -62,12 +67,12 @@
"LabelMovie": "Movie",
"LabelMusicVideo": "Music Video",
"LabelEpisode": "Episode",
- "LabelSeries": "Series",
+ "LabelSeries": "\u03a3\u03b5\u03b9\u03c1\u03ad\u03c2",
"LabelStopping": "Stopping",
"LabelCancelled": "(cancelled)",
- "LabelFailed": "(failed)",
- "ButtonHelp": "Help",
- "ButtonSave": "\u0391\u03c0\u03bf\u03b8\u03b7\u03ba\u03b5\u03cd\u03c3\u03c4\u03b5",
+ "LabelFailed": "\u0391\u03c0\u03bf\u03c4\u03c5\u03c7\u03af\u03b1",
+ "ButtonHelp": "\u0392\u03bf\u03ae\u03b8\u03b5\u03b9\u03b1",
+ "ButtonSave": "\u0391\u03c0\u03bf\u03b8\u03ae\u03ba\u03b5\u03c5\u03c3\u03b7",
"ButtonDownload": "Download",
"SyncJobStatusQueued": "Queued",
"SyncJobStatusConverting": "Converting",
@@ -79,10 +84,10 @@
"SyncJobStatusCompletedWithError": "Synced with errors",
"SyncJobItemStatusReadyToTransfer": "Ready to Transfer",
"LabelCollection": "Collection",
- "HeaderAddToCollection": "Add to Collection",
- "NewCollectionNameExample": "Example: Star Wars Collection",
- "OptionSearchForInternetMetadata": "Search the internet for artwork and metadata",
- "LabelSelectCollection": "Select collection:",
+ "HeaderAddToCollection": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c3\u03b5 \u03c3\u03c4\u03b7\u03bd \u03a3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ae",
+ "NewCollectionNameExample": "\u03a0\u03b1\u03c1\u03ac\u03b4\u03b5\u03b9\u03b3\u03bc\u03b1: \u03a3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ae \"\u03a0\u03cc\u03bb\u03b5\u03bc\u03bf\u03c2 \u03c4\u03c9\u03bd \u0386\u03c3\u03c4\u03c1\u03c9\u03bd\"",
+ "OptionSearchForInternetMetadata": "\u0391\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7 \u03c3\u03c4\u03bf \u03b4\u03b9\u03b1\u03b4\u03af\u03ba\u03c4\u03c5\u03bf \u03b3\u03b9\u03b1 \u03b5\u03be\u03ce\u03c6\u03c5\u03bb\u03bb\u03bf \u03ba\u03b1\u03b9 \u03c0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b5\u03c2",
+ "LabelSelectCollection": "\u0395\u03c0\u03ad\u03bb\u03b5\u03be\u03b5 \u03c3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ae:",
"HeaderDevices": "Devices",
"ButtonScheduledTasks": "Scheduled tasks",
"MessageItemsAdded": "Items added",
@@ -93,14 +98,14 @@
"LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
"HeaderWelcomeToProjectServerDashboard": "Welcome to the Emby Server Dashboard",
"HeaderWelcomeToProjectWebClient": "Welcome to the Emby Web Client",
- "ButtonTakeTheTour": "Take the tour",
+ "ButtonTakeTheTour": "\u039a\u03ac\u03bd\u03c4\u03b5 \u03c4\u03b7\u03bd \u039e\u03b5\u03bd\u03ac\u03b3\u03b7\u03c3\u03b7",
"HeaderWelcomeBack": "Welcome back!",
- "TitlePlugins": "Plugins",
+ "TitlePlugins": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c4\u03b1",
"ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
"MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
"HeaderLibraryAccess": "Library Access",
"HeaderChannelAccess": "Channel Access",
- "HeaderDeviceAccess": "Device Access",
+ "HeaderDeviceAccess": "\u03a0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7 \u03a3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae\u03c2",
"HeaderSelectDevices": "Select Devices",
"ButtonCancelItem": "Cancel item",
"ButtonQueueForRetry": "Queue for retry",
@@ -118,7 +123,7 @@
"LabelFree": "Free",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Select Audio",
@@ -133,14 +138,14 @@
"ButtonMute": "Mute",
"ButtonUnmute": "Unmute",
"ButtonStop": "Stop",
- "ButtonNextTrack": "Next Track",
+ "ButtonNextTrack": "\u0395\u03c0\u03cc\u03bc\u03b5\u03bd\u03bf \u039a\u03bf\u03bc\u03bc\u03ac\u03c4\u03b9",
"ButtonPause": "Pause",
"ButtonPlay": "Play",
"ButtonEdit": "Edit",
"ButtonQueue": "Queue",
- "ButtonPlayTrailer": "Play trailer",
+ "ButtonPlayTrailer": "\u0391\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae trailer",
"ButtonPlaylist": "Playlist",
- "ButtonPreviousTrack": "Previous Track",
+ "ButtonPreviousTrack": "\u03a0\u03c1\u03bf\u03b7\u03b3\u03bf\u03cd\u03bc\u03b5\u03bd\u03bf \u039a\u03bf\u03bc\u03bc\u03ac\u03c4\u03b9",
"LabelEnabled": "Enabled",
"LabelDisabled": "Disabled",
"ButtonMoreInformation": "More Information",
@@ -174,6 +179,9 @@
"OptionThursday": "Thursday",
"OptionFriday": "Friday",
"OptionSaturday": "Saturday",
+ "OptionEveryday": "Every day",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Confirm Deletion",
"MessageConfirmPathSubstitutionDeletion": "Are you sure you wish to delete this path substitution?",
"LiveTvUpdateAvailable": "(Update available)",
@@ -191,11 +199,12 @@
"HeaderSplitMedia": "Split Media Apart",
"MessageConfirmSplitMedia": "Are you sure you wish to split the media sources into separate items?",
"HeaderError": "Error",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Please select at least one item.",
"MessagePleaseSelectTwoItems": "Please select at least two items.",
"MessageTheFollowingItemsWillBeGrouped": "The following titles will be grouped into one item:",
"MessageConfirmItemGrouping": "Emby apps will automatically choose the optimal version to play based on device and network performance. Are you sure you wish to continue?",
- "HeaderResume": "\u03a3\u03c5\u03bd\u03b5\u03c7\u03af\u03c3\u03b5\u03b9 ",
+ "HeaderResume": "\u0395\u03c0\u03b1\u03bd\u03b5\u03ba\u03ba\u03af\u03bd\u03b7\u03c3\u03b7",
"HeaderMyViews": "My Views",
"HeaderLibraryFolders": "Media Folders",
"HeaderLatestMedia": "Latest Media",
@@ -219,7 +228,7 @@
"HeaderSelectChannelDownloadPath": "Select Channel Download Path",
"HeaderSelectChannelDownloadPathHelp": "Browse or enter the path to use for storing channel cache files. The folder must be writeable.",
"OptionNewCollection": "New...",
- "ButtonAdd": "Add",
+ "ButtonAdd": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c3\u03b5",
"ButtonRemove": "Remove",
"LabelChapterDownloaders": "Chapter downloaders:",
"LabelChapterDownloadersHelp": "Enable and rank your preferred chapter downloaders in order of priority. Lower priority downloaders will only be used to fill in missing information.",
@@ -266,7 +275,7 @@
"MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?",
"ButtonRemoteControl": "Remote Control",
"HeaderLatestTvRecordings": "Latest Recordings",
- "ButtonOk": "\u03b5\u03bd\u03c4\u03ac\u03be\u03b5\u03b9",
+ "ButtonOk": "\u0395\u03bd\u03c4\u03ac\u03be\u03b5\u03b9",
"ButtonCancel": "\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7 ",
"ButtonRefresh": "Refresh",
"LabelCurrentPath": "Current path:",
@@ -280,7 +289,7 @@
"ButtonShuffle": "Shuffle",
"ButtonInstantMix": "Instant mix",
"ButtonResume": "Resume",
- "HeaderScenes": "Scenes",
+ "HeaderScenes": "\u03a3\u03ba\u03b7\u03bd\u03ad\u03c2",
"HeaderAudioTracks": "Audio Tracks",
"HeaderLibraries": "Libraries",
"HeaderSubtitles": "Subtitles",
@@ -298,8 +307,8 @@
"HeaderArtist": "Artist",
"LabelAddedOnDate": "Added {0}",
"ButtonStart": "Start",
- "HeaderChannels": "Channels",
- "HeaderMediaFolders": "Media Folders",
+ "HeaderChannels": "\u039a\u03b1\u03bd\u03ac\u03bb\u03b9\u03b1",
+ "HeaderMediaFolders": "\u03a6\u03ac\u03ba\u03b5\u03bb\u03bf\u03b9 \u03a0\u03bf\u03bb\u03c5\u03bc\u03ad\u03c3\u03c9\u03bd",
"HeaderBlockItemsWithNoRating": "Block content with no rating information:",
"OptionBlockOthers": "Others",
"OptionBlockTvShows": "TV Shows",
@@ -383,7 +392,7 @@
"LabelPackageInstallCompleted": "{0} installation completed.",
"LabelPackageInstallFailed": "{0} installation failed.",
"LabelPackageInstallCancelled": "{0} installation cancelled.",
- "TabServer": "Server",
+ "TabServer": "\u0394\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae\u03c2",
"TabUsers": "Users",
"TabLibrary": "Library",
"TabMetadata": "Metadata",
@@ -394,20 +403,20 @@
"TabAdvanced": "Advanced",
"TabHelp": "Help",
"TabScheduledTasks": "Scheduled Tasks",
- "ButtonFullscreen": "Fullscreen",
- "ButtonAudioTracks": "Audio Tracks",
+ "ButtonFullscreen": "\u039f\u03bb\u03cc\u03ba\u03bb\u03b7\u03c1\u03b7 \u03bf\u03b8\u03cc\u03bd\u03b7",
+ "ButtonAudioTracks": "\u0397\u03c7\u03b7\u03c4\u03b9\u03ba\u03ac \u039a\u03cc\u03bc\u03bc\u03ac\u03c4\u03b9\u03b1",
"ButtonSubtitles": "Subtitles",
"ButtonScenes": "Scenes",
"ButtonQuality": "Quality",
"HeaderNotifications": "Notifications",
"HeaderSelectPlayer": "Select Player:",
- "ButtonSelect": "Select",
- "ButtonNew": "New",
+ "ButtonSelect": "\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae",
+ "ButtonNew": "\u039d\u03ad\u03bf",
"MessageInternetExplorerWebm": "For best results with Internet Explorer please install the WebM playback plugin.",
"HeaderVideoError": "Video Error",
"ButtonAddToPlaylist": "Add to playlist",
"HeaderAddToPlaylist": "Add to Playlist",
- "LabelName": "Name:",
+ "LabelName": "\u038c\u03bd\u03bf\u03bc\u03b1:",
"ButtonSubmit": "Submit",
"LabelSelectPlaylist": "Playlist:",
"OptionNewPlaylist": "New playlist...",
@@ -418,9 +427,9 @@
"ButtonRemoveFromPlaylist": "Remove from playlist",
"HeaderSpecials": "Specials",
"HeaderTrailers": "Trailers",
- "HeaderAudio": "Audio",
+ "HeaderAudio": "\u0389\u03c7\u03bf\u03c2",
"HeaderResolution": "Resolution",
- "HeaderVideo": "Video",
+ "HeaderVideo": "\u0392\u03af\u03bd\u03c4\u03b5\u03bf",
"HeaderRuntime": "Runtime",
"HeaderCommunityRating": "Community rating",
"HeaderParentalRating": "Parental rating",
@@ -436,11 +445,11 @@
"HeaderEmbeddedImage": "Embedded image",
"HeaderTrack": "Track",
"HeaderDisc": "Disc",
- "OptionMovies": "Movies",
+ "OptionMovies": "\u03a4\u03b1\u03b9\u03bd\u03af\u03b5\u03c2",
"OptionCollections": "Collections",
"OptionSeries": "Series",
"OptionSeasons": "Seasons",
- "OptionEpisodes": "Episodes",
+ "OptionEpisodes": "\u0395\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1",
"OptionGames": "Games",
"OptionGameSystems": "Game systems",
"OptionMusicArtists": "Music artists",
@@ -467,7 +476,7 @@
"PersonTypePerson": "Person",
"LabelTitleDisplayOrder": "Title display order:",
"OptionSortName": "Sort name",
- "OptionReleaseDate": "Release date",
+ "OptionReleaseDate": "\u03a0\u03c1\u03ce\u03c4\u03b7 \u03a0\u03c1\u03bf\u03b2\u03bf\u03bb\u03ae",
"LabelSeasonNumber": "Season number:",
"LabelDiscNumber": "Disc number",
"LabelParentNumber": "Parent number",
@@ -496,22 +505,22 @@
"LabelContentTypeValue": "Content type: {0}",
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
"FolderTypeUnset": "Unset (mixed content)",
- "FolderTypeMovies": "Movies",
- "FolderTypeMusic": "Music",
- "FolderTypeAdultVideos": "Adult videos",
- "FolderTypePhotos": "Photos",
- "FolderTypeMusicVideos": "Music videos",
- "FolderTypeHomeVideos": "Home videos",
- "FolderTypeGames": "Games",
- "FolderTypeBooks": "Books",
- "FolderTypeTvShows": "TV",
- "TabMovies": "Movies",
+ "FolderTypeMovies": "\u03a4\u03b1\u03b9\u03bd\u03af\u03b5\u03c2",
+ "FolderTypeMusic": "\u039c\u03bf\u03c5\u03c3\u03b9\u03ba\u03ae",
+ "FolderTypeAdultVideos": "\u03a4\u03b1\u03b9\u03bd\u03af\u03b5\u03c2 \u0395\u03bd\u03b7\u03bb\u03af\u03ba\u03c9\u03bd",
+ "FolderTypePhotos": "\u03a6\u03c9\u03c4\u03bf\u03b3\u03c1\u03b1\u03c6\u03af\u03b5\u03c2",
+ "FolderTypeMusicVideos": "\u039c\u03bf\u03c5\u03c3\u03b9\u03ba\u03ac \u0392\u03af\u03bd\u03c4\u03b5\u03bf",
+ "FolderTypeHomeVideos": "\u03a0\u03c1\u03bf\u03c3\u03c9\u03c0\u03b9\u03ba\u03ac \u0392\u03af\u03bd\u03c4\u03b5\u03bf",
+ "FolderTypeGames": "\u03a0\u03b1\u03b9\u03c7\u03bd\u03af\u03b4\u03b9\u03b1",
+ "FolderTypeBooks": "\u0392\u03b9\u03b2\u03bb\u03af\u03b1",
+ "FolderTypeTvShows": "\u03a4\u03b7\u03bb\u03b5\u03cc\u03c1\u03b1\u03c3\u03b7",
+ "TabMovies": "\u03a4\u03b1\u03b9\u03bd\u03af\u03b5\u03c2",
"TabSeries": "Series",
"TabEpisodes": "\u0395\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1",
"TabTrailers": "Trailers",
- "TabGames": "Games",
- "TabAlbums": "\u03ac\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc",
- "TabSongs": "\u03c4\u03c1\u03b1\u03b3\u03bf\u03cd\u03b4\u03b9\u03b1",
+ "TabGames": "\u03a0\u03b1\u03b9\u03c7\u03bd\u03af\u03b4\u03b9\u03b1",
+ "TabAlbums": "\u0386\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc",
+ "TabSongs": "\u03a4\u03c1\u03b1\u03b3\u03bf\u03cd\u03b4\u03b9\u03b1",
"TabMusicVideos": "\u039c\u03bf\u03c5\u03c3\u03b9\u03ba\u03ac \u03b2\u03af\u03bd\u03c4\u03b5\u03bf",
"BirthPlaceValue": "Birth place: {0}",
"DeathDateValue": "Died: {0}",
@@ -611,7 +620,7 @@
"HeaderAlbums": "Albums",
"HeaderGames": "Games",
"HeaderBooks": "Books",
- "HeaderEpisodes": "Episodes",
+ "HeaderEpisodes": "\u0395\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1",
"HeaderSeasons": "Seasons",
"HeaderTracks": "Tracks",
"HeaderItems": "Items",
@@ -649,7 +658,7 @@
"MediaInfoStreamTypeEmbeddedImage": "Embedded Image",
"MediaInfoRefFrames": "Ref frames",
"TabPlayback": "Playback",
- "TabNotifications": "Notifications",
+ "TabNotifications": "\u0395\u03b9\u03b4\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03b5\u03b9\u03c2",
"TabExpert": "Expert",
"HeaderSelectCustomIntrosPath": "Select Custom Intros Path",
"HeaderRateAndReview": "Rate and Review",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json
index e6509b9da..b18eb9d40 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirmation",
"MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
"MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "Live TV",
"TitleSync": "Sync",
+ "ButtonDonate": "Donate",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "Notifications",
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -118,7 +123,7 @@
"LabelFree": "Free",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Select Audio",
@@ -174,6 +179,9 @@
"OptionThursday": "Thursday",
"OptionFriday": "Friday",
"OptionSaturday": "Saturday",
+ "OptionEveryday": "Every day",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Confirm Deletion",
"MessageConfirmPathSubstitutionDeletion": "Are you sure you wish to delete this path substitution?",
"LiveTvUpdateAvailable": "(Update available)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Split Media Apart",
"MessageConfirmSplitMedia": "Are you sure you wish to split the media sources into separate items?",
"HeaderError": "Error",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Please select at least one item.",
"MessagePleaseSelectTwoItems": "Please select at least two items.",
"MessageTheFollowingItemsWillBeGrouped": "The following titles will be grouped into one item:",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json
index bc6c5aaf1..227de4f26 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirmation",
"MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
"MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "Live TV",
"TitleSync": "Sync",
+ "ButtonDonate": "Donate",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "Notifications",
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -118,7 +123,7 @@
"LabelFree": "Free",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Select Audio",
@@ -174,6 +179,9 @@
"OptionThursday": "Thursday",
"OptionFriday": "Friday",
"OptionSaturday": "Saturday",
+ "OptionEveryday": "Every day",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Confirm Deletion",
"MessageConfirmPathSubstitutionDeletion": "Are you sure you wish to delete this path substitution?",
"LiveTvUpdateAvailable": "(Update available)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Split Media Apart",
"MessageConfirmSplitMedia": "Are you sure you wish to split the media sources into separate items?",
"HeaderError": "Error",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Please select at least one item.",
"MessagePleaseSelectTwoItems": "Please select at least two items.",
"MessageTheFollowingItemsWillBeGrouped": "The following titles will be grouped into one item:",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/es.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/es.json
index 981286e12..9568be9b3 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/es.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/es.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirmaci\u00f3n",
"MessageKeyUpdated": "Gracias. Su clave de seguidor ha sido actualizada.",
"MessageKeyRemoved": "Gracias. Su clave de seguidor ha sido eliminada.",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "Tv en vivo",
"TitleSync": "Sync",
+ "ButtonDonate": "Donate",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "Notifications",
"ErrorLaunchingChromecast": "Ha habido un error al lanzar chromecast. Asegurese que su dispositivo est\u00e1 conectado a su red inal\u00e1mbrica.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -118,7 +123,7 @@
"LabelFree": "Libre",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Seleccionar Audio",
@@ -174,6 +179,9 @@
"OptionThursday": "Jueves",
"OptionFriday": "Viernes",
"OptionSaturday": "S\u00e1bado",
+ "OptionEveryday": "Every day",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Confirmar borrado",
"MessageConfirmPathSubstitutionDeletion": "\u00bfEst\u00e1 seguro que desea borrar esta ruta de sustituci\u00f3n?",
"LiveTvUpdateAvailable": "(Actualizaci\u00f3n disponible)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Divisi\u00f3n de medios",
"MessageConfirmSplitMedia": "\u00bfEst\u00e1 seguro que desea dividir los medios en partes separadas?",
"HeaderError": "Error",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Seleccione al menos un elemento.",
"MessagePleaseSelectTwoItems": "Seleccione al menos dos elementos.",
"MessageTheFollowingItemsWillBeGrouped": "Los siguientes t\u00edtulos se agrupar\u00e1n en un elemento.",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json
index b0700c49c..f6d81354f 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirmaci\u00f3n",
"MessageKeyUpdated": "Gracias. Su clave de aficionado ha sido actualizada.",
"MessageKeyRemoved": "Gracias. Su clave de aficionado ha sido eliminada.",
+ "HeaderSupportTheTeam": "Apoye al equipo de Emby",
+ "TextEnjoyBonusFeatures": "Disfruta de Caracter\u00edsticas Premium",
"TitleLiveTV": "TV en Vivo",
"TitleSync": "Sinc",
+ "ButtonDonate": "Donar",
+ "HeaderMyMedia": "Mis Medios",
+ "TitleNotifications": "Notificaciones",
"ErrorLaunchingChromecast": "Hubo un error iniciando chromecast. Por favor aseg\u00farate de que tu dispositivo este conectado a tu red inalambrica",
"MessageErrorLoadingSupporterInfo": "Se present\u00f3 un error al cargar la informaci\u00f3n del aficionado. Por favor int\u00e9ntelo m\u00e1s tarde.",
"MessageLinkYourSupporterKey": "Enlaza tu clave de aficionado con hasta {0} miembros de Emby Connect para disfrutar de acceso gratuito a la siguientes aplicaciones:",
@@ -118,9 +123,9 @@
"LabelFree": "Gratis",
"HeaderPlaybackError": "Error de Reproducci\u00f3n",
"MessagePlaybackErrorNotAllowed": "Actualmente no esta autorizado para reproducir este contenido. Por favor contacte a su administrador de sistema para mas informaci\u00f3n.",
- "MessagePlaybackErrorNoCompatibleStream": "No hay streams compatibles en este en este momento. Por favor intente de nuevo mas tarde.",
+ "MessagePlaybackErrorNoCompatibleStream": "No hay streams compatibles en este en este momento. Por favor intente de nuevo mas tarde o contacte a su administrador de sistema para mas detalles.",
"MessagePlaybackErrorRateLimitExceeded": "Su limite de transferencia ha sido excedido. Por favor contacte a su administrador de sistema para mas informaci\u00f3n.",
- "MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
+ "MessagePlaybackErrorPlaceHolder": "No es posible reproducir el contenido seleccionado en este dispositivo.",
"HeaderSelectAudio": "Seleccionar Audio",
"HeaderSelectSubtitles": "Seleccionar Subtitulos",
"ButtonMarkForRemoval": "Remover de dispositivo",
@@ -138,7 +143,7 @@
"ButtonPlay": "Reproducir",
"ButtonEdit": "Editar",
"ButtonQueue": "A cola",
- "ButtonPlayTrailer": "Reproducir avance",
+ "ButtonPlayTrailer": "Reproducir trailer",
"ButtonPlaylist": "Lista de Reprod.",
"ButtonPreviousTrack": "Pista Anterior",
"LabelEnabled": "Habilitado",
@@ -174,6 +179,9 @@
"OptionThursday": "Jueves",
"OptionFriday": "Viernes",
"OptionSaturday": "S\u00e1bado",
+ "OptionEveryday": "Todos los d\u00edas",
+ "OptionWeekend": "Fines de Semana",
+ "OptionWeekday": "D\u00edas de semana",
"HeaderConfirmDeletion": "Confirmar Eliminaci\u00f3n",
"MessageConfirmPathSubstitutionDeletion": "\u00bfEst\u00e1 seguro de querer eliminar esta ruta alternativa?",
"LiveTvUpdateAvailable": "(Actualizaci\u00f3n disponible)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Dividir y Separar Medios",
"MessageConfirmSplitMedia": "\u00bfEst\u00e1 seguro de querer dividir y separar estos medios en elementos individuales?",
"HeaderError": "Error",
+ "MessageChromecastConnectionError": "Su receptor Chromecast no puede conectarse con su Servidor Emby. Por favor revise las conexiones e intent\u00e9lo nuevamente.",
"MessagePleaseSelectOneItem": "Por favor selecciona al menos un elemento.",
"MessagePleaseSelectTwoItems": "Por favor selecciona al menos dos elementos.",
"MessageTheFollowingItemsWillBeGrouped": "Los siguientes t\u00edtulos ser\u00e1n agrupados en un solo elemento.",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/fi.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/fi.json
index 7fcd26b32..f980dda8f 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/fi.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/fi.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirmation",
"MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
"MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "Live TV",
"TitleSync": "Sync",
+ "ButtonDonate": "Donate",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "Notifications",
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -118,7 +123,7 @@
"LabelFree": "Free",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Select Audio",
@@ -174,6 +179,9 @@
"OptionThursday": "Thursday",
"OptionFriday": "Friday",
"OptionSaturday": "Saturday",
+ "OptionEveryday": "Every day",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Confirm Deletion",
"MessageConfirmPathSubstitutionDeletion": "Are you sure you wish to delete this path substitution?",
"LiveTvUpdateAvailable": "(Update available)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Split Media Apart",
"MessageConfirmSplitMedia": "Are you sure you wish to split the media sources into separate items?",
"HeaderError": "Error",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Please select at least one item.",
"MessagePleaseSelectTwoItems": "Please select at least two items.",
"MessageTheFollowingItemsWillBeGrouped": "The following titles will be grouped into one item:",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json
index 48b51da03..2e4c48473 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirmation",
"MessageKeyUpdated": "Merci. Votre cl\u00e9 de supporteur a \u00e9t\u00e9 mise \u00e0 jour.",
"MessageKeyRemoved": "Merci. Votre cl\u00e9 de supporteur a \u00e9t\u00e9 supprim\u00e9e.",
+ "HeaderSupportTheTeam": "Aidez l'\u00e9quipe Emby",
+ "TextEnjoyBonusFeatures": "Profitez bien des fonctionnalit\u00e9s bonus",
"TitleLiveTV": "TV en direct",
"TitleSync": "Sync.",
+ "ButtonDonate": "Faire un don",
+ "HeaderMyMedia": "Mes medias",
+ "TitleNotifications": "Notifications",
"ErrorLaunchingChromecast": "Une erreur a \u00e9t\u00e9 rencontr\u00e9e lors du lancement de Chromecast. Veuillez vous assurer que votre appareil est bien connect\u00e9 \u00e0 votre r\u00e9seau sans-fil.",
"MessageErrorLoadingSupporterInfo": "Il y a eu une erreur lors du chargement des informations de supporter. Veuillez r\u00e9essayer plus tard.",
"MessageLinkYourSupporterKey": "Liez votre cl\u00e9 de supporteur avec un maximum de {0} membres Emby Connect pour b\u00e9n\u00e9ficier de l'acc\u00e8s gratuit aux applications suivantes :",
@@ -118,9 +123,9 @@
"LabelFree": "Gratuit",
"HeaderPlaybackError": "Erreur de lecture",
"MessagePlaybackErrorNotAllowed": "Vous n'\u00eates pas autoris\u00e9 \u00e0 lire ce contenu. Veuillez contacter votre administrateur syst\u00e8me pour plus de d\u00e9tails.",
- "MessagePlaybackErrorNoCompatibleStream": "Aucun flux compatible n'est actuellement disponible. Veuillez r\u00e9essayer plus tard.",
+ "MessagePlaybackErrorNoCompatibleStream": "Aucun flux compatible n'est actuellement disponible. Veuillez r\u00e9essayer plus tard ou contactez votre administrateur pour plus de d\u00e9tails.",
"MessagePlaybackErrorRateLimitExceeded": "Vous avez d\u00e9pass\u00e9 votre limite de lecture. Veuillez contacter votre administrateur syst\u00e8me pour plus de d\u00e9tails.",
- "MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
+ "MessagePlaybackErrorPlaceHolder": "Impossible de lire le contenu choisi sur cet appareil",
"HeaderSelectAudio": "S\u00e9lectionner audio",
"HeaderSelectSubtitles": "S\u00e9lectionner sous-titres",
"ButtonMarkForRemoval": "Supprimer de l'appareil",
@@ -174,6 +179,9 @@
"OptionThursday": "Jeudi",
"OptionFriday": "Vendredi",
"OptionSaturday": "Samedi",
+ "OptionEveryday": "Tous les jours",
+ "OptionWeekend": "Week-ends",
+ "OptionWeekday": "Jours de semaine",
"HeaderConfirmDeletion": "Confirmer la suppression",
"MessageConfirmPathSubstitutionDeletion": "\u00cates-vous s\u00fbr de vouloir supprimer cette substitution de chemin d'acc\u00e8s?",
"LiveTvUpdateAvailable": "(Mise \u00e0 jour disponible)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "S\u00e9parer les m\u00e9dias",
"MessageConfirmSplitMedia": "\u00cates vous s\u00fbrs de vouloir diviser les sources de m\u00e9dia dans des items s\u00e9par\u00e9s ?",
"HeaderError": "Erreur",
+ "MessageChromecastConnectionError": "Votre cl\u00e9 Chromecast ne peut pas se connecter \u00e0 votre serveur Emby. Veuillez v\u00e9rifier les connections et recommencer.",
"MessagePleaseSelectOneItem": "Veuillez s\u00e9lectionner au moins un item.",
"MessagePleaseSelectTwoItems": "Veuillez s\u00e9lectionner au moins deux items.",
"MessageTheFollowingItemsWillBeGrouped": "Les titres suivants seront group\u00e9s en un seul item:",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/he.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/he.json
index a92346cb2..3c461177f 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/he.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/he.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirmation",
"MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
"MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "\u05d8\u05dc\u05d5\u05d5\u05d9\u05d6\u05d9\u05d4 \u05d7\u05d9\u05d9\u05d4",
"TitleSync": "Sync",
+ "ButtonDonate": "Donate",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "Notifications",
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -118,7 +123,7 @@
"LabelFree": "Free",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Select Audio",
@@ -174,6 +179,9 @@
"OptionThursday": "\u05d7\u05de\u05d9\u05e9\u05d9",
"OptionFriday": "\u05e9\u05d9\u05e9\u05d9",
"OptionSaturday": "\u05e9\u05d1\u05ea",
+ "OptionEveryday": "Every day",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Confirm Deletion",
"MessageConfirmPathSubstitutionDeletion": "Are you sure you wish to delete this path substitution?",
"LiveTvUpdateAvailable": "(Update available)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Split Media Apart",
"MessageConfirmSplitMedia": "Are you sure you wish to split the media sources into separate items?",
"HeaderError": "Error",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Please select at least one item.",
"MessagePleaseSelectTwoItems": "Please select at least two items.",
"MessageTheFollowingItemsWillBeGrouped": "The following titles will be grouped into one item:",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/hr.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/hr.json
index 3d2255b83..64b518013 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/hr.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/hr.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirmation",
"MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
"MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "TV",
"TitleSync": "Sync",
+ "ButtonDonate": "Donate",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "Notifications",
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -118,7 +123,7 @@
"LabelFree": "Free",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Select Audio",
@@ -174,6 +179,9 @@
"OptionThursday": "\u010cetvrtak",
"OptionFriday": "Petak",
"OptionSaturday": "Subota",
+ "OptionEveryday": "Every day",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Confirm Deletion",
"MessageConfirmPathSubstitutionDeletion": "Are you sure you wish to delete this path substitution?",
"LiveTvUpdateAvailable": "(Update available)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Split Media Apart",
"MessageConfirmSplitMedia": "Are you sure you wish to split the media sources into separate items?",
"HeaderError": "Error",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Please select at least one item.",
"MessagePleaseSelectTwoItems": "Please select at least two items.",
"MessageTheFollowingItemsWillBeGrouped": "The following titles will be grouped into one item:",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/hu.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/hu.json
index f9ddac88f..9a98b1951 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/hu.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/hu.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirmation",
"MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
"MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "Live TV",
"TitleSync": "Sync",
+ "ButtonDonate": "Donate",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "Notifications",
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -118,7 +123,7 @@
"LabelFree": "Free",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Select Audio",
@@ -174,6 +179,9 @@
"OptionThursday": "Thursday",
"OptionFriday": "Friday",
"OptionSaturday": "Saturday",
+ "OptionEveryday": "Every day",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Confirm Deletion",
"MessageConfirmPathSubstitutionDeletion": "Are you sure you wish to delete this path substitution?",
"LiveTvUpdateAvailable": "(Update available)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Split Media Apart",
"MessageConfirmSplitMedia": "Are you sure you wish to split the media sources into separate items?",
"HeaderError": "Error",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Please select at least one item.",
"MessagePleaseSelectTwoItems": "Please select at least two items.",
"MessageTheFollowingItemsWillBeGrouped": "The following titles will be grouped into one item:",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/it.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/it.json
index 76d29661b..1c6a166b2 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/it.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/it.json
@@ -6,8 +6,8 @@
"Administrator": "Amministratore",
"Password": "Password",
"DeleteImage": "Elimina immagine",
- "MessageThankYouForSupporting": "Thank you for supporting Emby.",
- "MessagePleaseSupportProject": "Please support Emby.",
+ "MessageThankYouForSupporting": "Grazie per il tuo sostegno a Emby.",
+ "MessagePleaseSupportProject": "Per favore, sostieni Emby.",
"DeleteImageConfirmation": "Sei sicuro di voler eliminare questa immagine?",
"FileReadCancelled": "Il file letto \u00e8 stato cancellato.",
"FileNotFound": "File non trovato",
@@ -35,14 +35,19 @@
"HeaderConfirmation": "Conferma",
"MessageKeyUpdated": "Grazie. La vostra chiave supporter \u00e8 stato aggiornato.",
"MessageKeyRemoved": "Grazie. La vostra chiave supporter \u00e8 stata rimossa.",
+ "HeaderSupportTheTeam": "Supporta il Team di Emby",
+ "TextEnjoyBonusFeatures": "Goditi le caratteristiche aggiuntive",
"TitleLiveTV": "Tv in diretta",
"TitleSync": "Sincronizza",
+ "ButtonDonate": "Donazione",
+ "HeaderMyMedia": "I mei media",
+ "TitleNotifications": "Notifiche",
"ErrorLaunchingChromecast": "Si \u00e8 verificato un errore all'avvio di chromecast. Assicurati che il tuo dispositivo sia connesso alla rete wireless.",
- "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
- "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
- "HeaderConfirmRemoveUser": "Remove User",
- "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
- "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+ "MessageErrorLoadingSupporterInfo": "Si \u00e8 verificato un errore caricando le informazioni sui supporter. Si prega di riprovare pi\u00f9 tardi.",
+ "MessageLinkYourSupporterKey": "Collega il tuo codice Supporter con al massimo {0} membri di Emby per accedere liberamente alle seguenti app:",
+ "HeaderConfirmRemoveUser": "Cancellazione utente",
+ "MessageSwipeDownOnRemoteControl": "Benvenuti nel controllo remoto. Scorri verso il basso ovunque su questa schermata per tornare da dove sei venuto.",
+ "MessageConfirmRemoveConnectSupporter": "Sei sicuro di voler rimuovere da questo utente i benefici aggiuntivi da supporter?",
"ValueTimeLimitSingleHour": "Tempo limite: 1 ora",
"ValueTimeLimitMultiHour": "Tempo limite: {0} ore",
"HeaderUsers": "Utenti",
@@ -89,18 +94,18 @@
"ButtonAddToCollection": "Aggiungi alla collezione",
"HeaderSelectCertificatePath": "Seleziona il percorso del Certificato",
"ConfirmMessageScheduledTaskButton": "L'operazione viene normalmente eseguita come operazione pianificata. Pu\u00f2 anche essere avviata manualmente da qui. Per configurare le operazioni pianificate, vedi:",
- "HeaderSupporterBenefit": "L'iscrizione come supporter da benefici addizionali, come l'accesso alla sincronizzazione, i plugin premium, canali con contenuto internet, e altro. {0}Scopri di pi\u00f9{1}.",
+ "HeaderSupporterBenefit": "L'iscrizione come supporter garantisce benefici aggiuntivi, come l'accesso alla sincronizzazione, i plugin premium, canali con contenuto internet, e altro ancora. {0}Scopri di pi\u00f9{1}.",
"LabelSyncNoTargetsHelp": "Sembra che al momento non avete applicazioni che supportano la sincronizzazione.",
- "HeaderWelcomeToProjectServerDashboard": "Welcome to the Emby Server Dashboard",
- "HeaderWelcomeToProjectWebClient": "Welcome to the Emby Web Client",
- "ButtonTakeTheTour": "Fai il tour",
+ "HeaderWelcomeToProjectServerDashboard": "Benvenuto nel Pannello di controllo del Server Emby",
+ "HeaderWelcomeToProjectWebClient": "Benvenuto nel client web Emby",
+ "ButtonTakeTheTour": "Fai una visita",
"HeaderWelcomeBack": "Ben tornato!",
- "TitlePlugins": "Plugins",
+ "TitlePlugins": "Plugin",
"ButtonTakeTheTourToSeeWhatsNew": "Fai un tour per vedere cosa \u00e8 cambiato",
"MessageNoSyncJobsFound": "Nessuna sincronizzazione pianificata. Creane una utilizzando i pulsanti sull'interfaccia web",
"HeaderLibraryAccess": "Accesso libreria",
"HeaderChannelAccess": "Accesso canali",
- "HeaderDeviceAccess": "Accesso dispositivo",
+ "HeaderDeviceAccess": "Accesso al dispositivo",
"HeaderSelectDevices": "Seleziona periferiche",
"ButtonCancelItem": "Cancella oggetto",
"ButtonQueueForRetry": "In attesa di riprovare",
@@ -118,9 +123,9 @@
"LabelFree": "Gratis",
"HeaderPlaybackError": "Errore di riproduzione",
"MessagePlaybackErrorNotAllowed": "Al momento non sei autorizzato a riprodurre questo contenuto. Per favore contatta l'amministratore del sistema per ulteriori dettagli",
- "MessagePlaybackErrorNoCompatibleStream": "Nessuna trasmissione compatibile \u00e8 al momento disponibile. Per favore riprova in seguito",
+ "MessagePlaybackErrorNoCompatibleStream": "Nessuna trasmissione compatibile \u00e8 al momento disponibile. Per favore riprova in seguito o contatta il tuo Amministratore di sistema per chiarimenti",
"MessagePlaybackErrorRateLimitExceeded": "La tua quota di riproduzione \u00e8 stata raggiunta. Per favore contatta l'amministratore del sistema per ulteriori dettagli",
- "MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
+ "MessagePlaybackErrorPlaceHolder": "Il contenuto scelto non pu\u00f2 essere riprodotto su questo dispositivo",
"HeaderSelectAudio": "Seleziona audio",
"HeaderSelectSubtitles": "Seleziona sottotitoli",
"ButtonMarkForRemoval": "Rimuovi dal dispositivo",
@@ -174,6 +179,9 @@
"OptionThursday": "Gioved\u00ec",
"OptionFriday": "Venerd\u00ec",
"OptionSaturday": "Sabato",
+ "OptionEveryday": "Tutti i giorni",
+ "OptionWeekend": "weekend",
+ "OptionWeekday": "Giorni feriali",
"HeaderConfirmDeletion": "Conferma Cancellazione",
"MessageConfirmPathSubstitutionDeletion": "Sei sicuro di voler cancellare questa sostituzione percorso?",
"LiveTvUpdateAvailable": "(Aggiornamento disponibile)",
@@ -191,10 +199,11 @@
"HeaderSplitMedia": "Dividi Media",
"MessageConfirmSplitMedia": "Sei sicuro di voler dividere le fonti dei media in voci separate?",
"HeaderError": "Errore",
+ "MessageChromecastConnectionError": "Il tuo ricevitore Chromecast non \u00e8 in grado di collegarsi al tuo Server Emby. Si prega di verificare la connessione e provare di nuovo",
"MessagePleaseSelectOneItem": "Si prega di selezionare almeno un elemento.",
"MessagePleaseSelectTwoItems": "Seleziona almeno due elementi.",
"MessageTheFollowingItemsWillBeGrouped": "I seguenti titoli saranno raggruppati in un unico elemento:",
- "MessageConfirmItemGrouping": "Emby apps will automatically choose the optimal version to play based on device and network performance. Are you sure you wish to continue?",
+ "MessageConfirmItemGrouping": "Le app Emby scieglieranno automaticamente la versione ottimale per la riproduzione basandosi sulle prestazioni del dispositivo e della rete. Sei sicuro di voler continuare?",
"HeaderResume": "Riprendi",
"HeaderMyViews": "Mie viste",
"HeaderLibraryFolders": "Cartelle dei mediati",
@@ -242,8 +251,8 @@
"OrganizePatternResult": "Risultati: {0}",
"HeaderRestart": "Riavvia",
"HeaderShutdown": "Spegni",
- "MessageConfirmRestart": "Are you sure you wish to restart Emby Server?",
- "MessageConfirmShutdown": "Are you sure you wish to shutdown Emby Server?",
+ "MessageConfirmRestart": "Sei sicuro di voler riavviare il Server Emby?",
+ "MessageConfirmShutdown": "Sei sicuro di voler spegnere il Server Emby?",
"ButtonUpdateNow": "Aggiorna Adesso",
"ValueItemCount": "{0} elemento",
"ValueItemCountPlural": "{0} elementi",
@@ -288,7 +297,7 @@
"MessageErrorPlayingVideo": "Si \u00e8 verificato un errore nella riproduzione del video.",
"MessageEnsureOpenTuner": "Si prega di assicurarsi che ci sia un sintonizzatore disponibile.",
"ButtonHome": "Home",
- "ButtonDashboard": "Dashboard",
+ "ButtonDashboard": "Pannello",
"ButtonReports": "Reports",
"ButtonMetadataManager": "Manager Metadati",
"HeaderTime": "Tempo",
@@ -312,7 +321,7 @@
"OptionBlockLiveTvChannels": "Canali TV in onda",
"OptionBlockChannelContent": "Contenuto di Canali Internet",
"ButtonRevoke": "Revocare",
- "MessageConfirmRevokeApiKey": "Are you sure you wish to revoke this api key? The application's connection to Emby Server will be abruptly terminated.",
+ "MessageConfirmRevokeApiKey": "Sei sicuro di voler revocare questa chiave api? La connessione dell'applicazione al Server Emby terminer\u00e0 immediatamente",
"HeaderConfirmRevokeApiKey": "Revocare Chiave Api",
"ValueContainer": "Contenitore: {0}",
"ValueAudioCodec": "Audio Codec: {0}",
@@ -389,7 +398,7 @@
"TabMetadata": "Metadati",
"TabDLNA": "DLNA",
"TabLiveTV": "Tv indiretta",
- "TabAutoOrganize": "Organizza Automaticamente",
+ "TabAutoOrganize": "Organizza Autom.",
"TabPlugins": "Plugins",
"TabAdvanced": "Avanzato",
"TabHelp": "Aiuto",
@@ -467,7 +476,7 @@
"PersonTypePerson": "Persona",
"LabelTitleDisplayOrder": "Titolo mostrato in ordine:",
"OptionSortName": "Nome ordinato",
- "OptionReleaseDate": "Data di uscita",
+ "OptionReleaseDate": "Data di rilascio",
"LabelSeasonNumber": "Numero Stagione:",
"LabelDiscNumber": "Disco numero",
"LabelParentNumber": "Numero superiore",
@@ -526,17 +535,17 @@
"MessageInstallPluginFromApp": "Questo Plugin deve essere installato dall'app in cui vuoi farlo funzionare",
"ValuePriceUSD": "Prezzo: {0} (USD)",
"MessageFeatureIncludedWithSupporter": "Siete registrati per questa funzione, e sarete in grado di continuare ad usarlo con un abbonamento attivo sostenitore.",
- "MessageChangeRecurringPlanConfirm": "After completing this transaction you will need to cancel your previous recurring donation from within your PayPal account. Thank you for supporting Emby.",
+ "MessageChangeRecurringPlanConfirm": "Dopo aver completato questa transazione dovrai cancellare dal tuo account PayPal la tua precedente donazione ricorrente. Grazie per aver sostenuto Emby.",
"MessageSupporterMembershipExpiredOn": "La tua iscrizione supporter scaduto il {0}.",
- "MessageYouHaveALifetimeMembership": "You have a lifetime supporter membership. You can provide additional donations on a one-time or recurring basis using the options below. Thank you for supporting Emby.",
+ "MessageYouHaveALifetimeMembership": "Tu hai un abbonamento come Supporter che non ha scadenza. Puoi fare ulteriori donazioni, singole o ricorrenti, scegliendo le opzioni sottostanti. Grazie per il tuo sostegno a Emby",
"MessageYouHaveAnActiveRecurringMembership": "Si dispone di un attivo {0} appartenenza. \u00c8 possibile aggiornare il vostro piano utilizzando le opzioni di seguito.",
"ButtonDelete": "Elimina",
- "HeaderEmbyAccountAdded": "Emby Account Added",
- "MessageEmbyAccountAdded": "The Emby account has been added to this user.",
- "MessagePendingEmbyAccountAdded": "The Emby account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.",
- "HeaderEmbyAccountRemoved": "Emby Account Removed",
- "MessageEmbyAccontRemoved": "The Emby account has been removed from this user.",
- "TooltipLinkedToEmbyConnect": "Linked to Emby Connect",
+ "HeaderEmbyAccountAdded": "Account Emby aggiunto",
+ "MessageEmbyAccountAdded": "L'account Emby \u00e8 stato aggiunto a questo utente",
+ "MessagePendingEmbyAccountAdded": "L'account Emby \u00e8 stato aggiunto a questo utente. Un'email sar\u00e0 inviata al proprietario dell'account. L'invito dovr\u00e0 essere confermato selezionando il link contenuto nell'email",
+ "HeaderEmbyAccountRemoved": "Account Emby rimosso",
+ "MessageEmbyAccontRemoved": "L'account Emby \u00e8 stato rimosso da questo utente",
+ "TooltipLinkedToEmbyConnect": "Collegato ad Emby Connect",
"HeaderUnrated": "Non votato",
"ValueDiscNumber": "Disco {0}",
"HeaderUnknownDate": "Data Sconosciuta",
@@ -584,7 +593,7 @@
"ValuePremieres": "Debuttato {0}",
"ValueStudio": "Studio: {0}",
"ValueStudios": "Studi: {0}",
- "ValueStatus": "Status: {0}",
+ "ValueStatus": "Stato {0}",
"ValueSpecialEpisodeName": "Speciali - {0}",
"LabelLimit": "Limite:",
"ValueLinks": "Collegamenti: {0}",
@@ -666,12 +675,12 @@
"WebClientTourMetadataManager": "Fare clic su Modifica per aprire la gestione dei metadati",
"WebClientTourPlaylists": "Facile creazione di playlist , e riprodurli su qualsiasi dispositivo",
"WebClientTourCollections": "Creare collezioni di film di casella di gruppo imposta insieme",
- "WebClientTourUserPreferences1": "User preferences allow you to customize the way your library is presented in all of your Emby apps",
- "WebClientTourUserPreferences2": "Configure your audio and subtitle language settings once, for every Emby app",
+ "WebClientTourUserPreferences1": "Le Preferenze Utente consentono di personalizzare il modo in cui la tua libreria viene presentata in tutte le app Emby",
+ "WebClientTourUserPreferences2": "Configura le impostazioni audio e la lingua dei sottotitoli valide per tutte le app Emby",
"WebClientTourUserPreferences3": "Progettare la home page del client web a proprio piacimento",
"WebClientTourUserPreferences4": "Configurare fondali, sigle e lettori esterni",
"WebClientTourMobile1": "Il client web funziona alla grande su smartphone e tablet ...",
- "WebClientTourMobile2": "and easily controls other devices and Emby apps",
+ "WebClientTourMobile2": "e controlla facilmente altri dispositivi e app Emby",
"WebClientTourMySync": "Sincronizza il tuo personal media per i dispositivi per la visualizzazione offline.",
"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.",
@@ -683,7 +692,7 @@
"DashboardTourPlugins": "Installare il plugin come canali internet video, live tv, scanner metadati e altro ancora.",
"DashboardTourNotifications": "Inviare automaticamente notifiche di eventi server al vostro dispositivo mobile, e-mail e altro ancora.",
"DashboardTourScheduledTasks": "Gestire facilmente le operazioni di lunga esecuzione con le operazioni pianificate. Decidere quando corrono, e con quale frequenza.",
- "DashboardTourMobile": "The Emby Server dashboard works great on smartphones and tablets. Manage your server from the palm of your hand anytime, anywhere.",
+ "DashboardTourMobile": "Il Pannello di Controllo del Server Emby funziona bene su smartphone e tablet. Gestisci il tuo server con il palmo della tua mano, quando vuoi, dove vuoi",
"DashboardTourSync": "Sincronizza il tuo personal media per i dispositivi per la visualizzazione offline.",
"MessageRefreshQueued": "Aggiornamento programmato",
"TabDevices": "Dispositivi",
@@ -693,13 +702,13 @@
"DeleteDeviceConfirmation": "Sei sicuro di voler cancellare questo dispositivo? Esso riapparir\u00e0 la prossima volta che un utente accede con esso.",
"LabelEnableCameraUploadFor": "Abilita caricamento macchina fotografica per:",
"HeaderSelectUploadPath": "Seleziona cartella upload",
- "LabelEnableCameraUploadForHelp": "Uploads will occur automatically in the background when signed into Emby.",
+ "LabelEnableCameraUploadForHelp": "Gli upload saranno eseguiti automaticamente in background quando sei collegato a Emby",
"ErrorMessageStartHourGreaterThanEnd": "Ora di fine deve essere maggiore del tempo di avvio.",
"ButtonLibraryAccess": "Accesso biblioteca",
"ButtonParentalControl": "Controllo parentale",
"HeaderInvitationSent": "Invito inviato",
"MessageInvitationSentToUser": "Una e-mail \u00e8 stata inviata a {0}, invitandoli ad accettare l'invito di condivisione.",
- "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Emby.",
+ "MessageInvitationSentToNewUser": "Un'email \u00e8 stata inviata a {0} invitandolo a registrarsi a Emby",
"HeaderConnectionFailure": "Errore di connessione",
"MessageUnableToConnectToServer": "Non siamo in grado di connettersi al server selezionato al momento. Per favore assicurati che sia in esecuzione e riprova.",
"ButtonSelectServer": "Selezionare il server",
@@ -716,12 +725,12 @@
"MessageInvalidForgotPasswordPin": "Un pin Invalido o scaduto \u00e8 stato inserito. Riprova.",
"MessagePasswordResetForUsers": "Le password per i seguenti utenti sono state rimosse:",
"HeaderInviteGuest": "Invita Ospite",
- "ButtonLinkMyEmbyAccount": "Link my account now",
- "MessageConnectAccountRequiredToInviteGuest": "In order to invite guests you need to first link your Emby account to this server.",
+ "ButtonLinkMyEmbyAccount": "Collega il mio account ora",
+ "MessageConnectAccountRequiredToInviteGuest": "Per invitare gli amici \u00e8 necessario innanzitutto collegare l'account Emby a questo server.",
"ButtonSync": "Sinc.",
"SyncMedia": "Sync media",
"HeaderCancelSyncJob": "Cancel Sync",
- "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
+ "CancelSyncJobConfirmation": "La cancellazione dell'attivit\u00e0 di sincronizzazione causer\u00e0 la rimozione dal dispositivo dei media sincronizzati durante il prossimo processo di sincronizzazione. Sei sicuro di voler comunque procedere?",
"TabSync": "Sinc",
"MessagePleaseSelectDeviceToSyncTo": "Selezionare un dispositivo per la sincronizzazione",
"MessageSyncJobCreated": "Attivit\u00e0 di Sincronizz. Creata",
@@ -745,6 +754,6 @@
"SyncJobItemStatusFailed": "Fallito",
"SyncJobItemStatusRemovedFromDevice": "Rimosso dal dispositivo",
"SyncJobItemStatusCancelled": "Cancellato",
- "LabelProfile": "Profile:",
+ "LabelProfile": "Profilo:",
"LabelBitrateMbps": "Bitrate (Mbps):"
} \ 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 9c53eb92e..c15e520e2 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
@@ -40,6 +40,8 @@
"TitleLiveTV": "Live TV",
"TitleSync": "Sync",
"ButtonDonate": "Donate",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "Notifications",
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -121,7 +123,7 @@
"LabelFree": "Free",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Select Audio",
@@ -198,6 +200,7 @@
"HeaderSplitMedia": "Split Media Apart",
"MessageConfirmSplitMedia": "Are you sure you wish to split the media sources into separate items?",
"HeaderError": "Error",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Please select at least one item.",
"MessagePleaseSelectTwoItems": "Please select at least two items.",
"MessageTheFollowingItemsWillBeGrouped": "The following titles will be grouped into one item:",
@@ -437,6 +440,7 @@
"HeaderVideo": "Video",
"HeaderRuntime": "Runtime",
"HeaderCommunityRating": "Community rating",
+ "HeaderPasswordReset": "Password Reset",
"HeaderParentalRating": "Parental rating",
"HeaderReleaseDate": "Release date",
"HeaderDateAdded": "Date added",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json
index 596a9bdd7..ecdd36c0e 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "\u0420\u0430\u0441\u0442\u0430\u0443",
"MessageKeyUpdated": "\u0416\u0430\u049b\u0442\u0430\u0443\u0448\u044b \u043a\u0456\u043b\u0442\u0456\u04a3\u0456\u0437 \u0436\u0430\u04a3\u0430\u0440\u0442\u044b\u043b\u0434\u044b.",
"MessageKeyRemoved": "\u0416\u0430\u049b\u0442\u0430\u0443\u0448\u044b \u043a\u0456\u043b\u0442\u0456\u04a3\u0456\u0437 \u0430\u043b\u0430\u0441\u0442\u0430\u043b\u0434\u044b.",
+ "HeaderSupportTheTeam": "Emby \u0442\u043e\u0431\u044b\u043d \u049b\u043e\u043b\u0434\u0430\u04a3\u044b\u0437",
+ "TextEnjoyBonusFeatures": "\u0421\u044b\u0439\u0430\u049b\u044b \u0435\u0440\u0435\u043a\u0448\u0435\u043b\u0456\u043a\u0442\u0435\u0440\u0434\u0456 \u0442\u0430\u043c\u0430\u0448\u0430\u043b\u0430\u043d\u044b\u04a3\u044b\u0437",
"TitleLiveTV": "\u042d\u0444\u0438\u0440\u043b\u0456\u043a \u0422\u0414",
"TitleSync": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443",
+ "ButtonDonate": "\u049a\u0430\u0439\u044b\u0440\u043c\u0430\u043b\u0430\u0443",
+ "HeaderMyMedia": "\u041c\u0435\u043d\u0456\u04a3 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0456\u043c",
+ "TitleNotifications": "\u0425\u0430\u0431\u0430\u0440\u043b\u0430\u043d\u0434\u044b\u0440\u0443\u043b\u0430\u0440",
"ErrorLaunchingChromecast": "Chromecast \u0456\u0441\u043a\u0435 \u049b\u043e\u0441\u044b\u043b\u0443 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u049b\u0430\u0442\u0435 \u043e\u0440\u044b\u043d \u0430\u043b\u0434\u044b. \u049a\u04b1\u0440\u044b\u043b\u0493\u044b\u04a3\u044b\u0437 \u0441\u044b\u043c\u0441\u044b\u0437 \u0436\u0435\u043b\u0456\u0433\u0435 \u049b\u043e\u0441\u044b\u043b\u0493\u0430\u043d\u044b\u043d\u0430 \u043a\u04e9\u0437 \u0436\u0435\u0442\u043a\u0456\u0437\u0456\u04a3\u0456\u0437.",
"MessageErrorLoadingSupporterInfo": "\u0416\u0430\u049b\u0442\u0430\u0443\u0448\u044b \u0430\u049b\u043f\u0430\u0440\u0430\u0442\u044b\u043d \u0436\u04af\u043a\u0442\u0435\u0443 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u049b\u0430\u0442\u0435 \u043e\u0440\u044b\u043d \u0430\u043b\u0434\u044b. \u04d8\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u043a\u0435\u0439\u0456\u043d \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437.",
"MessageLinkYourSupporterKey": "\u041a\u0435\u043b\u0435\u0441\u0456 \u0431\u0430\u0493\u0434\u0430\u0440\u043b\u0430\u043c\u0430\u043b\u0430\u0440\u0493\u0430 \u0442\u0435\u0433\u0456\u043d \u049b\u0430\u0442\u044b\u043d\u0430\u0443\u0434\u044b \u0442\u0430\u043c\u0430\u0448\u0430\u043b\u0430\u0443 \u04af\u0448\u0456\u043d {0} Emby Connect \u043c\u04af\u0448\u0435\u0441\u0456\u043d\u0435 \u0434\u0435\u0439\u0456\u043d \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u0442\u044b\u0440\u044b\u04a3\u044b\u0437.",
@@ -66,7 +71,7 @@
"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\u0493\u0430",
+ "ButtonHelp": "\u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0442\u0435\u0433\u0456 \u0430\u043d\u044b\u049b\u0442\u0430\u043c\u0430\u0493\u0430",
"ButtonSave": "\u0421\u0430\u049b\u0442\u0430\u0443",
"ButtonDownload": "\u0416\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443",
"SyncJobStatusQueued": "\u041a\u0435\u0437\u0435\u043a\u0442\u0435",
@@ -81,7 +86,7 @@
"LabelCollection": "\u0416\u0438\u044b\u043d\u0442\u044b\u049b",
"HeaderAddToCollection": "\u0416\u0438\u044b\u043d\u0442\u044b\u049b\u049b\u0430 \u04af\u0441\u0442\u0435\u0443",
"NewCollectionNameExample": "\u041c\u044b\u0441\u0430\u043b: \u0416\u04b1\u043b\u0434\u044b\u0437 \u0441\u043e\u0493\u044b\u0441\u0442\u0430\u0440\u044b (\u0436\u0438\u044b\u043d\u0442\u044b\u049b)",
- "OptionSearchForInternetMetadata": "\u0421\u0443\u0440\u0435\u0442\u0442\u0435\u043c\u0435\u043b\u0435\u0440 \u0431\u0435\u043d \u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0442\u0435\u043d \u0456\u0437\u0434\u0435\u0443",
+ "OptionSearchForInternetMetadata": "\u0421\u0443\u0440\u0435\u0442\u0442\u0435\u043c\u0435\u043b\u0435\u0440 \u0431\u0435\u043d \u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0442\u0435\u043d \u0456\u0437\u0434\u0435\u0443",
"LabelSelectCollection": "\u0416\u0438\u044b\u043d\u0442\u044b\u049b\u0442\u044b \u0442\u0430\u04a3\u0434\u0430\u0443:",
"HeaderDevices": "\u049a\u04b1\u0440\u044b\u043b\u0493\u044b\u043b\u0430\u0440",
"ButtonScheduledTasks": "\u0416\u043e\u0441\u043f\u0430\u0440\u043b\u0430\u0493\u0430\u043d \u0442\u0430\u043f\u0441\u044b\u0440\u043c\u0430\u043b\u0430\u0440\u0493\u0430 \u04e9\u0442\u0443",
@@ -117,9 +122,9 @@
"LabelNumberReviews": "{0} \u043f\u0456\u043a\u0456\u0440",
"LabelFree": "\u0422\u0435\u0433\u0456\u043d",
"HeaderPlaybackError": "\u041e\u0439\u043d\u0430\u0442\u0443 \u049b\u0430\u0442\u0435\u0441\u0456",
- "MessagePlaybackErrorNotAllowed": "\u041e\u0441\u044b \u043c\u0430\u0437\u043c\u04b1\u043d\u0434\u044b \u043e\u0439\u043d\u0430\u0442\u0443 \u04af\u0448\u0456\u043d \u0430\u0493\u044b\u043c\u0434\u0430 \u0441\u0456\u0437\u0433\u0435 \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0456\u043b\u043c\u0435\u0433\u0435\u043d. \u041c\u04d9\u043b\u0456\u043c\u0435\u0442\u0442\u0435\u0440 \u04af\u0448\u0456\u043d \u0436\u04af\u0439\u0435\u043b\u0456\u043a \u04d9\u043a\u0456\u043c\u0448\u0456\u04a3\u0456\u0437\u0433\u0435 \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u044b\u04a3\u044b\u0437.",
- "MessagePlaybackErrorNoCompatibleStream": "\u0410\u0493\u044b\u043c\u0434\u0430 \u0435\u0448\u049b\u0430\u043d\u0434\u0430\u0439 \u0441\u044b\u0439\u044b\u0441\u044b\u043c\u0434\u044b \u0430\u0493\u044b\u043d\u0434\u0430\u0440 \u049b\u0430\u0442\u044b\u043d\u0430\u0443\u043b\u044b \u0435\u043c\u0435\u0441. \u04d8\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u043a\u0435\u0439\u0456\u043d \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437.",
- "MessagePlaybackErrorRateLimitExceeded": "\u041e\u0439\u043d\u0430\u0442\u0443 \u049b\u0430\u0440\u049b\u044b\u043d\u044b\u04a3\u044b\u0437 \u0448\u0435\u043a\u0442\u0435\u043d \u0430\u0441\u044b\u043f \u043a\u0435\u0442\u043a\u0435\u043d. \u041c\u04d9\u043b\u0456\u043c\u0435\u0442\u0442\u0435\u0440 \u04af\u0448\u0456\u043d \u0436\u04af\u0439\u0435\u043b\u0456\u043a \u04d9\u043a\u0456\u043c\u0448\u0456\u04a3\u0456\u0437\u0433\u0435 \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u044b\u04a3\u044b\u0437.",
+ "MessagePlaybackErrorNotAllowed": "\u041e\u0441\u044b \u043c\u0430\u0437\u043c\u04b1\u043d\u0434\u044b \u043e\u0439\u043d\u0430\u0442\u0443 \u04af\u0448\u0456\u043d \u0430\u0493\u044b\u043c\u0434\u0430 \u0441\u0456\u0437\u0433\u0435 \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0456\u043b\u043c\u0435\u0433\u0435\u043d. \u0422\u043e\u043b\u044b\u049b \u043c\u04d9\u043b\u0456\u043c\u0435\u0442\u0442\u0435\u0440 \u04af\u0448\u0456\u043d \u0436\u04af\u0439\u0435\u043b\u0456\u043a \u04d9\u043a\u0456\u043c\u0448\u0456\u04a3\u0456\u0437\u0433\u0435 \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u044b\u04a3\u044b\u0437.",
+ "MessagePlaybackErrorNoCompatibleStream": "\u0410\u0493\u044b\u043c\u0434\u0430 \u0435\u0448\u049b\u0430\u043d\u0434\u0430\u0439 \u0441\u044b\u0439\u044b\u0441\u044b\u043c\u0434\u044b \u0430\u0493\u044b\u043d\u0434\u0430\u0440 \u049b\u0430\u0442\u044b\u043d\u0430\u0443\u043b\u044b \u0435\u043c\u0435\u0441. \u04d8\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u043a\u0435\u0439\u0456\u043d \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437 \u043d\u0435\u043c\u0435\u0441\u0435 \u0442\u043e\u043b\u044b\u049b \u043c\u04d9\u043b\u0456\u043c\u0435\u0442\u0442\u0435\u0440 \u04af\u0448\u0456\u043d \u0436\u04af\u0439\u0435\u043b\u0456\u043a \u04d9\u043a\u0456\u043c\u0448\u0456\u04a3\u0456\u0437\u0433\u0435 \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u044b\u04a3\u044b\u0437.",
+ "MessagePlaybackErrorRateLimitExceeded": "\u041e\u0439\u043d\u0430\u0442\u0443 \u049b\u0430\u0440\u049b\u044b\u043d\u044b\u04a3\u044b\u0437 \u0448\u0435\u043a\u0442\u0435\u043d \u0430\u0441\u044b\u043f \u043a\u0435\u0442\u043a\u0435\u043d. \u0422\u043e\u043b\u044b\u049b \u043c\u04d9\u043b\u0456\u043c\u0435\u0442\u0442\u0435\u0440 \u04af\u0448\u0456\u043d \u0436\u04af\u0439\u0435\u043b\u0456\u043a \u04d9\u043a\u0456\u043c\u0448\u0456\u04a3\u0456\u0437\u0433\u0435 \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u044b\u04a3\u044b\u0437.",
"MessagePlaybackErrorPlaceHolder": "\u0422\u0430\u04a3\u0434\u0430\u043b\u0493\u0430\u043d \u043c\u0430\u0437\u043c\u04b1\u043d \u0431\u04b1\u043b \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u0434\u0430\u043d \u043e\u0439\u043d\u0430\u0442\u044b\u043b\u0430\u0442\u044b\u043d \u0435\u043c\u0435\u0441.",
"HeaderSelectAudio": "\u0414\u044b\u0431\u044b\u0441 \u0442\u0430\u04a3\u0434\u0430\u0443",
"HeaderSelectSubtitles": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 \u0442\u0430\u04a3\u0434\u0430\u0443",
@@ -174,6 +179,9 @@
"OptionThursday": "\u0431\u0435\u0439\u0441\u0435\u043d\u0431\u0456",
"OptionFriday": "\u0436\u04b1\u043c\u0430",
"OptionSaturday": "\u0441\u0435\u043d\u0431\u0456",
+ "OptionEveryday": "\u041a\u04af\u043d \u0441\u0430\u0439\u044b\u043d",
+ "OptionWeekend": "\u0414\u0435\u043c\u0430\u043b\u044b\u0441 \u043a\u04af\u043d\u0434\u0435\u0440\u0456",
+ "OptionWeekday": "\u0410\u043f\u0442\u0430 \u043a\u04af\u043d\u0434\u0435\u0440\u0456",
"HeaderConfirmDeletion": "\u0416\u043e\u044e\u0434\u044b \u0440\u0430\u0441\u0442\u0430\u0443",
"MessageConfirmPathSubstitutionDeletion": "\u0428\u044b\u043d\u044b\u043c\u0435\u043d \u043e\u0441\u044b \u0436\u043e\u043b \u0430\u043b\u043c\u0430\u0441\u0442\u044b\u0440\u0443\u0434\u044b \u0436\u043e\u044e \u049b\u0430\u0436\u0435\u0442 \u043f\u0435?",
"LiveTvUpdateAvailable": "(\u0416\u0430\u04a3\u0430\u0440\u0442\u0443 \u049b\u043e\u043b \u0436\u0435\u0442\u0456\u043c\u0434\u0456)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "\u0422\u0430\u0441\u044b\u0493\u044b\u0448\u043d\u044b \u0431\u04e9\u043b\u0435\u043a\u0442\u0435\u043f \u0431\u04e9\u043b\u0443",
"MessageConfirmSplitMedia": "\u0428\u044b\u043d\u044b\u043c\u0435\u043d \u0442\u0430\u0441\u044b\u0493\u044b\u0448 \u043a\u04e9\u0437\u0434\u0435\u0440\u0456\u043d \u0431\u04e9\u043b\u0435\u043a \u0442\u0430\u0440\u043c\u0430\u049b\u0442\u0430\u0440\u0493\u0430 \u0431\u04e9\u043b\u0443 \u049b\u0430\u0436\u0435\u0442 \u043f\u0435?",
"HeaderError": "\u049a\u0430\u0442\u0435",
+ "MessageChromecastConnectionError": "Chromecast \u049b\u0430\u0431\u044b\u043b\u0434\u0430\u0493\u044b\u0448\u044b Emby Server \u04af\u0448\u0456\u043d \u049b\u043e\u0441\u044b\u043b\u0443\u044b \u043c\u04af\u043c\u043a\u0456\u043d \u0435\u043c\u0435\u0441. \u041e\u043b\u0430\u0440\u0434\u044b\u04a3 \u049b\u043e\u0441\u044b\u043b\u044b\u043c\u0434\u0430\u0440\u044b\u043d \u0442\u0435\u043a\u0441\u0435\u0440\u0456\u04a3\u0456\u0437 \u0434\u0435 \u0436\u04d9\u043d\u0435 \u04d9\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u043a\u0435\u0439\u0456\u043d \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437.",
"MessagePleaseSelectOneItem": "\u0415\u04a3 \u043a\u0435\u043c\u0456\u043d\u0434\u0435 \u0431\u0456\u0440 \u0442\u0430\u0440\u043c\u0430\u049b\u0442\u044b \u0442\u0430\u04a3\u0434\u0430\u04a3\u044b\u0437.",
"MessagePleaseSelectTwoItems": "\u0415\u04a3 \u043a\u0435\u043c\u0456\u043d\u0434\u0435 \u0435\u043a\u0456 \u0442\u0430\u0440\u043c\u0430\u049b\u0442\u044b \u0442\u0430\u04a3\u0434\u0430\u04a3\u044b\u0437.",
"MessageTheFollowingItemsWillBeGrouped": "\u041a\u0435\u043b\u0435\u0441\u0456 \u0442\u0443\u044b\u043d\u0434\u044b\u043b\u0430\u0440 \u0431\u0456\u0440 \u0442\u0430\u0440\u043c\u0430\u049b\u049b\u0430 \u0442\u043e\u043f\u0442\u0430\u0441\u0442\u044b\u0440\u044b\u043b\u0430\u0434\u044b:",
@@ -705,12 +714,12 @@
"ButtonSelectServer": "\u0421\u0435\u0440\u0432\u0435\u0440\u0434\u0456 \u0442\u0430\u04a3\u0434\u0430\u0443",
"MessagePluginConfigurationRequiresLocalAccess": "\u041e\u0441\u044b \u043f\u043b\u0430\u0433\u0438\u043d\u0434\u0456 \u0442\u0435\u04a3\u0448\u0435\u0443 \u04af\u0448\u0456\u043d \u0436\u0435\u0440\u0433\u0456\u043b\u0456\u043a\u0442\u0456 \u0441\u0435\u0440\u0432\u0435\u0440\u0456\u04a3\u0456\u0437\u0433\u0435 \u0442\u0456\u043a\u0435\u043b\u0435\u0439 \u043a\u0456\u0440\u0456\u04a3\u0456\u0437.",
"MessageLoggedOutParentalControl": "\u0410\u0493\u044b\u043c\u0434\u0430 \u049b\u0430\u0442\u044b\u043d\u0430\u0443 \u0448\u0435\u043a\u0442\u0435\u043b\u0433\u0435\u043d. \u04d8\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u043a\u0435\u0439\u0456\u043d \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437.",
- "DefaultErrorMessage": "\u0421\u0430\u0443\u0430\u043b\u0434\u044b \u04e9\u04a3\u0434\u0435\u0442\u0443 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u049b\u0430\u0442\u0435 \u043e\u0440\u044b\u043d \u0430\u043b\u0434\u044b. \u04d8\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u043a\u0435\u0439\u0456\u043d \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437.",
+ "DefaultErrorMessage": "\u0421\u0430\u0443\u0430\u043b \u04e9\u04a3\u0434\u0435\u043b\u0443 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u049b\u0430\u0442\u0435 \u043e\u0440\u044b\u043d \u0430\u043b\u0434\u044b. \u04d8\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u043a\u0435\u0439\u0456\u043d \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437.",
"ButtonAccept": "\u049a\u0430\u0431\u044b\u043b\u0434\u0430\u0443",
"ButtonReject": "\u049a\u0430\u0431\u044b\u043b\u0434\u0430\u043c\u0430\u0443",
"HeaderForgotPassword": "\u049a\u04b1\u043f\u0438\u044f \u0441\u04e9\u0437\u0434\u0456 \u04b1\u043c\u044b\u0442\u044b\u04a3\u044b\u0437 \u0431\u0430?",
"MessageContactAdminToResetPassword": "\u049a\u04b1\u043f\u0438\u044f \u0441\u04e9\u0437\u0456\u04a3\u0456\u0437\u0434\u0456 \u044b\u0441\u044b\u0440\u0443 \u04af\u0448\u0456\u043d \u0436\u04af\u0439\u0435\u043b\u0456\u043a \u04d9\u043a\u0456\u043c\u0448\u0456\u04a3\u0456\u0437\u0433\u0435 \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u044b\u04a3\u044b\u0437.",
- "MessageForgotPasswordInNetworkRequired": "\u049a\u04b1\u043f\u0438\u044f \u0441\u04e9\u0437\u0434\u0456 \u044b\u0441\u044b\u0440\u0443 \u04af\u0434\u0435\u0440\u0456\u0441\u0456 \u04af\u0448\u0456\u043d \u04d9\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u04af\u0439\u043b\u0456\u043a \u0436\u0435\u043b\u0456\u04a3\u0456\u0437\u0434\u0456\u04a3 \u0456\u0448\u0456\u043d\u0434\u0435 \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437.",
+ "MessageForgotPasswordInNetworkRequired": "\u049a\u04b1\u043f\u0438\u044f \u0441\u04e9\u0437\u0434\u0456 \u044b\u0441\u044b\u0440\u0443 \u043f\u0440\u043e\u0446\u0435\u0441\u0456 \u04af\u0448\u0456\u043d \u04d9\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u04af\u0439\u043b\u0456\u043a \u0436\u0435\u043b\u0456\u04a3\u0456\u0437\u0434\u0456\u04a3 \u0456\u0448\u0456\u043d\u0434\u0435 \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437.",
"MessageForgotPasswordFileCreated": "\u041a\u0435\u043b\u0435\u0441\u0456 \u0444\u0430\u0439\u043b \u0441\u0435\u0440\u0432\u0435\u0440\u0456\u04a3\u0456\u0437\u0434\u0435 \u0436\u0430\u0441\u0430\u043b\u0434\u044b \u0436\u04d9\u043d\u0435 \u049b\u0430\u043b\u0430\u0439 \u043a\u0456\u0440\u0456\u0441\u0443 \u0442\u0443\u0440\u0430\u043b\u044b \u043d\u04b1\u0441\u049b\u0430\u0443\u043b\u0430\u0440 \u0456\u0448\u0456\u043d\u0434\u0435 \u0431\u0430\u0440:",
"MessageForgotPasswordFileExpiration": "PIN \u044b\u0441\u044b\u0440\u0443 \u043c\u0435\u0437\u0433\u0456\u043b\u0456 {0} \u0431\u0456\u0442\u0435\u0434\u0456.",
"MessageInvalidForgotPasswordPin": "\u0416\u0430\u0440\u0430\u043c\u0441\u044b\u0437 \u043d\u0435\u043c\u0435\u0441\u0435 \u043c\u0435\u0440\u0437\u0456\u043c\u0456 \u0430\u044f\u049b\u0442\u0430\u043b\u0493\u0430\u043d PIN \u0435\u043d\u0433\u0456\u0437\u0456\u043b\u0434\u0456. \u04d8\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437.",
@@ -721,7 +730,7 @@
"ButtonSync": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443",
"SyncMedia": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443",
"HeaderCancelSyncJob": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443\u0434\u0456 \u0431\u043e\u043b\u0434\u044b\u0440\u043c\u0430\u0443",
- "CancelSyncJobConfirmation": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u0436\u04b1\u043c\u044b\u0441\u044b\u043d \u0431\u043e\u043b\u0434\u044b\u0440\u043c\u0430\u0443 \u043a\u0435\u043b\u0435\u0441\u0456 \u04af\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u04af\u0434\u0435\u0440\u0456\u0441\u0456\u043d\u0434\u0435 \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u0434\u0430\u043d \u04af\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0456\u043b\u0433\u0435\u043d \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u0436\u043e\u044e\u0493\u0430 \u04d9\u043a\u0435\u043b\u0435\u0434\u0456. \u0428\u044b\u043d\u044b\u043c\u0435\u043d \u043a\u0456\u0440\u0456\u0441\u0443 \u049b\u0430\u0436\u0435\u0442 \u043f\u0435?",
+ "CancelSyncJobConfirmation": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u0436\u04b1\u043c\u044b\u0441\u044b\u043d \u0431\u043e\u043b\u0434\u044b\u0440\u043c\u0430\u0443\u044b \u043a\u0435\u043b\u0435\u0441\u0456 \u04af\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u043f\u0440\u043e\u0446\u0435\u0441\u0456 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u0434\u0430\u043d \u04af\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0456\u043b\u0433\u0435\u043d \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u0436\u043e\u044f\u0434\u044b. \u0428\u044b\u043d\u044b\u043c\u0435\u043d \u043a\u0456\u0440\u0456\u0441\u0443 \u049b\u0430\u0436\u0435\u0442 \u043f\u0435?",
"TabSync": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443",
"MessagePleaseSelectDeviceToSyncTo": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0456\u043b\u0435\u0442\u0456\u043d \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u043d\u044b \u0442\u0430\u04a3\u0434\u0430\u04a3\u044b\u0437.",
"MessageSyncJobCreated": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u0436\u04b1\u043c\u044b\u0441\u044b \u0436\u0430\u0441\u0430\u043b\u0434\u044b.",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json
index 4da140d1d..92c83e8c7 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirmation",
"MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
"MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "Live TV",
"TitleSync": "Sync",
+ "ButtonDonate": "Donate",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "Notifications",
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -118,7 +123,7 @@
"LabelFree": "Free",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Select Audio",
@@ -174,6 +179,9 @@
"OptionThursday": "Thursday",
"OptionFriday": "Friday",
"OptionSaturday": "Saturday",
+ "OptionEveryday": "Every day",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Confirm Deletion",
"MessageConfirmPathSubstitutionDeletion": "Are you sure you wish to delete this path substitution?",
"LiveTvUpdateAvailable": "(Update available)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Split Media Apart",
"MessageConfirmSplitMedia": "Are you sure you wish to split the media sources into separate items?",
"HeaderError": "Error",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Please select at least one item.",
"MessagePleaseSelectTwoItems": "Please select at least two items.",
"MessageTheFollowingItemsWillBeGrouped": "The following titles will be grouped into one item:",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json
index b2c86d218..31c6ec66c 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Bekreftelse",
"MessageKeyUpdated": "Takk. Din supportern\u00f8kkel har blitt oppdatert.",
"MessageKeyRemoved": "Takk. Din supportern\u00f8kkel har blitt fjernet.",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "Live TV",
"TitleSync": "Synk",
+ "ButtonDonate": "Don\u00e9r",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "Beskjeder",
"ErrorLaunchingChromecast": "Det var en feil ved start av Chromecast. Vennligst forsikre deg om at enheten har korrekt forbindelse til ditt tr\u00e5dl\u00f8se nettverk.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -118,7 +123,7 @@
"LabelFree": "Gratis",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Velg Lyd",
@@ -174,6 +179,9 @@
"OptionThursday": "Torsdag",
"OptionFriday": "Fredag",
"OptionSaturday": "L\u00f8rdag",
+ "OptionEveryday": "Hver dag",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Bekreft Kansellering",
"MessageConfirmPathSubstitutionDeletion": "Er du sikker p\u00e5 at du vil slette sti erstatter?",
"LiveTvUpdateAvailable": "(Oppdatering tilgjengelig)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Del Media Fra Hverandre",
"MessageConfirmSplitMedia": "Er du sikker at du vil splitte mediakilden i separerte elementer?",
"HeaderError": "Feil",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Vennligst velg minst ett element.",
"MessagePleaseSelectTwoItems": "Vennligst velg minst to elementer.",
"MessageTheFollowingItemsWillBeGrouped": "F\u00f8lgende titler vil bli gruppert til ett element:",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json
index 3709b6bc2..d83de9d68 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Bevestiging",
"MessageKeyUpdated": "Dank u. Uw supporter sleutel is bijgewerkt.",
"MessageKeyRemoved": "Dank u. Uw supporter sleutel is verwijderd.",
+ "HeaderSupportTheTeam": "Ondersteun het Emby Team",
+ "TextEnjoyBonusFeatures": "Geniet van Bonus Features",
"TitleLiveTV": "Live TV",
"TitleSync": "Synchroniseer",
+ "ButtonDonate": "Doneren",
+ "HeaderMyMedia": "Mijn media",
+ "TitleNotifications": "Meldingen",
"ErrorLaunchingChromecast": "Er is een fout opgetreden bij het starten van chromecast. Zorg ervoor dat uw apparaat is aangesloten op uw draadloze netwerk.",
"MessageErrorLoadingSupporterInfo": "Er is een fout opgetreden bij het laden van uw supporter informatie. Probeer het later opnieuw.",
"MessageLinkYourSupporterKey": "Koppel uw supporters sleutel met maximaal {0} Emby Connect leden om te genieten van gratis toegang tot de volgende apps:",
@@ -119,8 +124,8 @@
"HeaderPlaybackError": "Afspeel Fout",
"MessagePlaybackErrorNotAllowed": "U bent niet bevoegd om deze content af te spelen. Neem contact op met uw systeembeheerder voor meer informatie.",
"MessagePlaybackErrorNoCompatibleStream": "Geen compatibele streams beschikbaar. Probeer het later opnieuw.",
- "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
- "MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
+ "MessagePlaybackErrorRateLimitExceeded": "Je afspeel rate limiet is overschreden. Neem contact op met de beheerder van de server voor details.",
+ "MessagePlaybackErrorPlaceHolder": "De gekozen content is niet af te spelen vanaf dit apparaat.",
"HeaderSelectAudio": "Selecteer Audio",
"HeaderSelectSubtitles": "Selecteer Ondertitels",
"ButtonMarkForRemoval": "Van apparaat verwijderen",
@@ -174,6 +179,9 @@
"OptionThursday": "Donderdag",
"OptionFriday": "Vrijdag",
"OptionSaturday": "Zaterdag",
+ "OptionEveryday": "Elke dag",
+ "OptionWeekend": "Weekenden",
+ "OptionWeekday": "Weekdagen",
"HeaderConfirmDeletion": "Bevestigen Verwijdering",
"MessageConfirmPathSubstitutionDeletion": "Weet u zeker dat u dit pad vervanging wilt verwijderen?",
"LiveTvUpdateAvailable": "(Update beschikbaar)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Splits Media Apart",
"MessageConfirmSplitMedia": "Weet u zeker dat u de media bronnen wilt splitsen in afzonderlijke items?",
"HeaderError": "Fout",
+ "MessageChromecastConnectionError": "Je Chromcast ontvanger kan niet met je Emby server verbinden. Controleer je verbindingen en probeer het opnieuw.",
"MessagePleaseSelectOneItem": "Selecteer ten minste een item.",
"MessagePleaseSelectTwoItems": "Selecteer ten minste twee items.",
"MessageTheFollowingItemsWillBeGrouped": "De volgende titels worden gegroepeerd in \u00e9\u00e9n item:",
@@ -526,9 +535,9 @@
"MessageInstallPluginFromApp": "Deze plugin moet ge\u00efnstalleerd worden vanuit de app waarin u het wilt gebruiken.",
"ValuePriceUSD": "Prijs {0} (USD)",
"MessageFeatureIncludedWithSupporter": "U bent geregistreerd voor deze functie, en zal deze kunnen blijven gebruiken met uw actieve supporter lidmaatschap.",
- "MessageChangeRecurringPlanConfirm": "After completing this transaction you will need to cancel your previous recurring donation from within your PayPal account. Thank you for supporting Emby.",
+ "MessageChangeRecurringPlanConfirm": "Na het voltooien van deze transactie zal je de eerdere terugkerende donatie in je PayPal account moeten annuleren. Bedankt voor de ondersteuning aan Emby.",
"MessageSupporterMembershipExpiredOn": "Uw supporter lidmaatschap is verlopen op {0}",
- "MessageYouHaveALifetimeMembership": "You have a lifetime supporter membership. You can provide additional donations on a one-time or recurring basis using the options below. Thank you for supporting Emby.",
+ "MessageYouHaveALifetimeMembership": "Je hebt een levenslang supporter lidmaatschap. Je kan eenmalige- en terugkerende donaties doen met onderstaande opties. Bedankt voor de ondersteuning aan Emby.",
"MessageYouHaveAnActiveRecurringMembership": "U hebt een actief {0} lidmaatschap. U kunt met de opties hieronder uw lidmaatschap upgraden.",
"ButtonDelete": "Verwijderen",
"HeaderEmbyAccountAdded": "Emby Account Toegevoegd",
@@ -666,12 +675,12 @@
"WebClientTourMetadataManager": "Klik wijzigen om de metadata manager te openen",
"WebClientTourPlaylists": "Maak eenvoudig een afspeellijst en mixlijst, en speel deze op elk apparaat",
"WebClientTourCollections": "Maak film Collecties door boxsets samen te voegen",
- "WebClientTourUserPreferences1": "User preferences allow you to customize the way your library is presented in all of your Emby apps",
- "WebClientTourUserPreferences2": "Configure your audio and subtitle language settings once, for every Emby app",
+ "WebClientTourUserPreferences1": "Met gebruikersvoorkeuren kan je de manier waarop je bibliotheek getoond wordt in alle Emby apps aanpassen",
+ "WebClientTourUserPreferences2": "Stel eenmalig je voorkeuren voor je audio- en ondertitelingstaal voor elke Emby app",
"WebClientTourUserPreferences3": "Ontwerp de startpagina van de web client volgens uw wensen",
"WebClientTourUserPreferences4": "Configureer achtergronden, theme songs en externe spelers",
"WebClientTourMobile1": "De web client werk perfect op smartphones en tablets...",
- "WebClientTourMobile2": "and easily controls other devices and Emby apps",
+ "WebClientTourMobile2": "en bedien eenvoudig je andere apparaten en Emby apps",
"WebClientTourMySync": "Synchroniseer je persoonlijke media naar je apparaten om het offline te bekijken.",
"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.",
@@ -683,7 +692,7 @@
"DashboardTourPlugins": "Installeer plugins zoals Internet videokanalen, live tv, metadata, scanners en meer.",
"DashboardTourNotifications": "Meldingen van de server gebeurtenissen automatisch verzenden naar uw mobiele apparaat, e-mail en meer.",
"DashboardTourScheduledTasks": "Beheer eenvoudig langlopende transacties met geplande taken. Beslis zelf wanneer ze worden uitgevoerd en hoe vaak.",
- "DashboardTourMobile": "The Emby Server dashboard works great on smartphones and tablets. Manage your server from the palm of your hand anytime, anywhere.",
+ "DashboardTourMobile": "Het Emby Server dashboard werkt goed op smartphones en tablets. Beheer je server in de palm van je hand, altijd en overal.",
"DashboardTourSync": "Synchroniseer je persoonlijke media naar je apparaten om het offline te bekijken.",
"MessageRefreshQueued": "Vernieuwen wachtrij",
"TabDevices": "Apparaten",
@@ -693,7 +702,7 @@
"DeleteDeviceConfirmation": "Weet u zeker dat u dit apparaat wilt verwijderen? Het zal opnieuw verschijnen als een gebruiker zich hiermee aanmeldt.",
"LabelEnableCameraUploadFor": "Schakel camera upload in voor:",
"HeaderSelectUploadPath": "Kies upload pad",
- "LabelEnableCameraUploadForHelp": "Uploads will occur automatically in the background when signed into Emby.",
+ "LabelEnableCameraUploadForHelp": "Uploads zullen automatisch op de achtergrond plaatsvinden wanneer bij Emby aangemeld is.",
"ErrorMessageStartHourGreaterThanEnd": "Eind tijd moet na de start tijd liggen.",
"ButtonLibraryAccess": "Bibliotheek toegang",
"ButtonParentalControl": "Ouderlijk toezicht",
@@ -717,11 +726,11 @@
"MessagePasswordResetForUsers": "Wachtwoorden zijn verwijderd van de volgende gebruikers:",
"HeaderInviteGuest": "Nodig gast uit",
"ButtonLinkMyEmbyAccount": "Koppel mijn account nu",
- "MessageConnectAccountRequiredToInviteGuest": "In order to invite guests you need to first link your Emby account to this server.",
+ "MessageConnectAccountRequiredToInviteGuest": "Om gasten uit te kunnen nodigen moet je je Emby account aan deze server koppelen.",
"ButtonSync": "Synchronisatie",
"SyncMedia": "Synchroniseer media",
"HeaderCancelSyncJob": "Annuleer synchronisatie",
- "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
+ "CancelSyncJobConfirmation": "Als je de synchroniseertaak annuleert wordt de gesynchroniseerde media bij de volgende synchroniseertaak van het apparaat verwijderd. Weet je zeker dat je door wilt gaan?",
"TabSync": "Synchronisatie",
"MessagePleaseSelectDeviceToSyncTo": "Selecteer een apparaat om mee te synchroniseren.",
"MessageSyncJobCreated": "Synchronisatie taak gemaakt.",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json
index da54b8c1d..6d15e132b 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirmation",
"MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
"MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "Live TV",
"TitleSync": "Sync",
+ "ButtonDonate": "Donate",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "Notifications",
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -118,7 +123,7 @@
"LabelFree": "Free",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Select Audio",
@@ -174,6 +179,9 @@
"OptionThursday": "Czwartek",
"OptionFriday": "Pi\u0105tek",
"OptionSaturday": "Sobota",
+ "OptionEveryday": "Every day",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Confirm Deletion",
"MessageConfirmPathSubstitutionDeletion": "Are you sure you wish to delete this path substitution?",
"LiveTvUpdateAvailable": "(Update available)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Split Media Apart",
"MessageConfirmSplitMedia": "Are you sure you wish to split the media sources into separate items?",
"HeaderError": "Error",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Please select at least one item.",
"MessagePleaseSelectTwoItems": "Please select at least two items.",
"MessageTheFollowingItemsWillBeGrouped": "The following titles will be grouped into one item:",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json
index 0f7e35454..7e9b1811d 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirma\u00e7\u00e3o",
"MessageKeyUpdated": "Obrigado. Sua chave de colaborador foi atualizada.",
"MessageKeyRemoved": "Obrigado. Sua chave de colaborador foi removida.",
+ "HeaderSupportTheTeam": "Colabore com o Time do Emby",
+ "TextEnjoyBonusFeatures": "Aproveite Funcionalidades Extras",
"TitleLiveTV": "TV ao Vivo",
"TitleSync": "Sinc",
+ "ButtonDonate": "Doar",
+ "HeaderMyMedia": "Minha M\u00eddia",
+ "TitleNotifications": "Notifica\u00e7\u00f5es",
"ErrorLaunchingChromecast": "Ocorreu um erro ao iniciar o chromecast. Por favor verifique se seu dispositivo est\u00e1 conectado \u00e0 sua rede sem fio.",
"MessageErrorLoadingSupporterInfo": "Ocorreu um erro ao carregar a informa\u00e7\u00e3o do colaborador. Por favor, tente novamente mais tarde.",
"MessageLinkYourSupporterKey": "Associe sua chave de colaborador com at\u00e9 {0} membros do Emby Connect para desfrutar acesso gr\u00e1tis \u00e0s seguintes apps:",
@@ -118,7 +123,7 @@
"LabelFree": "Gr\u00e1tis",
"HeaderPlaybackError": "Erro na Reprodu\u00e7\u00e3o",
"MessagePlaybackErrorNotAllowed": "Voc\u00ea n\u00e3o est\u00e1 autorizado a reproduzir este conte\u00fado. Por favor, entre em contato com o administrador do sistema para mais detalhes.",
- "MessagePlaybackErrorNoCompatibleStream": "N\u00e3o existem streams compat\u00edveis dispon\u00edveis. Por favor, tente novamente mais tarde.",
+ "MessagePlaybackErrorNoCompatibleStream": "N\u00e3o existem streams compat\u00edveis. Por favor, tente novamente mais tarde ou contate o administrador do sistema para mais detalhes.",
"MessagePlaybackErrorRateLimitExceeded": "Seu limite da taxa de reprodu\u00e7\u00e3o foi excedido. Por favor, entre em contato com o administrador do sistema para mais detalhes.",
"MessagePlaybackErrorPlaceHolder": "O conte\u00fado escolhido n\u00e3o \u00e9 reproduz\u00edvel neste dispositivo.",
"HeaderSelectAudio": "Selecione \u00c1udio",
@@ -174,6 +179,9 @@
"OptionThursday": "Quinta-feira",
"OptionFriday": "Sexta-feira",
"OptionSaturday": "S\u00e1bado",
+ "OptionEveryday": "Todos os dias",
+ "OptionWeekend": "Fins-de-semana",
+ "OptionWeekday": "Dias da semana",
"HeaderConfirmDeletion": "Confirmar Exclus\u00e3o",
"MessageConfirmPathSubstitutionDeletion": "Deseja realmente excluir esta substitui\u00e7\u00e3o de caminho?",
"LiveTvUpdateAvailable": "(Atualiza\u00e7\u00e3o dispon\u00edvel)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Separar M\u00eddia",
"MessageConfirmSplitMedia": "Deseja realmente dividir as fontes de m\u00eddia em itens separados?",
"HeaderError": "Erro",
+ "MessageChromecastConnectionError": "Seu receptor Chromecast n\u00e3o pode se conectar com seu Servidor Emby. Por favor, verifique suas conex\u00f5es e tente novamente.",
"MessagePleaseSelectOneItem": "Por favor selecione pelo menos um item.",
"MessagePleaseSelectTwoItems": "Por favor selecione pelo menos dois itens.",
"MessageTheFollowingItemsWillBeGrouped": "Os seguintes t\u00edtulos ser\u00e3o agrupados em um \u00fanico item:",
@@ -380,7 +389,7 @@
"ButtonMyPreferences": "Minhas Prefer\u00eancias",
"MessageBrowserDoesNotSupportWebSockets": "Este navegador n\u00e3o suporta web sockets. Para uma melhor experi\u00eancia, tente um navegador mais atual como o Chrome, Firefox, IE10+, Safari (iOS) ou Opera.",
"LabelInstallingPackage": "Instalando {0}",
- "LabelPackageInstallCompleted": "Instala\u00e7\u00e3o de {0} completa.",
+ "LabelPackageInstallCompleted": "Instala\u00e7\u00e3o de {0} conclu\u00edda.",
"LabelPackageInstallFailed": "Instala\u00e7\u00e3o de {0} falhou.",
"LabelPackageInstallCancelled": "Instala\u00e7\u00e3o de {0} cancelada.",
"TabServer": "Servidor",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json
index 6a1092c89..525bd440e 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirmation",
"MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
"MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "TV ao Vivo",
"TitleSync": "Sync",
+ "ButtonDonate": "Donate",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "Notifications",
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -79,7 +84,7 @@
"SyncJobStatusCompletedWithError": "Synced with errors",
"SyncJobItemStatusReadyToTransfer": "Ready to Transfer",
"LabelCollection": "Collection",
- "HeaderAddToCollection": "Add to Collection",
+ "HeaderAddToCollection": "Adicionar \u00e0 Cole\u00e7\u00e3o",
"NewCollectionNameExample": "Exemplo: Cole\u00e7\u00e3o Guerra das Estrelas",
"OptionSearchForInternetMetadata": "Procurar na internet por imagens e metadados",
"LabelSelectCollection": "Select collection:",
@@ -116,9 +121,9 @@
"LabelVersionInstalled": "{0} installed",
"LabelNumberReviews": "{0} Reviews",
"LabelFree": "Free",
- "HeaderPlaybackError": "Playback Error",
- "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "HeaderPlaybackError": "Erro na Reprodu\u00e7\u00e3o",
+ "MessagePlaybackErrorNotAllowed": "N\u00e3o est\u00e1 autorizado a reproduzir este conte\u00fado. Por favor, contacte o administrador do sistema para mais detalhes.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Select Audio",
@@ -174,6 +179,9 @@
"OptionThursday": "Quinta",
"OptionFriday": "Sexta",
"OptionSaturday": "S\u00e1bado",
+ "OptionEveryday": "Every day",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Confirm Deletion",
"MessageConfirmPathSubstitutionDeletion": "Are you sure you wish to delete this path substitution?",
"LiveTvUpdateAvailable": "(Update available)",
@@ -191,13 +199,14 @@
"HeaderSplitMedia": "Split Media Apart",
"MessageConfirmSplitMedia": "Are you sure you wish to split the media sources into separate items?",
"HeaderError": "Error",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Please select at least one item.",
"MessagePleaseSelectTwoItems": "Please select at least two items.",
"MessageTheFollowingItemsWillBeGrouped": "The following titles will be grouped into one item:",
"MessageConfirmItemGrouping": "Emby apps will automatically choose the optimal version to play based on device and network performance. Are you sure you wish to continue?",
"HeaderResume": "Resumir",
"HeaderMyViews": "My Views",
- "HeaderLibraryFolders": "Media Folders",
+ "HeaderLibraryFolders": "Pastas multim\u00e9dia",
"HeaderLatestMedia": "Latest Media",
"ButtonMoreItems": "More...",
"ButtonMore": "More",
@@ -385,7 +394,7 @@
"LabelPackageInstallCancelled": "{0} installation cancelled.",
"TabServer": "Servidor",
"TabUsers": "Users",
- "TabLibrary": "Library",
+ "TabLibrary": "Biblioteca",
"TabMetadata": "Metadados",
"TabDLNA": "DLNA",
"TabLiveTV": "Live TV",
@@ -648,7 +657,7 @@
"MediaInfoStreamTypeSubtitle": "Subtitle",
"MediaInfoStreamTypeEmbeddedImage": "Embedded Image",
"MediaInfoRefFrames": "Ref frames",
- "TabPlayback": "Playback",
+ "TabPlayback": "Reprodu\u00e7\u00e3o",
"TabNotifications": "Notifica\u00e7\u00f5es",
"TabExpert": "Expert",
"HeaderSelectCustomIntrosPath": "Select Custom Intros Path",
@@ -677,7 +686,7 @@
"DashboardTourDashboard": "O Painel Principal do servidor permite monitorizar o seu servidor e os seus utilizadores. Poder\u00e1 sempre saber onde est\u00e3o e o que est\u00e3o a fazer.",
"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.",
+ "DashboardTourCinemaMode": "O modo cinema traz a experi\u00eancia do cinema para a sua sala, possibilitando reproduzir trailers e introdu\u00e7\u00f5es personalizadas antes da longa-metragem.",
"DashboardTourChapters": "Enable chapter image generation for your videos for a more pleasing presentation while viewing.",
"DashboardTourSubtitles": "Automatically download subtitles for your videos in any language.",
"DashboardTourPlugins": "Install plugins such as internet video channels, live tv, metadata scanners, and more.",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json
index 4718e8930..7a1fc5115 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435",
"MessageKeyUpdated": "\u041a\u043b\u044e\u0447 \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430 \u0431\u044b\u043b \u043e\u0431\u043d\u043e\u0432\u043b\u0451\u043d.",
"MessageKeyRemoved": "\u041a\u043b\u044e\u0447 \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430 \u0431\u044b\u043b \u0443\u0434\u0430\u043b\u0451\u043d.",
+ "HeaderSupportTheTeam": "\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0442\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 Emby",
+ "TextEnjoyBonusFeatures": "\u0412\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435\u0441\u044c \u0431\u043e\u043d\u0443\u0441\u043d\u044b\u043c\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438",
"TitleLiveTV": "\u0422\u0412-\u044d\u0444\u0438\u0440",
"TitleSync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f",
+ "ButtonDonate": "\u041f\u043e\u0436\u0435\u0440\u0442\u0432\u043e\u0432\u0430\u0442\u044c",
+ "HeaderMyMedia": "\u041c\u043e\u0438 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435",
+ "TitleNotifications": "\u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f",
"ErrorLaunchingChromecast": "\u041f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 Chromecast. \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0432\u0430\u0448\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043e \u043a \u0431\u0435\u0441\u043f\u0440\u043e\u0432\u043e\u0434\u043d\u043e\u0439 \u0441\u0435\u0442\u0438.",
"MessageErrorLoadingSupporterInfo": "\u041f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0435. \u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443 \u043f\u043e\u0437\u0436\u0435.",
"MessageLinkYourSupporterKey": "\u0421\u0432\u044f\u0436\u0438\u0442\u0435 \u0432\u0430\u0448 \u043a\u043b\u044e\u0447 \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430 \u0441\u043e \u0432\u043f\u043b\u043e\u0442\u044c \u0434\u043e {0} \u0447\u043b\u0435\u043d\u043e\u0432 Emby Connect, \u0447\u0442\u043e\u0431\u044b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c \u043a \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c:",
@@ -66,7 +71,7 @@
"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": "\u041a \u0441\u043f\u0440\u0430\u0432\u043a\u0435",
+ "ButtonHelp": "\u041a \u0441\u043f\u0440\u0430\u0432\u043a\u0435 \u0432 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435",
"ButtonSave": "\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c",
"ButtonDownload": "\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c",
"SyncJobStatusQueued": "\u0412 \u043e\u0447\u0435\u0440\u0435\u0434\u0438",
@@ -81,7 +86,7 @@
"LabelCollection": "\u041a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f",
"HeaderAddToCollection": "\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u043e \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438",
"NewCollectionNameExample": "\u041f\u0440\u0438\u043c\u0435\u0440: \u0417\u0432\u0451\u0437\u0434\u043d\u044b\u0435 \u0432\u043e\u0439\u043d\u044b (\u041a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f)",
- "OptionSearchForInternetMetadata": "\u0418\u0441\u043a\u0430\u0442\u044c \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0438 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435",
+ "OptionSearchForInternetMetadata": "\u0418\u0441\u043a\u0430\u0442\u044c \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0438 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435",
"LabelSelectCollection": "\u0412\u044b\u0431\u043e\u0440 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438:",
"HeaderDevices": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430",
"ButtonScheduledTasks": "\u041a \u041f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0449\u0438\u043a\u0443",
@@ -89,7 +94,7 @@
"ButtonAddToCollection": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043a\u043e \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438",
"HeaderSelectCertificatePath": "\u0412\u044b\u0431\u043e\u0440 \u043f\u0443\u0442\u0438 \u043a \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u0443",
"ConfirmMessageScheduledTaskButton": "\u042d\u0442\u0430 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043e\u0431\u044b\u0447\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043a\u0430\u043a \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430. \u042d\u0442\u043e \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043e \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u043e\u0442\u0441\u044e\u0434\u0430. \u0427\u0442\u043e\u0431\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443, \u0441\u043c.:",
- "HeaderSupporterBenefit": "\u0427\u043b\u0435\u043d\u0441\u0442\u0432\u043e \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438, \u043f\u0440\u0435\u043c\u0438\u0430\u043b\u044c\u043d\u044b\u043c \u043f\u043b\u0430\u0433\u0438\u043d\u0430\u043c, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044e \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043a\u0430\u043d\u0430\u043b\u043e\u0432 \u0438 \u043c\u043d\u043e\u0433\u043e\u043c\u0443 \u0434\u0440\u0443\u0433\u043e\u043c\u0443. {0}\u0423\u0437\u043d\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435{1}.",
+ "HeaderSupporterBenefit": "\u0427\u043b\u0435\u043d\u0441\u0442\u0432\u043e \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438, \u043f\u0440\u0435\u043c\u0438\u0430\u043b\u044c\u043d\u044b\u043c \u043f\u043b\u0430\u0433\u0438\u043d\u0430\u043c, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044e \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043a\u0430\u043d\u0430\u043b\u043e\u0432 \u0438 \u0442.\u0434. {0}\u0423\u0437\u043d\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435{1}.",
"LabelSyncNoTargetsHelp": "\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0449\u0438\u0445 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044e, \u043d\u0435 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u043e.",
"HeaderWelcomeToProjectServerDashboard": "\u041f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u043c \u0432 \u0418\u043d\u0444\u043e\u043f\u0430\u043d\u0435\u043b\u0438 Emby Server",
"HeaderWelcomeToProjectWebClient": "\u0412\u0435\u0431-\u043a\u043b\u0438\u0435\u043d\u0442 Emby \u043f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432\u0430\u0441!",
@@ -117,10 +122,10 @@
"LabelNumberReviews": "\u041e\u0442\u0437\u044b\u0432\u044b: {0}",
"LabelFree": "\u0411\u0435\u0441\u043f\u043b.",
"HeaderPlaybackError": "\u041e\u0448\u0438\u0431\u043a\u0430 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f",
- "MessagePlaybackErrorNotAllowed": "\u0412 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u044b \u043d\u0435 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u044b \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f. \u0414\u043b\u044f \u0434\u0435\u0442\u0430\u043b\u0435\u0439 \u0441\u0432\u044f\u0436\u0438\u0442\u0435\u0441\u044c \u0441 \u0432\u0430\u0448\u0438\u043c \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u043c \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u043c.",
- "MessagePlaybackErrorNoCompatibleStream": "\u0412 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432. \u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443 \u043f\u043e\u0437\u0436\u0435.",
- "MessagePlaybackErrorRateLimitExceeded": "\u0412\u0430\u0448\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0431\u044b\u043b\u0430 \u043f\u0440\u0435\u0432\u044b\u0448\u0435\u043d\u0430. \u0414\u043b\u044f \u0434\u0435\u0442\u0430\u043b\u0435\u0439 \u0441\u0432\u044f\u0436\u0438\u0442\u0435\u0441\u044c \u0441 \u0432\u0430\u0448\u0438\u043c \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u043c \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u043c.",
- "MessagePlaybackErrorPlaceHolder": "\u0412\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u043d\u0435 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0441 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430.",
+ "MessagePlaybackErrorNotAllowed": "\u0412 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u044b \u043d\u0435 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u044b \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f. \u0417\u0430 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u044f\u043c\u0438 \u0441\u0432\u044f\u0436\u0438\u0442\u0435\u0441\u044c \u0441 \u0432\u0430\u0448\u0438\u043c \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u043c \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u043c.",
+ "MessagePlaybackErrorNoCompatibleStream": "\u0412 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432. \u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443 \u043f\u043e\u0437\u0436\u0435 \u0438\u043b\u0438 \u0437\u0430 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u044f\u043c\u0438 \u0441\u0432\u044f\u0436\u0438\u0442\u0435\u0441\u044c \u0441 \u0432\u0430\u0448\u0438\u043c \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u043c \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u043c.",
+ "MessagePlaybackErrorRateLimitExceeded": "\u0412\u0430\u0448\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0431\u044b\u043b\u0430 \u043f\u0440\u0435\u0432\u044b\u0448\u0435\u043d\u0430. \u0417\u0430 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u044f\u043c\u0438 \u0441\u0432\u044f\u0436\u0438\u0442\u0435\u0441\u044c \u0441 \u0432\u0430\u0448\u0438\u043c \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u043c \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u043c.",
+ "MessagePlaybackErrorPlaceHolder": "\u0412\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u043d\u0435\u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u043c\u043e \u0441 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430.",
"HeaderSelectAudio": "\u0412\u044b\u0431\u043e\u0440 \u0430\u0443\u0434\u0438\u043e",
"HeaderSelectSubtitles": "\u0412\u044b\u0431\u043e\u0440 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432",
"ButtonMarkForRemoval": "\u0418\u0437\u044a\u044f\u0442\u044c \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430",
@@ -174,6 +179,9 @@
"OptionThursday": "\u0447\u0435\u0442\u0432\u0435\u0440\u0433",
"OptionFriday": "\u043f\u044f\u0442\u043d\u0438\u0446\u0430",
"OptionSaturday": "\u0441\u0443\u0431\u0431\u043e\u0442\u0430",
+ "OptionEveryday": "\u0415\u0436\u0435\u0434\u043d\u0435\u0432\u043d\u043e",
+ "OptionWeekend": "\u0412\u044b\u0445\u043e\u0434\u043d\u044b\u0435",
+ "OptionWeekday": "\u0414\u043d\u0438 \u043d\u0435\u0434\u0435\u043b\u0438",
"HeaderConfirmDeletion": "\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f",
"MessageConfirmPathSubstitutionDeletion": "\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\u0443\u044e \u043f\u043e\u0434\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 \u043f\u0443\u0442\u0438?",
"LiveTvUpdateAvailable": "(\u0418\u043c\u0435\u0435\u0442\u0441\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435)",
@@ -191,11 +199,12 @@
"HeaderSplitMedia": "\u0420\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u0435 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0432\u0440\u043e\u0437\u044c",
"MessageConfirmSplitMedia": "\u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u0440\u0430\u0437\u0431\u0438\u0442\u044c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c?",
"HeaderError": "\u041e\u0448\u0438\u0431\u043a\u0430",
+ "MessageChromecastConnectionError": "\u041f\u0440\u0438\u0435\u043c\u043d\u0438\u043a Chromecast \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0434\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u044c\u0441\u044f \u043a Emby Server. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0438\u0445 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443 \u043f\u043e\u0437\u0436\u0435.",
"MessagePleaseSelectOneItem": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0445\u043e\u0442\u044f \u0431\u044b \u043e\u0434\u0438\u043d \u044d\u043b\u0435\u043c\u0435\u043d\u0442.",
"MessagePleaseSelectTwoItems": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0445\u043e\u0442\u044f \u0431\u044b \u0434\u0432\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430.",
"MessageTheFollowingItemsWillBeGrouped": "\u0412 \u0435\u0434\u0438\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0431\u0443\u0434\u0443\u0442 \u0441\u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f :",
"MessageConfirmItemGrouping": "\u0412 Emby-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u0431\u0443\u0434\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c\u0441\u044f \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u0434\u043b\u044f \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0441\u0435\u0442\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?",
- "HeaderResume": "\u0412\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u0438\u043c\u044b\u0435",
+ "HeaderResume": "\u0412\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u0438\u043c\u043e\u0435",
"HeaderMyViews": "\u041c\u043e\u0438 \u0430\u0441\u043f\u0435\u043a\u0442\u044b",
"HeaderLibraryFolders": "\u041c\u0435\u0434\u0438\u0430\u043f\u0430\u043f\u043a\u0438",
"HeaderLatestMedia": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435",
@@ -287,7 +296,7 @@
"HeaderVideoQuality": "\u041a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u0432\u0438\u0434\u0435\u043e",
"MessageErrorPlayingVideo": "\u041f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0438 \u0432\u0438\u0434\u0435\u043e.",
"MessageEnsureOpenTuner": "\u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0439 \u0442\u044e\u043d\u0435\u0440.",
- "ButtonHome": "\u041a \u0433\u043b\u0430\u0432\u043d\u043e\u043c\u0443",
+ "ButtonHome": "\u041a\u043e \u0433\u043b\u0430\u0432\u043d\u043e\u043c\u0443",
"ButtonDashboard": "\u041a \u0418\u043d\u0444\u043e\u043f\u0430\u043d\u0435\u043b\u0438",
"ButtonReports": "\u041a \u043e\u0442\u0447\u0451\u0442\u0430\u043c",
"ButtonMetadataManager": "\u041a \u0414\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u0443 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445",
@@ -659,7 +668,7 @@
"LabelFullReview": "\u041e\u0442\u0437\u044b\u0432 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e:",
"LabelShortRatingDescription": "\u041a\u0440\u0430\u0442\u043a\u0430\u044f \u0441\u0432\u043e\u0434\u043a\u0430 \u043e\u0446\u0435\u043d\u043a\u0438:",
"OptionIRecommendThisItem": "\u042f \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u044d\u0442\u043e\u0442 \u044d\u043b\u0435\u043c\u0435\u043d\u0442",
- "WebClientTourContent": "\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 \u0441\u0432\u043e\u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435, \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u044d\u043f\u0438\u0437\u043e\u0434\u044b \u0438 \u0442.\u043f. \u0417\u0435\u043b\u0435\u043d\u044b\u0435 \u043a\u0440\u0443\u0436\u043e\u0447\u043a\u0438 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443 \u0432\u0430\u0441 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043d\u0435\u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0451\u043d\u043d\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432.",
+ "WebClientTourContent": "\u0421\u043c\u043e\u0442\u0440\u0438\u0442\u0435 \u0441\u0432\u043e\u0438 \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435, \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u044d\u043f\u0438\u0437\u043e\u0434\u044b \u0438 \u0442.\u0434. \u0417\u0435\u043b\u0451\u043d\u044b\u0435 \u043a\u0440\u0443\u0436\u043e\u0447\u043a\u0438 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443 \u0432\u0430\u0441 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043d\u0435\u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0451\u043d\u043d\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432.",
"WebClientTourMovies": "\u0412\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435 \u0444\u0438\u043b\u044c\u043c\u044b, \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u044b \u0438 \u0442.\u043f., \u0441 \u043b\u044e\u0431\u043e\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0438\u043c\u0435\u044e\u0449\u0435\u0433\u043e \u0432\u0435\u0431-\u0431\u0440\u0430\u0443\u0437\u0435\u0440.",
"WebClientTourMouseOver": "\u0417\u0430\u0434\u0435\u0440\u0436\u0438\u0442\u0435 \u043a\u0443\u0440\u0441\u043e\u0440 \u043c\u044b\u0448\u0438 \u043d\u0430\u0434 \u043b\u044e\u0431\u044b\u043c \u043f\u043e\u0441\u0442\u0435\u0440\u043e\u043c \u0434\u043b\u044f \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0432\u0430\u0436\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438",
"WebClientTourTapHold": "\u041a\u043e\u0441\u043d\u0438\u0442\u0435\u0441\u044c \u0438 \u0443\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0439\u0442\u0435 \u0438\u043b\u0438 \u0449\u0435\u043b\u043a\u043d\u0438\u0442\u0435 \u043f\u0440\u0430\u0432\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u043e\u0439 \u043c\u044b\u0448\u0438 \u043f\u043e \u043b\u044e\u0431\u043e\u043c\u0443 \u043f\u043e\u0441\u0442\u0435\u0440\u0443 \u0434\u043b\u044f \u0432\u044b\u0437\u043e\u0432\u0430 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0433\u043e \u043c\u0435\u043d\u044e",
@@ -667,7 +676,7 @@
"WebClientTourPlaylists": "\u0421\u0432\u043e\u0431\u043e\u0434\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u043f\u0438\u0441\u043a\u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0438 \u0430\u0432\u0442\u043e\u043c\u0438\u043a\u0441\u044b, \u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435 \u0438\u0445 \u043d\u0430 \u043b\u044e\u0431\u043e\u043c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435",
"WebClientTourCollections": "\u0421\u043e\u0437\u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 \u0444\u0438\u043b\u044c\u043c\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u0441\u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0432\u043c\u0435\u0441\u0442\u0435",
"WebClientTourUserPreferences1": "\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0441\u043f\u043e\u0441\u043e\u0431, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0432\u0430\u0448\u0430 \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u0432\u043e \u0432\u0441\u0435\u0445 \u0432\u0430\u0448\u0438\u0445 Emby-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445.",
- "WebClientTourUserPreferences2": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u0442\u0435 \u0441\u0432\u043e\u0438\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u044f\u0437\u044b\u043a\u043e\u0432 \u0430\u0443\u0434\u0438\u043e \u0438 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432 \u0435\u0434\u0438\u043d\u043e\u0436\u0434\u044b, \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e Emby-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f",
+ "WebClientTourUserPreferences2": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u0442\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0430\u0443\u0434\u0438\u043e \u0438 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432 \u0441\u0432\u043e\u0435\u0433\u043e \u044f\u0437\u044b\u043a\u0430 \u0435\u0434\u0438\u043d\u043e\u0436\u0434\u044b, \u0434\u043b\u044f \u0432\u0441\u044f\u043a\u043e\u0433\u043e Emby-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f",
"WebClientTourUserPreferences3": "\u041e\u0444\u043e\u0440\u044c\u043c\u0442\u0435 \u0433\u043b\u0430\u0432\u043d\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0432\u0435\u0431-\u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043f\u043e \u0441\u0432\u043e\u0438\u043c \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0435\u043d\u0438\u044f\u043c",
"WebClientTourUserPreferences4": "\u041d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u0435 \u0437\u0430\u0434\u043d\u0438\u043a\u0438, \u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043c\u0435\u043b\u043e\u0434\u0438\u0438 \u0438 \u0432\u043d\u0435\u0448\u043d\u0438\u0435 \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0442\u0435\u043b\u0438",
"WebClientTourMobile1": "\u0412\u0435\u0431-\u043a\u043b\u0438\u0435\u043d\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u043d\u0430 \u0441\u043c\u0430\u0440\u0442\u0444\u043e\u043d\u0430\u0445 \u0438 \u043f\u043b\u0430\u043d\u0448\u0435\u0442\u0430\u0445...",
@@ -678,12 +687,12 @@
"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\u043e \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.",
+ "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\u0433\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430.",
"DashboardTourSubtitles": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0439\u0442\u0435 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044b \u0434\u043b\u044f \u0432\u0438\u0434\u0435\u043e \u043d\u0430 \u043b\u044e\u0431\u043e\u043c \u044f\u0437\u044b\u043a\u0435.",
- "DashboardTourPlugins": "\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0439\u0442\u0435 \u043f\u043b\u0430\u0433\u0438\u043d\u044b, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043a\u0430\u043d\u0430\u043b\u043e\u0432 \u0432\u0438\u0434\u0435\u043e, \u0422\u0412-\u044d\u0444\u0438\u0440\u0430, \u0441\u043a\u0430\u043d\u043d\u0435\u0440\u043e\u0432 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0442.\u043f.",
- "DashboardTourNotifications": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043e \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u044f\u0445 \u043d\u0430 \u0432\u0430\u0448\u0435 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430, \u044d-\u043f\u043e\u0447\u0442\u0443 \u0438 \u0442.\u043f.",
+ "DashboardTourPlugins": "\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0439\u0442\u0435 \u043f\u043b\u0430\u0433\u0438\u043d\u044b, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043a\u0430\u043d\u0430\u043b\u043e\u0432 \u0432\u0438\u0434\u0435\u043e, \u0422\u0412-\u044d\u0444\u0438\u0440\u0430, \u0441\u043a\u0430\u043d\u043d\u0435\u0440\u043e\u0432 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0442.\u0434.",
+ "DashboardTourNotifications": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043e \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u044f\u0445 \u043d\u0430 \u0432\u0430\u0448\u0435 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430, \u044d-\u043f\u043e\u0447\u0442\u0443 \u0438 \u0442.\u0434.",
"DashboardTourScheduledTasks": "\u0421\u0432\u043e\u0431\u043e\u0434\u043d\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0439\u0442\u0435 \u0434\u043e\u043b\u0433\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f\u043c\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447. \u041f\u0440\u0438\u043d\u0438\u043c\u0430\u0439\u0442\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043a\u043e\u0433\u0434\u0430 \u043e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f, \u0438 \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0447\u0430\u0441\u0442\u043e.",
- "DashboardTourMobile": "\u0418\u043d\u0444\u043e\u043f\u0430\u043d\u0435\u043b\u044c Emby Server \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0437\u0430\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0430 \u0441\u043c\u0430\u0440\u0442\u0444\u043e\u043d\u0430\u0445 \u0438 \u043f\u043b\u0430\u043d\u0448\u0435\u0442\u0430\u0445. \u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0439\u0442\u0435 \u0432\u0430\u0448\u0438\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u0441 \u043d\u0430\u043b\u0430\u0434\u043e\u043d\u043d\u0438\u043a\u0430 \u0432 \u0441\u0432\u043e\u0435\u0439 \u0440\u0443\u043a\u0435 \u0432 \u043b\u044e\u0431\u043e\u0435 \u0432\u0440\u0435\u043c\u044f, \u043d\u0430 \u043b\u044e\u0431\u043e\u043c \u043c\u0435\u0441\u0442\u0435.",
+ "DashboardTourMobile": "\u0418\u043d\u0444\u043e\u043f\u0430\u043d\u0435\u043b\u044c Emby Server \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0437\u0430\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0430 \u0441\u043c\u0430\u0440\u0442\u0444\u043e\u043d\u0430\u0445 \u0438 \u043f\u043b\u0430\u043d\u0448\u0435\u0442\u0430\u0445. \u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0439\u0442\u0435 \u0441\u0432\u043e\u0438\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u0441 \u043b\u0430\u0434\u043e\u043d\u0438 \u0432 \u043b\u044e\u0431\u043e\u0435 \u0432\u0440\u0435\u043c\u044f, \u0441 \u043b\u044e\u0431\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u0430.",
"DashboardTourSync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u0443\u0439\u0442\u0435 \u0441\u0432\u043e\u0438 \u043b\u0438\u0447\u043d\u044b\u0435 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0441 \u0432\u0430\u0448\u0438\u043c\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438 \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043d\u043e\u043c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430.",
"MessageRefreshQueued": "\u041f\u043e\u0434\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u0438",
"TabDevices": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430",
@@ -693,7 +702,7 @@
"DeleteDeviceConfirmation": "\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\u043e\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e? \u041e\u043d\u043e \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u0441\u043d\u043e\u0432\u0430 \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u043e\u0439\u0434\u0451\u0442 \u0441 \u043d\u0435\u0433\u043e.",
"LabelEnableCameraUploadFor": "\u0412\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0432\u044b\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u043d\u0438\u044f \u0441 \u043a\u0430\u043c\u0435\u0440\u044b \u0434\u043b\u044f:",
"HeaderSelectUploadPath": "\u0412\u044b\u0431\u043e\u0440 \u043f\u0443\u0442\u0438 \u0432\u044b\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0435\u043c\u043e\u0433\u043e",
- "LabelEnableCameraUploadForHelp": "\u0412\u044b\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0443\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432 \u0444\u043e\u043d\u043e\u0432\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435, \u043f\u0440\u0438 \u0432\u0445\u043e\u0434\u0435 \u0432 Emby.",
+ "LabelEnableCameraUploadForHelp": "\u0412\u044b\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0443\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u043e \u0444\u043e\u043d\u043e\u0432\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435, \u043f\u0440\u0438 \u0432\u0445\u043e\u0434\u0435 \u0432 Emby.",
"ErrorMessageStartHourGreaterThanEnd": "\u041a\u043e\u043d\u0435\u0447\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043f\u043e\u0437\u0436\u0435, \u0447\u0435\u043c \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f.",
"ButtonLibraryAccess": "\u041a \u0434\u043e\u0441\u0442\u0443\u043f\u0443 \u043a \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0435",
"ButtonParentalControl": "\u041a \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435\u043c",
@@ -719,7 +728,7 @@
"ButtonLinkMyEmbyAccount": "\u0421\u0432\u044f\u0437\u0430\u0442\u044c \u043c\u043e\u044e \u0443\u0447\u0451\u0442\u043d\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c",
"MessageConnectAccountRequiredToInviteGuest": "\u0427\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u0433\u043b\u0430\u0448\u0430\u0442\u044c \u0433\u043e\u0441\u0442\u0435\u0439, \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0432\u044f\u0437\u0430\u0442\u044c \u0432\u0430\u0448\u0443 \u0443\u0447\u0451\u0442\u043d\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c Emby \u0441 \u0434\u0430\u043d\u043d\u044b\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c.",
"ButtonSync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c",
- "SyncMedia": "\u0421\u0438\u043d\u0445\u0440-\u0438\u044f",
+ "SyncMedia": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f",
"HeaderCancelSyncJob": "\u041e\u0442\u043c\u0435\u043d\u0430 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438",
"CancelSyncJobConfirmation": "\u041e\u0442\u043c\u0435\u043d\u0430 \u0437\u0430\u0434\u0430\u043d\u0438\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u0442 \u043a \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044e \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438. \u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c?",
"TabSync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f",
@@ -741,10 +750,10 @@
"SyncJobItemStatusQueued": "\u0412 \u043e\u0447\u0435\u0440\u0435\u0434\u0438",
"SyncJobItemStatusConverting": "\u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442\u0441\u044f",
"SyncJobItemStatusTransferring": "\u041f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u0442\u0441\u044f",
- "SyncJobItemStatusSynced": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043e",
+ "SyncJobItemStatusSynced": "\u0421\u0438\u043d\u0445\u0440-\u043d\u043e",
"SyncJobItemStatusFailed": "\u041d\u0435\u0443\u0434\u0430\u0447\u043d\u043e",
"SyncJobItemStatusRemovedFromDevice": "\u0418\u0437\u044a\u044f\u0442\u043e \u0438\u0437 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430",
"SyncJobItemStatusCancelled": "\u041e\u0442\u043c\u0435\u043d\u0435\u043d\u043e",
"LabelProfile": "\u041f\u0440\u043e\u0444\u0438\u043b\u044c:",
- "LabelBitrateMbps": "\u041f\u043e\u0442\u043e\u043a\u043e\u0432\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c (\u041c\u0431\u0438\u0442\/\u0441):"
+ "LabelBitrateMbps": "\u041f\u043e\u0442\u043e\u043a\u043e\u0432\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c, \u041c\u0431\u0438\u0442\/\u0441:"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/sl_SI.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/sl_SI.json
index 16df937c9..0dd275cd5 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/sl_SI.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/sl_SI.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirmation",
"MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
"MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "Live TV",
"TitleSync": "Sync",
+ "ButtonDonate": "Donate",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "Notifications",
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -118,7 +123,7 @@
"LabelFree": "Free",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Select Audio",
@@ -174,6 +179,9 @@
"OptionThursday": "Thursday",
"OptionFriday": "Friday",
"OptionSaturday": "Saturday",
+ "OptionEveryday": "Every day",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Confirm Deletion",
"MessageConfirmPathSubstitutionDeletion": "Are you sure you wish to delete this path substitution?",
"LiveTvUpdateAvailable": "(Update available)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Split Media Apart",
"MessageConfirmSplitMedia": "Are you sure you wish to split the media sources into separate items?",
"HeaderError": "Error",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Please select at least one item.",
"MessagePleaseSelectTwoItems": "Please select at least two items.",
"MessageTheFollowingItemsWillBeGrouped": "The following titles will be grouped into one item:",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json
index 458890307..182d21653 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Bekr\u00e4ftelse",
"MessageKeyUpdated": "Tack. Din donationskod har uppdaterats.",
"MessageKeyRemoved": "Tack. Din donationskod har raderats.",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "Live-TV",
"TitleSync": "Sync",
+ "ButtonDonate": "Donera",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "Notifications",
"ErrorLaunchingChromecast": "Det gick inte att starta Chromecast. Kontrollera att enheten \u00e4r ansluten till det tr\u00e5dl\u00f6sa n\u00e4tverket.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -118,7 +123,7 @@
"LabelFree": "Gratis",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "V\u00e4lj ljudsp\u00e5r",
@@ -174,6 +179,9 @@
"OptionThursday": "Torsdag",
"OptionFriday": "Fredag",
"OptionSaturday": "L\u00f6rdag",
+ "OptionEveryday": "Varje dag",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Bekr\u00e4fta radering",
"MessageConfirmPathSubstitutionDeletion": "Vill du verkligen ta bort detta s\u00f6kv\u00e4gsutbyte?",
"LiveTvUpdateAvailable": "(Uppdatering tillg\u00e4nglig)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Dela upp media",
"MessageConfirmSplitMedia": "\u00c4r du s\u00e4ker p\u00e5 att du vill dela upp dessa media i separata objekt?",
"HeaderError": "Fel",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Var god v\u00e4lj minst ett objekt.",
"MessagePleaseSelectTwoItems": "Var god v\u00e4lj minst tv\u00e5 objekt.",
"MessageTheFollowingItemsWillBeGrouped": "F\u00f6ljande titlar kommer att grupperas till ett enda objekt:",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json
index 2e2f58a77..f52e9a425 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirmation",
"MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
"MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "Canl\u0131 TV",
"TitleSync": "Sync",
+ "ButtonDonate": "Donate",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "Notifications",
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -118,7 +123,7 @@
"LabelFree": "Free",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Select Audio",
@@ -174,6 +179,9 @@
"OptionThursday": "Per\u015fembe",
"OptionFriday": "Cuma",
"OptionSaturday": "Cumartesi",
+ "OptionEveryday": "Every day",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Confirm Deletion",
"MessageConfirmPathSubstitutionDeletion": "Are you sure you wish to delete this path substitution?",
"LiveTvUpdateAvailable": "(Update available)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Split Media Apart",
"MessageConfirmSplitMedia": "Are you sure you wish to split the media sources into separate items?",
"HeaderError": "Error",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Please select at least one item.",
"MessagePleaseSelectTwoItems": "Please select at least two items.",
"MessageTheFollowingItemsWillBeGrouped": "The following titles will be grouped into one item:",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/uk.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/uk.json
index 9a8f4b57a..b15a0005f 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/uk.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/uk.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirmation",
"MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
"MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "Live TV",
"TitleSync": "Sync",
+ "ButtonDonate": "Donate",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "\u041f\u043e\u0432\u0456\u0434\u043e\u043c\u043b\u0435\u043d\u043d\u044f",
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -118,7 +123,7 @@
"LabelFree": "Free",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Select Audio",
@@ -174,6 +179,9 @@
"OptionThursday": "Thursday",
"OptionFriday": "Friday",
"OptionSaturday": "Saturday",
+ "OptionEveryday": "Every day",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Confirm Deletion",
"MessageConfirmPathSubstitutionDeletion": "Are you sure you wish to delete this path substitution?",
"LiveTvUpdateAvailable": "(Update available)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Split Media Apart",
"MessageConfirmSplitMedia": "Are you sure you wish to split the media sources into separate items?",
"HeaderError": "Error",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Please select at least one item.",
"MessagePleaseSelectTwoItems": "Please select at least two items.",
"MessageTheFollowingItemsWillBeGrouped": "The following titles will be grouped into one item:",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json
index 71e353329..b449590a6 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirmation",
"MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
"MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "Live TV",
"TitleSync": "Sync",
+ "ButtonDonate": "Donate",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "Notifications",
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -118,7 +123,7 @@
"LabelFree": "Free",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Select Audio",
@@ -174,6 +179,9 @@
"OptionThursday": "Thursday",
"OptionFriday": "Friday",
"OptionSaturday": "Th\u1ee9 B\u1ea3y",
+ "OptionEveryday": "Every day",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Confirm Deletion",
"MessageConfirmPathSubstitutionDeletion": "Are you sure you wish to delete this path substitution?",
"LiveTvUpdateAvailable": "(Update available)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Split Media Apart",
"MessageConfirmSplitMedia": "Are you sure you wish to split the media sources into separate items?",
"HeaderError": "Error",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Please select at least one item.",
"MessagePleaseSelectTwoItems": "Please select at least two items.",
"MessageTheFollowingItemsWillBeGrouped": "The following titles will be grouped into one item:",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_CN.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_CN.json
index bfa2b3e24..2a29a8f49 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_CN.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_CN.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "\u786e\u8ba4",
"MessageKeyUpdated": "\u8c22\u8c22\u3002\u4f60\u7684\u652f\u6301\u8005\u5e8f\u53f7\u5df2\u66f4\u65b0\u3002",
"MessageKeyRemoved": "\u8c22\u8c22\u3002\u4f60\u7684\u652f\u6301\u8005\u5e8f\u53f7\u5df2\u79fb\u9664\u3002",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "\u4eab\u53d7\u5956\u52b1\u529f\u80fd",
"TitleLiveTV": "\u7535\u89c6\u76f4\u64ad",
"TitleSync": "\u540c\u6b65",
+ "ButtonDonate": "\u6350\u8d60",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "\u901a\u77e5",
"ErrorLaunchingChromecast": "\u542f\u52a8chromecast\u9047\u5230\u9519\u8bef\uff0c\u8bf7\u786e\u8ba4\u8bbe\u5907\u5df2\u7ecf\u8fde\u63a5\u5230\u4f60\u7684\u65e0\u7ebf\u7f51\u7edc\u3002",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -118,7 +123,7 @@
"LabelFree": "\u514d\u8d39",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "\u9009\u62e9\u97f3\u9891",
@@ -174,6 +179,9 @@
"OptionThursday": "\u661f\u671f\u56db",
"OptionFriday": "\u661f\u671f\u4e94",
"OptionSaturday": "\u661f\u671f\u516d",
+ "OptionEveryday": "Every day",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "\u786e\u8ba4\u5220\u9664",
"MessageConfirmPathSubstitutionDeletion": "\u4f60\u786e\u5b9a\u5e0c\u671b\u5220\u9664\u6b64\u8def\u5f84\u66ff\u4ee3\uff1f",
"LiveTvUpdateAvailable": "(\u66f4\u65b0\u53ef\u7528)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "\u62c6\u5206\u5a92\u4f53",
"MessageConfirmSplitMedia": "\u60a8\u786e\u5b9a\u8981\u628a\u5a92\u4f53\u6e90\u62c6\u5206\u4e3a\u5355\u72ec\u7684\u9879\u76ee\uff1f",
"HeaderError": "\u9519\u8bef",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "\u8bf7\u81f3\u5c11\u9009\u62e9\u4e00\u4e2a\u9879\u76ee\u3002",
"MessagePleaseSelectTwoItems": "\u8bf7\u81f3\u5c11\u9009\u62e92\u4e2a\u9879\u76ee\u3002",
"MessageTheFollowingItemsWillBeGrouped": "\u4ee5\u4e0b\u6807\u9898\u5c06\u88ab\u5f52\u5165\u4e00\u4e2a\u9879\u76ee\uff1a",
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json
index 68437bb68..bdd3b6cf6 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json
@@ -35,8 +35,13 @@
"HeaderConfirmation": "Confirmation",
"MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
"MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
+ "HeaderSupportTheTeam": "Support the Emby Team",
+ "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"TitleLiveTV": "\u96fb\u8996\u529f\u80fd",
"TitleSync": "Sync",
+ "ButtonDonate": "Donate",
+ "HeaderMyMedia": "My Media",
+ "TitleNotifications": "Notifications",
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -118,7 +123,7 @@
"LabelFree": "Free",
"HeaderPlaybackError": "Playback Error",
"MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
- "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+ "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
"MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
"MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
"HeaderSelectAudio": "Select Audio",
@@ -174,6 +179,9 @@
"OptionThursday": "\u661f\u671f\u56db",
"OptionFriday": "\u661f\u671f\u4e94",
"OptionSaturday": "\u661f\u671f\u516d",
+ "OptionEveryday": "Every day",
+ "OptionWeekend": "Weekends",
+ "OptionWeekday": "Weekdays",
"HeaderConfirmDeletion": "Confirm Deletion",
"MessageConfirmPathSubstitutionDeletion": "Are you sure you wish to delete this path substitution?",
"LiveTvUpdateAvailable": "(Update available)",
@@ -191,6 +199,7 @@
"HeaderSplitMedia": "Split Media Apart",
"MessageConfirmSplitMedia": "Are you sure you wish to split the media sources into separate items?",
"HeaderError": "Error",
+ "MessageChromecastConnectionError": "Your Chromecast receiver is unable to connect to your Emby Server. Please check their connections and try again.",
"MessagePleaseSelectOneItem": "Please select at least one item.",
"MessagePleaseSelectTwoItems": "Please select at least two items.",
"MessageTheFollowingItemsWillBeGrouped": "The following titles will be grouped into one item:",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/ar.json b/MediaBrowser.Server.Implementations/Localization/Server/ar.json
index 61aaea0f8..d19090ddd 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/ar.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/ar.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Add User",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
"LabelPinCode": "Pin code:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "\u0645\u0648\u0627\u0641\u0642",
"ButtonCancel": "\u0627\u0644\u063a\u0627\u0621",
"ButtonExit": "Exit",
@@ -167,6 +169,7 @@
"MessageNothingHere": "\u0644\u0627 \u0634\u0649\u0621 \u0647\u0646\u0627.",
"MessagePleaseEnsureInternetMetadata": "Please ensure downloading of internet metadata is enabled.",
"TabSuggested": "\u0645\u0642\u062a\u0631\u062d",
+ "TabSuggestions": "Suggestions",
"TabLatest": "\u0627\u0644\u0627\u062e\u064a\u0631",
"TabUpcoming": "\u0627\u0644\u0642\u0627\u062f\u0645",
"TabShows": "\u0627\u0644\u0645\u0633\u0644\u0633\u0644\u0627\u062a",
@@ -401,9 +404,10 @@
"ButtonRefresh": "Refresh",
"ButtonAdvancedRefresh": "Advanced Refresh",
"OptionPriority": "Priority",
- "OptionRecordOnAllChannels": "Record program on all channels",
- "OptionRecordAnytime": "Record program at any time",
+ "OptionRecordOnAllChannels": "Record on all channels",
+ "OptionRecordAnytime": "Record at any time",
"OptionRecordOnlyNewEpisodes": "Record only new episodes",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "Days",
"HeaderActiveRecordings": "Active Recordings",
"HeaderLatestRecordings": "Latest Recordings",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "Web socket port number:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Home page section 2:",
"LabelHomePageSection3": "Home page section 3:",
"LabelHomePageSection4": "Home page section 4:",
- "OptionMyViewsButtons": "My views (buttons)",
- "OptionMyViews": "My views",
- "OptionMyViewsSmall": "My views (small)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Resume",
"OptionLatestMedia": "Latest media",
"OptionLatestChannelMedia": "Latest channel items",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Default",
"OptionCommunityMostWatchedSort": "Most Watched",
"TabNextUp": "Next Up",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
"MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favorites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Display Settings",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "More...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/bg_BG.json b/MediaBrowser.Server.Implementations/Localization/Server/bg_BG.json
index 5831f3d10..d0cd8cadf 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/bg_BG.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/bg_BG.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Add User",
"LabelAddConnectSupporterHelp": "\u0417\u0430 \u0434\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b \u043a\u043e\u0439\u0442\u043e \u043d\u0435 \u0435 \u0432 \u043b\u0438\u0441\u0442\u0438\u0442\u0435, \u0449\u0435 \u0442\u0440\u044f\u0431\u0432\u0430 \u043f\u044a\u0440\u0432\u043e \u0434\u0430 \u0437\u0430\u043a\u0430\u0447\u0438\u0442\u0435 \u0442\u0435\u0445\u043d\u0438\u044f \u043f\u0440\u043e\u0444\u0438\u043b \u043a\u044a\u043c Emby Connect \u043e\u0442 \u0442\u044f\u0445\u043d\u0430\u0442\u0430 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0441\u043a\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430.",
"LabelPinCode": "Pin code:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "\u041e\u043a",
"ButtonCancel": "\u041e\u0442\u043c\u0435\u043d\u0438",
"ButtonExit": "Exit",
@@ -167,6 +169,7 @@
"MessageNothingHere": "\u0422\u0443\u043a \u043d\u044f\u043c\u0430 \u043d\u0438\u0449\u043e.",
"MessagePleaseEnsureInternetMetadata": "\u041c\u043e\u043b\u044f, \u0443\u0432\u0435\u0440\u0435\u0442\u0435 \u0441\u0435 \u0447\u0435 \u0441\u0432\u0430\u043b\u044f\u043d\u0435\u0442\u043e \u043d\u0430 \u043c\u0435\u0442\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e\u0442 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u043e.",
"TabSuggested": "\u041f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f",
+ "TabSuggestions": "Suggestions",
"TabLatest": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438",
"TabUpcoming": "\u041f\u0440\u0435\u0434\u0441\u0442\u043e\u044f\u0449\u0438",
"TabShows": "\u041f\u0440\u0435\u0434\u0430\u0432\u0430\u043d\u0438\u044f",
@@ -404,6 +407,7 @@
"OptionRecordOnAllChannels": "\u0417\u0430\u043f\u0438\u0441\u0432\u0430\u0439 \u043f\u0440\u0435\u0434\u0430\u0432\u0430\u043d\u0435\u0442\u043e \u043d\u0430 \u0432\u0441\u0438\u0447\u043a\u0438 \u043a\u0430\u043d\u0430\u043b\u0438",
"OptionRecordAnytime": "\u0417\u0430\u043f\u0438\u0441\u0432\u0430\u0439 \u043f\u0440\u0435\u0434\u0430\u0432\u0430\u043d\u0435\u0442\u043e \u043f\u043e \u0432\u0441\u044f\u043a\u043e \u0432\u0440\u0435\u043c\u0435",
"OptionRecordOnlyNewEpisodes": "\u0417\u0430\u043f\u0438\u0441\u0432\u0430\u0439 \u0441\u0430\u043c\u043e \u043d\u043e\u0432\u0438 \u0435\u043f\u0438\u0437\u043e\u0434\u0438",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "\u0414\u043d\u0438",
"HeaderActiveRecordings": "\u0410\u043a\u0442\u0438\u0432\u043d\u0438 \u0417\u0430\u043f\u0438\u0441\u0438",
"HeaderLatestRecordings": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0417\u0430\u043f\u0438\u0441\u0438",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "TCP \u043f\u043e\u0440\u0442\u044a\u0442 \u043d\u0430 \u043a\u043e\u0439\u0442\u043e HTTPS \u0441\u044a\u0440\u0432\u044a\u0440\u044a\u0442 \u043d\u0430 Emby \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u0441\u0435 \u0437\u0430\u043a\u0430\u0447\u0438.",
"LabelWebSocketPortNumber": "Web socket port number:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Home page section 2:",
"LabelHomePageSection3": "Home page section 3:",
"LabelHomePageSection4": "Home page section 4:",
- "OptionMyViewsButtons": "My views (buttons)",
- "OptionMyViews": "My views",
- "OptionMyViewsSmall": "My views (small)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Resume",
"OptionLatestMedia": "Latest media",
"OptionLatestChannelMedia": "Latest channel items",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Default",
"OptionCommunityMostWatchedSort": "Most Watched",
"TabNextUp": "Next Up",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
"MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favorites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Display Settings",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "More...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ 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 65f8df592..3661325a2 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/ca.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/ca.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Add User",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
"LabelPinCode": "Pin code:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "Ok",
"ButtonCancel": "Cancel",
"ButtonExit": "Exit",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Nothing here.",
"MessagePleaseEnsureInternetMetadata": "Please ensure downloading of internet metadata is enabled.",
"TabSuggested": "Suggested",
+ "TabSuggestions": "Suggestions",
"TabLatest": "Latest",
"TabUpcoming": "Upcoming",
"TabShows": "Shows",
@@ -401,9 +404,10 @@
"ButtonRefresh": "Refresh",
"ButtonAdvancedRefresh": "Advanced Refresh",
"OptionPriority": "Priority",
- "OptionRecordOnAllChannels": "Record program on all channels",
- "OptionRecordAnytime": "Record program at any time",
+ "OptionRecordOnAllChannels": "Record on all channels",
+ "OptionRecordAnytime": "Record at any time",
"OptionRecordOnlyNewEpisodes": "Record only new episodes",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "Days",
"HeaderActiveRecordings": "Active Recordings",
"HeaderLatestRecordings": "Latest Recordings",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "Web socket port number:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Home page section 2:",
"LabelHomePageSection3": "Home page section 3:",
"LabelHomePageSection4": "Home page section 4:",
- "OptionMyViewsButtons": "My views (buttons)",
- "OptionMyViews": "My views",
- "OptionMyViewsSmall": "My views (small)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Resume",
"OptionLatestMedia": "Latest media",
"OptionLatestChannelMedia": "Latest channel items",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Default",
"OptionCommunityMostWatchedSort": "Most Watched",
"TabNextUp": "Next Up",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
"MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favorites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Display Settings",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "More...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ 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 8d9ccff49..11372143c 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/cs.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/cs.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Add User",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
"LabelPinCode": "Pin code:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "Ok",
"ButtonCancel": "Zru\u0161it",
"ButtonExit": "Exit",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Tady nic nen\u00ed.",
"MessagePleaseEnsureInternetMetadata": "Pros\u00edm zkontrolujte, zda m\u00e1te povoleno stahov\u00e1n\u00ed metadat z internetu.",
"TabSuggested": "Doporu\u010den\u00e9",
+ "TabSuggestions": "Suggestions",
"TabLatest": "Posledn\u00ed",
"TabUpcoming": "Nadch\u00e1zej\u00edc\u00ed",
"TabShows": "Seri\u00e1ly",
@@ -404,6 +407,7 @@
"OptionRecordOnAllChannels": "Nahr\u00e1vat program na v\u0161ech kan\u00e1lech",
"OptionRecordAnytime": "Nahr\u00e1vat program v jak\u00fdkoliv \u010das",
"OptionRecordOnlyNewEpisodes": "Nahr\u00e1vat pouze nov\u00e9 epizody",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "Dny",
"HeaderActiveRecordings": "Aktivn\u00ed nahr\u00e1v\u00e1n\u00ed",
"HeaderLatestRecordings": "Posledn\u00ed nahr\u00e1v\u00e1n\u00ed",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "\u010c\u00edslo portu web socketu:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Home page section 2:",
"LabelHomePageSection3": "Home page section 3:",
"LabelHomePageSection4": "Home page section 4:",
- "OptionMyViewsButtons": "My views (buttons)",
- "OptionMyViews": "My views",
- "OptionMyViewsSmall": "My views (small)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Pokra\u010dovat",
"OptionLatestMedia": "Latest media",
"OptionLatestChannelMedia": "Latest channel items",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Default",
"OptionCommunityMostWatchedSort": "Nejsledovan\u011bj\u0161\u00ed",
"TabNextUp": "Next Up",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
"MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favorites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Display Settings",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "More...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ 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 0dda45289..4251b2d70 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/da.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/da.json
@@ -4,7 +4,7 @@
"LabelGithub": "Github",
"LabelSwagger": "Swagger",
"LabelStandard": "Standard",
- "LabelApiDocumentation": "Api Documentation",
+ "LabelApiDocumentation": "Api dokumentation",
"LabelDeveloperResources": "Developer Resources",
"LabelBrowseLibrary": "Gennemse biblitek",
"LabelConfigureServer": "Configure Emby",
@@ -15,7 +15,7 @@
"LabelFinish": "Slut",
"LabelNext": "N\u00e6ste",
"LabelYoureDone": "Du er f\u00e6rdig!",
- "WelcomeToProject": "Welcome to Emby!",
+ "WelcomeToProject": "Velkommen til Emby!",
"ThisWizardWillGuideYou": "Denne guide vil hj\u00e6lpe dig igennem ops\u00e6tningen. For at begynde, venligst v\u00e6lg dit fortrukne sprog.",
"TellUsAboutYourself": "Fort\u00e6l os lidt om dig selv",
"ButtonQuickStartGuide": "Quick start guide",
@@ -49,17 +49,19 @@
"ButtonOrganize": "Organize",
"LinkedToEmbyConnect": "Linked to Emby Connect",
"HeaderSupporterBenefits": "Supporter Benefits",
- "HeaderAddUser": "Add User",
+ "HeaderAddUser": "Tilf\u00f8j bruger",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
- "LabelPinCode": "Pin code:",
+ "LabelPinCode": "Pin kode:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "Ok",
"ButtonCancel": "Annuller",
- "ButtonExit": "Exit",
+ "ButtonExit": "Afslut",
"ButtonNew": "Ny",
"HeaderTV": "TV",
"HeaderAudio": "Audio",
"HeaderVideo": "Video",
- "HeaderPaths": "Paths",
+ "HeaderPaths": "Stier",
"CategorySync": "Sync",
"TabPlaylist": "Playlist",
"HeaderEasyPinCode": "Easy Pin Code",
@@ -80,23 +82,23 @@
"LabelCustomCertificatePath": "Custom certificate path:",
"LabelCustomCertificatePathHelp": "Supply your own ssl certificate .pfx file. If omitted, the server will create a self-signed certificate.",
"TitleNotifications": "Notifications",
- "ButtonDonateWithPayPal": "Donate with PayPal",
+ "ButtonDonateWithPayPal": "Doner via PayPal",
"OptionDetectArchiveFilesAsMedia": "Detect archive files as media",
"OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
- "LabelEnterConnectUserName": "User name or email:",
+ "LabelEnterConnectUserName": "Brugernavn eller e-mail:",
"LabelEnterConnectUserNameHelp": "This is your Emby online account user name or password.",
"LabelEnableEnhancedMovies": "Enable enhanced movie displays",
"LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
"HeaderSyncJobInfo": "Sync Job",
"FolderTypeMixed": "Mixed content",
- "FolderTypeMovies": "Movies",
- "FolderTypeMusic": "Music",
- "FolderTypeAdultVideos": "Adult videos",
- "FolderTypePhotos": "Photos",
- "FolderTypeMusicVideos": "Music videos",
- "FolderTypeHomeVideos": "Home videos",
- "FolderTypeGames": "Games",
- "FolderTypeBooks": "Books",
+ "FolderTypeMovies": "FIlm",
+ "FolderTypeMusic": "Musik",
+ "FolderTypeAdultVideos": "Voksenfilm",
+ "FolderTypePhotos": "Fotos",
+ "FolderTypeMusicVideos": "Musikvideoer",
+ "FolderTypeHomeVideos": "Hjemmevideoer",
+ "FolderTypeGames": "Spil",
+ "FolderTypeBooks": "B\u00f8ger",
"FolderTypeTvShows": "TV",
"FolderTypeInherit": "Inherit",
"LabelContentType": "Content type:",
@@ -122,7 +124,7 @@
"TabProfile": "Profil",
"TabMetadata": "Metadata",
"TabImages": "Billeder",
- "TabNotifications": "Notifications",
+ "TabNotifications": "Notifikationer",
"TabCollectionTitles": "Titler",
"HeaderDeviceAccess": "Device Access",
"OptionEnableAccessFromAllDevices": "Enable access from all devices",
@@ -146,8 +148,8 @@
"TabProfiles": "Profiler",
"TabSecurity": "Sikkerhed",
"ButtonAddUser": "Tilf\u00f8j bruger",
- "ButtonAddLocalUser": "Add Local User",
- "ButtonInviteUser": "Invite User",
+ "ButtonAddLocalUser": "Tilf\u00f8j lokal bruger",
+ "ButtonInviteUser": "Inviter bruger",
"ButtonSave": "Gem",
"ButtonResetPassword": "Nulstil kode",
"LabelNewPassword": "Ny kode:",
@@ -159,7 +161,7 @@
"LibraryAccessHelp": "V\u00e6lg hvilke medie mapper der skal deles med denne bruger. Administratorer vil kunne redigere alle mapper ved hj\u00e6lp af metadata administratoren.",
"ChannelAccessHelp": "Select the channels to share with this user. Administrators will be able to edit all channels using the metadata manager.",
"ButtonDeleteImage": "Slet Billede",
- "LabelSelectUsers": "Select users:",
+ "LabelSelectUsers": "V\u00e6lg brugere:",
"ButtonUpload": "Upload",
"HeaderUploadNewImage": "Upload Nyt Billede",
"LabelDropImageHere": "Drop image here",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Her er ingenting.",
"MessagePleaseEnsureInternetMetadata": "V\u00e6r venligst sikker p\u00e5 at hentning af internet metadata er aktiveret.",
"TabSuggested": "Foresl\u00e5et",
+ "TabSuggestions": "Suggestions",
"TabLatest": "Seneste",
"TabUpcoming": "Kommende",
"TabShows": "Shows",
@@ -404,6 +407,7 @@
"OptionRecordOnAllChannels": "Optag program p\u00e5 alle kanaler",
"OptionRecordAnytime": "Optag program uanset tidpunkt",
"OptionRecordOnlyNewEpisodes": "Optag kun nye episoder",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "Dage",
"HeaderActiveRecordings": "Aktive Optagelser",
"HeaderLatestRecordings": "Seneste Optagelse",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "Web socket port number:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Home page section 2:",
"LabelHomePageSection3": "Home page section 3:",
"LabelHomePageSection4": "Home page section 4:",
- "OptionMyViewsButtons": "My views (buttons)",
- "OptionMyViews": "My views",
- "OptionMyViewsSmall": "My views (small)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Resume",
"OptionLatestMedia": "Latest media",
"OptionLatestChannelMedia": "Latest channel items",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Default",
"OptionCommunityMostWatchedSort": "Most Watched",
"TabNextUp": "Next Up",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
"MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favorites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Display Settings",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "More...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ 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 d69bede29..92e4e7f10 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/de.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/de.json
@@ -29,7 +29,7 @@
"WizardCompleted": "Das ist alles was wir bis jetzt brauchen. Emby hat nun angefangen Informationen \u00fcber Ihre Medienbibliothek zu sammeln. Schauen Sie sich ein paar unserer Apps an, dann Klicken Sie auf <b>Fertig<\/b> um das <b>Server Dashboard<\/b> anzuzeigen.",
"LabelConfigureSettings": "Konfiguriere Einstellungen",
"LabelEnableVideoImageExtraction": "Aktiviere Videobild-Extrahierung",
- "VideoImageExtractionHelp": "F\u00fcr Videos die noch keien Bilder haben, und f\u00fcr die wir keine Internetbilder finden k\u00f6nnen. Hierdurch wird der erste Bibliothekenscan etwas mehr Zeit beanspruchen, f\u00fchrt aber zu einer ansprechenderen Pr\u00e4sentation.",
+ "VideoImageExtractionHelp": "F\u00fcr Videos die noch keinen Bilder haben, und f\u00fcr die wir keine Internetbilder finden k\u00f6nnen. Hierdurch wird der erste Bibliotheken scan etwas mehr Zeit beanspruchen, f\u00fchrt aber zu einer ansprechenderen Pr\u00e4sentation.",
"LabelEnableChapterImageExtractionForMovies": "Extrahiere Kapitelbilder f\u00fcr Filme",
"LabelChapterImageExtractionForMoviesHelp": "Das Extrahieren von Kapitel-Bildern erm\u00f6glicht es den Clients eine grafische Szenenauswahl anzubieten. Das Erstellen ist recht langsam, rechenintensiv und erfordert einige Gigabyte an freien Speicherplatz. Diese Aufgabe startet jede Nacht, das kann aber in den geplanten Aufgaben ge\u00e4ndert werden. Es wird nicht empfohlen diese Aufgabe in Zeiten hoher Server-Auslastung zu starten.",
"LabelEnableAutomaticPortMapping": "Aktiviere automatische Portweiterleitung",
@@ -52,6 +52,8 @@
"HeaderAddUser": "Benutzer hinzuf\u00fcgen",
"LabelAddConnectSupporterHelp": "Um einen Benutzer hinzuzuf\u00fcgen, der nicht angezeigt wird, m\u00fcssen Sie diesen erst mit Emby Connect von seinem Benutzerprofil verbinden.",
"LabelPinCode": "PIN Code:",
+ "OptionHideWatchedContentFromLatestMedia": "Verberge gesehene Inhalte von zuletzt hinzugef\u00fcgten.",
+ "HeaderSync": "Synchronisiere",
"ButtonOk": "Ok",
"ButtonCancel": "Abbrechen",
"ButtonExit": "Exit",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Nichts hier.",
"MessagePleaseEnsureInternetMetadata": "Bitte sicherstellen, dass das Herunterladen von Internet Metadaten aktiviert ist.",
"TabSuggested": "Vorgeschlagen",
+ "TabSuggestions": "Empfehlungen",
"TabLatest": "Neueste",
"TabUpcoming": "Bevorstehend",
"TabShows": "Serien",
@@ -404,6 +407,7 @@
"OptionRecordOnAllChannels": "Nehme Programm auf allen Kan\u00e4len auf",
"OptionRecordAnytime": "Neme Programm zu jeder Zeit auf",
"OptionRecordOnlyNewEpisodes": "Nehme nur neue Episoden auf",
+ "HeaderRepeatingOptions": "Wiederholungs Einstellungen",
"HeaderDays": "Tage",
"HeaderActiveRecordings": "Aktive Aufnahmen",
"HeaderLatestRecordings": "Neueste Aufnahmen",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Startseite Bereich 2:",
"LabelHomePageSection3": "Startseite Bereich 3:",
"LabelHomePageSection4": "Startseite Bereich 4:",
- "OptionMyViewsButtons": "Meine Ansichten (Tasten)",
- "OptionMyViews": "Meine Ansichten",
- "OptionMyViewsSmall": "Meine Ansichten (Klein)",
+ "OptionMyMediaButtons": "Meine Medien (Schaltfl\u00e4chen)",
+ "OptionMyMedia": "Meine Medien",
+ "OptionMyMediaSmall": "Meine Medien (Klein)",
"OptionResumablemedia": "Wiederhole",
"OptionLatestMedia": "Neuste Medien",
"OptionLatestChannelMedia": "Neueste Channel Inhalte:",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Default",
"OptionCommunityMostWatchedSort": "Meistgesehen",
"TabNextUp": "Als N\u00e4chstes",
+ "PlaceholderUsername": "Benutzername",
"HeaderBecomeProjectSupporter": "Werden Sie Emby Unterst\u00fctzer",
- "TextEnjoyBonusFeatures": "Erleben Sie Bonus Funktionen",
"MessageNoMovieSuggestionsAvailable": "Momentan sind keine Filmvorschl\u00e4ge verf\u00fcgbar. Schaue und bewerte zuerst deine Filme. Komme danach zur\u00fcck, um deine Filmvorschl\u00e4ge anzuschauen.",
"MessageNoCollectionsAvailable": "Sammlungen erlauben Ihnen eine personalisierte Gruppierung von Filmen, Serien, Alben, B\u00fcchern und Spielen. Klicken Sie die + Schaltfl\u00e4che um Sammlungen zu erstellen.",
"MessageNoPlaylistsAvailable": "Wiedergabeliste erlauben es dir eine Liste mit Inhalt zu erstellen der fortlaufend abgespielt wird. Um einer Wiedergabeliste Inhalte hinzuzuf\u00fcgen klicke rechts oder mache einen langen Tap und w\u00e4hle daraufhin \"Zur Wiedergabeliste hinzuf\u00fcgen\" aus.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favoriten",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Neueste",
+ "ViewTypeMusicPlaylists": "Wiedergabelisten",
"ViewTypeMusicAlbums": "Alben",
"ViewTypeMusicAlbumArtists": "Album-K\u00fcnstler",
"HeaderOtherDisplaySettings": "Anzeige Einstellungen",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Lade Internet Metadaten f\u00fcr:",
"OptionTVMovies": "TV Filme",
"HeaderUpcomingMovies": "Bevorstehende Filme",
+ "HeaderUpcomingSports": "Folgende Sportveranstaltungen",
"HeaderUpcomingPrograms": "Bevorstehende Programme",
"ButtonMoreItems": "Mehr...",
"LabelShowLibraryTileNames": "Zeige Bibliothek Kachelnamen.",
"LabelShowLibraryTileNamesHelp": "Legen Sie fest, ob Beschriftungen unter den Kacheln der Startseite angezeigt werden sollen.",
- "OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottle": "aktiviere Drosselung",
+ "OptionEnableTranscodingThrottleHelp": "Die Drosselung justiert die Transkodier-Geschwindigkeit, um die Server CPU Auslastung w\u00e4hrend der Wiedergabe zu minimieren.",
+ "LabelUploadSpeedLimit": "Upload Geschwindigkeitslimit (mbps):",
+ "OptionAllowSyncTranscoding": "Erlaube Synchronisation die Transkodierung ben\u00f6tigen",
+ "HeaderPlayback": "Medien Wiedergabe",
+ "OptionAllowAudioPlaybackTranscoding": "Erlaube Audio-Wiedergabe die Transkodierung ben\u00f6tigt",
+ "OptionAllowVideoPlaybackTranscoding": "Erlaube Video-Wiedergabe die Transkodierung ben\u00f6tigt",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Benutzer erhalten aussagekr\u00e4ftige Fehlermeldungen gem\u00e4\u00df den Einstellungen, wenn Medien nicht wiedergegeben werden k\u00f6nnen.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Limitierte Client-Fernzugriff Datenrate (in mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "Eine optionale Streaming Datengrenze f\u00fcr alle Clients mit Fernzugriff. Dies verhindert, dass Clients eine h\u00f6here Bandbreite als die zur Verf\u00fcgung stehende Verbindung, anfragen.",
+ "LabelConversionCpuCoreLimit": "CPU Kerne Limit:",
+ "LabelConversionCpuCoreLimitHelp": "Begrenzt die Anzahl der verwendeten CPU Kerne w\u00e4hrend der Konvertierung f\u00fcr die Synchronisation.",
+ "OptionEnableFullSpeedConversion": "Aktiviere Hochleistung-Konvertierung.",
+ "OptionEnableFullSpeedConversionHelp": "In der Grundeinstellung wird die Konvertierung f\u00fcr die Synchronisation mit niedriger Geschwindigkeit durchgef\u00fchrt und spart damit System Ressourcen.",
+ "HeaderPlaylists": "Wiedergabeliste",
+ "HeaderSelectDate": "Datum w\u00e4hlen",
+ "HeaderWelcomeExclamation": "Willkommen!",
+ "HeaderMyPreferences": "Meine Einstellungen",
+ "ButtonMyPreferencesWelcomeYes": "Ja, ich m\u00f6chte meine Einstellungen nun festlegen.",
+ "ButtonMyPreferencesWelcomeNo": "Nein danke, das mache ich sp\u00e4ter.",
+ "MyPreferencesWelcomeMessage1": "Wir pr\u00e4sentieren Ihnen Ihre Bibliothek in einer Art, wie wir denken, dass es Ihnen gefallen d\u00fcrfte. Die Darstellung und Gruppierung des Inhaltes kann jederzeit in Ihren Einstellungen angepasst werden. Ihre Einstellungen werden auf alle Empy Apps \u00fcbertragen.",
+ "MyPreferencesWelcomeMessage2": "M\u00f6chten Sie Ihre Einstellungen nun festlegen?",
+ "ToAccessPreferencesHelp": "Um Ihre Einstellungen sp\u00e4ter zu \u00e4ndern, klicken Sie ihr Benutzer-Icon im oberen rechten Bereich oder w\u00e4hlen Sie \"Meine Einstellungen\".",
+ "HeaderViewStyles": "Zeige Stiele",
+ "LabelSelectViewStyles": "Aktiviere erweiterte Darstellungen f\u00fcr:",
+ "LabelSelectViewStylesHelp": "Wenn aktiviert werden Darstellungen von Kategorien mit Medieninformationen wie Empfehlungen, k\u00fcrzlich hinzugef\u00fcgt, Genres und weitere, angereichert. Wenn deaktiviert werden diese nur als simple Verzeichnisse dargestellt."
} \ 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 96b67ae6e..e23ad5b8e 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/el.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/el.json
@@ -1,113 +1,115 @@
{
- "LabelExit": "\u03ad\u03be\u03bf\u03b4\u03bf\u03c2",
- "LabelVisitCommunity": "\u0395\u03c0\u03af\u03c3\u03ba\u03b5\u03c8\u03b7 \u039a\u03bf\u03b9\u03bd\u03cc\u03c4\u03b7\u03c4\u03b1",
+ "LabelExit": "\u0388\u03be\u03bf\u03b4\u03bf\u03c2",
+ "LabelVisitCommunity": "\u039a\u03bf\u03b9\u03bd\u03cc\u03c4\u03b7\u03c4\u03b1",
"LabelGithub": "Github",
"LabelSwagger": "Swagger",
- "LabelStandard": "\u03c0\u03c1\u03cc\u03c4\u03c5\u03c0\u03bf",
+ "LabelStandard": "\u03a0\u03c1\u03cc\u03c4\u03c5\u03c0\u03bf",
"LabelApiDocumentation": "Api Documentation",
- "LabelDeveloperResources": "Developer Resources",
- "LabelBrowseLibrary": "\u03c0\u03b5\u03c1\u03b9\u03b7\u03b3\u03b7\u03b8\u03b5\u03af\u03c4\u03b5 \u03c3\u03c4\u03b7 \u03b2\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7",
- "LabelConfigureServer": "Configure Emby",
+ "LabelDeveloperResources": "\u03a0\u03b7\u03b3\u03ad\u03c2 \u03a0\u03c1\u03bf\u03b3\u03c1\u03b1\u03bc\u03bc\u03b1\u03c4\u03b9\u03c3\u03c4\u03ae",
+ "LabelBrowseLibrary": "\u03a0\u03b5\u03c1\u03b9\u03b7\u03b3\u03b7\u03b8\u03b5\u03af\u03c4\u03b5 \u03c3\u03c4\u03b7 \u03b2\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7",
+ "LabelConfigureServer": "\u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2 Emby",
"LabelOpenLibraryViewer": "\u03b1\u03bd\u03bf\u03af\u03be\u03b5\u03c4\u03b5 \u03c4\u03b7\u03bd \u0392\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7 \u03b8\u03b5\u03b1\u03c4\u03ae",
- "LabelRestartServer": "\u03b5\u03c0\u03b1\u03bd\u03b5\u03ba\u03ba\u03af\u03bd\u03b7\u03c3\u03b7 \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae",
- "LabelShowLogWindow": "\u0394\u03b5\u03af\u03c7\u03bd\u03bf\u03c5\u03bd \u03c4\u03bf \u03b7\u03bc\u03b5\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03bf \u03c0\u03b1\u03c1\u03ac\u03b8\u03c5\u03c1\u03bf",
+ "LabelRestartServer": "\u0395\u03c0\u03b1\u03bd\u03b5\u03ba\u03ba\u03af\u03bd\u03b7\u03c3\u03b7 \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae",
+ "LabelShowLogWindow": "\u0391\u03c1\u03c7\u03b5\u03af\u03bf \u039a\u03b1\u03c4\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2",
"LabelPrevious": "\u03c0\u03c1\u03bf\u03b7\u03b3\u03bf\u03cd\u03bc\u03b5\u03bd\u03bf\u03c2",
- "LabelFinish": "\u03c4\u03ad\u03bb\u03bf\u03c2",
- "LabelNext": "\u03b5\u03c0\u03cc\u03bc\u03b5\u03bd\u03bf\u03c2 ",
- "LabelYoureDone": "\u03a4\u03b5\u03bb\u03b5\u03b9\u03ce\u03c3\u03b1\u03c4\u03b5",
- "WelcomeToProject": "Welcome to Emby!",
+ "LabelFinish": "\u03a4\u03ad\u03bb\u03bf\u03c2",
+ "LabelNext": "\u0395\u03c0\u03cc\u03bc\u03b5\u03bd\u03bf",
+ "LabelYoureDone": "\u0395\u03af\u03c3\u03c4\u03b5 \u0388\u03c4\u03bf\u03b9\u03bc\u03bf\u03b9!",
+ "WelcomeToProject": "\u039a\u03b1\u03bb\u03c9\u03c2 \u03ae\u03c1\u03b8\u03b1\u03c4\u03b5 \u03c3\u03c4\u03bf Emby!",
"ThisWizardWillGuideYou": "\u0391\u03c5\u03c4\u03cc\u03c2 \u03bf \u03bf\u03b4\u03b7\u03b3\u03cc\u03c2 \u03b8\u03b1 \u03c3\u03b1\u03c2 \u03ba\u03b1\u03b8\u03bf\u03b4\u03b7\u03b3\u03ae\u03c3\u03b5\u03b9 \u03bc\u03ad\u03c3\u03c9 \u03c4\u03b7\u03c2 \u03b4\u03b9\u03b1\u03b4\u03b9\u03ba\u03b1\u03c3\u03af\u03b1\u03c2 \u03b5\u03b3\u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7\u03c2. \u0393\u03b9\u03b1 \u03bd\u03b1 \u03be\u03b5\u03ba\u03b9\u03bd\u03ae\u03c3\u03b5\u03c4\u03b5, \u03b5\u03c0\u03b9\u03bb\u03ad\u03be\u03c4\u03b5 \u03c4\u03b7 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b1 \u03c4\u03b7\u03c2 \u03c0\u03c1\u03bf\u03c4\u03af\u03bc\u03b7\u03c3\u03ae\u03c2 \u03c3\u03b1\u03c2.",
"TellUsAboutYourself": "\u03a0\u03b5\u03af\u03c4\u03b5 \u03bc\u03b1\u03c2 \u03b3\u03b9\u03b1 \u03b5\u03c3\u03ac\u03c2",
- "ButtonQuickStartGuide": "Quick start guide",
+ "ButtonQuickStartGuide": "\u039f\u03b4\u03b7\u03b3\u03cc\u03c2 \u03b3\u03c1\u03ae\u03b3\u03bf\u03c1\u03b7\u03c2 \u03b5\u03ba\u03ba\u03af\u03bd\u03b7\u03c3\u03b7\u03c2",
"LabelYourFirstName": "\u03a4\u03bf \u03cc\u03bd\u03bf\u03bc\u03ac \u03c3\u03b1\u03c2",
"MoreUsersCanBeAddedLater": "\u03a0\u03b5\u03c1\u03b9\u03c3\u03c3\u03cc\u03c4\u03b5\u03c1\u03bf\u03c5\u03c2 \u03c7\u03c1\u03ae\u03c3\u03c4\u03b5\u03c2 \u03bc\u03c0\u03bf\u03c1\u03bf\u03cd\u03bd \u03bd\u03b1 \u03c0\u03c1\u03bf\u03c3\u03c4\u03b5\u03b8\u03bf\u03cd\u03bd \u03b1\u03c1\u03b3\u03cc\u03c4\u03b5\u03c1\u03b1 \u03bc\u03b5 \u03c4\u03bf \u03c4\u03b1\u03bc\u03c0\u03bb\u03cc",
"UserProfilesIntro": "Emby includes built-in support for user profiles, enabling each user to have their own display settings, playstate and parental controls.",
- "LabelWindowsService": "Windows \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1 ",
- "AWindowsServiceHasBeenInstalled": "\u039c\u03b9\u03b1 \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1 Windows \u03ad\u03c7\u03bf\u03c5\u03bd \u03b5\u03b3\u03ba\u03b1\u03c4\u03b1\u03c3\u03c4\u03b1\u03b8\u03b5\u03af",
- "WindowsServiceIntro1": "Emby Server normally runs as a desktop application with a tray icon, but if you prefer to run it as a background service, it can be started from the windows services control panel instead.",
+ "LabelWindowsService": "\u03a5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1 Windows",
+ "AWindowsServiceHasBeenInstalled": "\u039c\u03b9\u03b1 \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1 Windows \u03ad\u03c7\u03b5\u03b9 \u03b5\u03b3\u03ba\u03b1\u03c4\u03b1\u03c3\u03c4\u03b1\u03b8\u03b5\u03af",
+ "WindowsServiceIntro1": "\u039f \u0394\u03b9\u03b1\u03c7\u03b5\u03b9\u03c1\u03b9\u03c3\u03c4\u03ae\u03c2 Emby \u03ba\u03b1\u03bd\u03bf\u03bd\u03b9\u03ba\u03ac \u03bb\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03b5\u03af \u03c3\u03b1\u03bd \u03bc\u03b9\u03b1 \u03b5\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae \u03bc\u03b5 \u03b5\u03b9\u03ba\u03bf\u03bd\u03af\u03b4\u03b9\u03bf, \u03b1\u03bb\u03bb\u03ac \u03b1\u03bd \u03c0\u03c1\u03bf\u03c4\u03b9\u03bc\u03ac\u03c4\u03b5 \u03bd\u03b1 \u03bb\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03b5\u03af \u03c3\u03b1\u03bd \u03bc\u03b9\u03b1 \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1 \u03c3\u03c4\u03bf \u03b2\u03ac\u03b8\u03bf\u03c2, \u03bc\u03c0\u03bf\u03c1\u03b5\u03af \u03bd\u03b1 \u03b5\u03ba\u03ba\u03b9\u03bd\u03b7\u03b8\u03b5\u03af \u03b1\u03c0\u03cc \u03c4\u03bf\u03bd \u03c0\u03af\u03bd\u03b1\u03ba\u03b1 \u03b5\u03bb\u03ad\u03b3\u03c7\u03bf\u03c5 \u03c4\u03c9\u03bd \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03b9\u03ce\u03bd \u03c4\u03c9\u03bd Windows",
"WindowsServiceIntro2": "If using the windows service, please note that it cannot be run at the same time as the tray icon, so you'll need to exit the tray in order to run the service. The service will also need to be configured with administrative privileges via the control panel. Please note that at this time the service is unable to self-update, so new versions will require manual interaction.",
"WizardCompleted": "That's all we need for now. Emby has begun collecting information about your media library. Check out some of our apps, and then click <b>Finish<\/b> to view the <b>Server Dashboard<\/b>.",
- "LabelConfigureSettings": "\u03b4\u03b9\u03b1\u03bc\u03bf\u03c1\u03c6\u03ce\u03c3\u03b5\u03c4\u03b5 \u03c4\u03b9\u03c2 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2",
- "LabelEnableVideoImageExtraction": "Enable video image extraction",
- "VideoImageExtractionHelp": "For videos that don't already have images, and that we're unable to find internet images for. This will add some additional time to the initial library scan but will result in a more pleasing presentation.",
- "LabelEnableChapterImageExtractionForMovies": "Extract chapter image extraction for Movies",
+ "LabelConfigureSettings": "\u0394\u03b9\u03b1\u03bc\u03bf\u03c1\u03c6\u03ce\u03c3\u03b5\u03c4\u03b5 \u03c4\u03b9\u03c2 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2",
+ "LabelEnableVideoImageExtraction": "\u0395\u03be\u03b1\u03b3\u03c9\u03b3\u03ae \u0395\u03b9\u03ba\u03cc\u03bd\u03b1\u03c2 \u03b1\u03c0\u03cc \u0392\u03af\u03bd\u03c4\u03b5\u03bf",
+ "VideoImageExtractionHelp": "\u0393\u03b9\u03b1 \u03c4\u03b1 \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03c0\u03bf\u03c5 \u03b4\u03b5\u03bd \u03ad\u03c7\u03bf\u03c5\u03bd \u03ae\u03b4\u03b7 \u03b5\u03b9\u03ba\u03cc\u03bd\u03b5\u03c2, \u03ba\u03b1\u03b9 \u03b4\u03b5\u03bd \u03bc\u03c0\u03bf\u03c1\u03ad\u03c3\u03b1\u03bc\u03b5 \u03bd\u03b1 \u03b2\u03c1\u03bf\u03cd\u03bc\u03b5 \u03c3\u03c4\u03bf \u03b4\u03b9\u03b1\u03b4\u03af\u03ba\u03c4\u03c5\u03bf. \u0391\u03c5\u03c4\u03cc \u03b8\u03b1 \u03ba\u03b1\u03b8\u03c5\u03c3\u03c4\u03b5\u03c1\u03ae\u03c3\u03b5\u03b9 \u03bb\u03af\u03b3\u03bf \u03c4\u03b7\u03bd \u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7 \u03c3\u03c4\u03b7\u03bd \u03b1\u03c1\u03c7\u03b9\u03ba\u03ae \u03b2\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7 \u03b1\u03bb\u03bb\u03b1 \u03b8\u03b1 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b7 \u03c4\u03b5\u03bb\u03b9\u03ba\u03ae \u03bc\u03bf\u03c1\u03c6\u03ae \u03c0\u03b9\u03bf \u03cc\u03bc\u03bf\u03c1\u03c6\u03b7.",
+ "LabelEnableChapterImageExtractionForMovies": "\u0395\u03be\u03b1\u03b3\u03c9\u03b3\u03ae \u0395\u03b9\u03ba\u03cc\u03bd\u03b1\u03c2 \u039a\u03b5\u03c6\u03b1\u03bb\u03bb\u03b1\u03af\u03c9\u03bd \u03b3\u03b9\u03b1 \u03c4\u03b9\u03c2 \u03a4\u03b1\u03b9\u03bd\u03af\u03b5\u03c2",
"LabelChapterImageExtractionForMoviesHelp": "Extracting chapter images will allow clients to display graphical scene selection menus. The process can be slow, cpu-intensive and may require several gigabytes of space. It runs as a nightly scheduled task, although this is configurable in the scheduled tasks area. It is not recommended to run this task during peak usage hours.",
- "LabelEnableAutomaticPortMapping": "\u0395\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 \u03bb\u03b9\u03bc\u03ac\u03bd\u03b9 \u03b1\u03c5\u03c4\u03cc\u03bc\u03b1\u03c4\u03b7 \u03c7\u03b1\u03c1\u03c4\u03bf\u03b3\u03c1\u03ac\u03c6\u03b7\u03c3\u03b7",
- "LabelEnableAutomaticPortMappingHelp": "UPnP allows automated router configuration for easy remote access. This may not work with some router models.",
+ "LabelEnableAutomaticPortMapping": "\u0395\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03b1\u03c5\u03c4\u03cc\u03bc\u03b1\u03c4\u03b7\u03c2 \u03ba\u03b1\u03c4\u03b1\u03c7\u03ce\u03c1\u03b7\u03c3\u03b7\u03c2 \u0398\u03c5\u03c1\u03ce\u03bd",
+ "LabelEnableAutomaticPortMappingHelp": "To UPnP \u03b5\u03c0\u03b9\u03c4\u03c1\u03ad\u03c0\u03b5\u03b9 \u03c4\u03b7\u03bd \u03b1\u03c5\u03c4\u03cc\u03bc\u03b1\u03c4\u03b7 \u03c1\u03cd\u03b8\u03bc\u03b9\u03c3\u03b7 \u03c4\u03bf\u03c5 \u03b4\u03c1\u03bf\u03bc\u03bf\u03bb\u03bf\u03b3\u03b7\u03c4\u03ae \u03b3\u03b9\u03b1 \u03b5\u03cd\u03ba\u03bf\u03bb\u03b7 \u03b1\u03c0\u03bf\u03bc\u03b1\u03ba\u03c1\u03c5\u03c3\u03bc\u03ad\u03bd\u03b7 \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7. \u0391\u03c5\u03c4\u03ae \u03b7 \u03c1\u03cd\u03b8\u03bc\u03b9\u03c3\u03b7 \u03bc\u03c0\u03bf\u03c1\u03b5\u03af \u03bd\u03b1 \u03bc\u03b7\u03bd \u03b4\u03bf\u03c5\u03bb\u03ad\u03c8\u03b5\u03b9 \u03bc\u03b5 \u03ba\u03ac\u03c0\u03bf\u03b9\u03b1 \u03bc\u03bf\u03bd\u03c4\u03ad\u03bb\u03b1 \u03b4\u03c1\u03bf\u03bc\u03bf\u03bb\u03bf\u03b3\u03b7\u03c4\u03ce\u03bd",
"HeaderTermsOfService": "Emby Terms of Service",
- "MessagePleaseAcceptTermsOfService": "Please accept the terms of service and privacy policy before continuing.",
- "OptionIAcceptTermsOfService": "I accept the terms of service",
- "ButtonPrivacyPolicy": "Privacy policy",
- "ButtonTermsOfService": "Terms of Service",
+ "MessagePleaseAcceptTermsOfService": "\u03a0\u03b1\u03c1\u03b1\u03ba\u03b1\u03bb\u03ce \u03b1\u03c0\u03bf\u03b4\u03b5\u03c7\u03c4\u03b5\u03af\u03c4\u03b5 \u03c4\u03bf\u03c5\u03c2 \u038c\u03c1\u03bf\u03c5\u03c2 \u03a7\u03c1\u03ae\u03c3\u03b7\u03c2 \u03ba\u03b1\u03b9 \u03a0\u03c1\u03bf\u03c3\u03c4\u03b1\u03c3\u03af\u03b1\u03c2 \u0394\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03c9\u03bd \u03c0\u03c1\u03b9\u03bd \u03c0\u03c1\u03bf\u03c7\u03c9\u03c1\u03ae\u03c3\u03b5\u03c4\u03b5.",
+ "OptionIAcceptTermsOfService": "\u0391\u03c0\u03cc\u03b4\u03b5\u03c7\u03bf\u03bc\u03b1\u03b9 \u03c4\u03bf\u03c5\u03c2 \u038c\u03c1\u03bf\u03c5\u03c2 \u03a7\u03c1\u03ae\u03c3\u03b7\u03c2",
+ "ButtonPrivacyPolicy": "\u03a0\u03c1\u03bf\u03c3\u03c4\u03b1\u03c3\u03af\u03b1 \u0394\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03c9\u03bd",
+ "ButtonTermsOfService": "\u038c\u03c1\u03bf\u03b9 \u03a7\u03c1\u03ae\u03c3\u03b7\u03c2",
"HeaderDeveloperOptions": "Developer Options",
- "OptionEnableWebClientResponseCache": "Enable web client response caching",
+ "OptionEnableWebClientResponseCache": "Ene",
"OptionDisableForDevelopmentHelp": "Configure these as needed for web client development purposes.",
"OptionEnableWebClientResourceMinification": "Enable web client resource minification",
"LabelDashboardSourcePath": "Web client source path:",
"LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
"ButtonConvertMedia": "Convert media",
- "ButtonOrganize": "Organize",
+ "ButtonOrganize": "\u039f\u03c1\u03b3\u03ac\u03bd\u03c9\u03c3\u03b7",
"LinkedToEmbyConnect": "Linked to Emby Connect",
"HeaderSupporterBenefits": "Supporter Benefits",
- "HeaderAddUser": "Add User",
+ "HeaderAddUser": "\u03a0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7 \u03a7\u03c1\u03ae\u03c3\u03c4\u03b7",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
"LabelPinCode": "Pin code:",
- "ButtonOk": "\u03b5\u03bd\u03c4\u03ac\u03be\u03b5\u03b9",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
+ "ButtonOk": "\u0395\u03bd\u03c4\u03ac\u03be\u03b5\u03b9",
"ButtonCancel": "\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7 ",
- "ButtonExit": "Exit",
- "ButtonNew": "New",
- "HeaderTV": "TV",
- "HeaderAudio": "Audio",
- "HeaderVideo": "Video",
- "HeaderPaths": "Paths",
- "CategorySync": "Sync",
- "TabPlaylist": "Playlist",
+ "ButtonExit": "\u0388\u03be\u03bf\u03b4\u03bf\u03c2",
+ "ButtonNew": "\u039d\u03ad\u03bf",
+ "HeaderTV": "\u03a4\u03b7\u03bb\u03b5\u03cc\u03c1\u03b1\u03c3\u03b7",
+ "HeaderAudio": "\u0389\u03c7\u03bf\u03c2",
+ "HeaderVideo": "\u0392\u03af\u03bd\u03c4\u03b5\u03bf",
+ "HeaderPaths": "\u0394\u03b9\u03b1\u03b4\u03c1\u03bf\u03bc\u03ae",
+ "CategorySync": "\u03a3\u03c5\u03c7\u03c1\u03bf\u03bd\u03b9\u03c3\u03bc\u03cc\u03c2",
+ "TabPlaylist": "\u039b\u03af\u03c3\u03c4\u03b1",
"HeaderEasyPinCode": "Easy Pin Code",
- "HeaderGrownupsOnly": "Grown-ups Only!",
- "DividerOr": "-- or --",
- "HeaderInstalledServices": "Installed Services",
- "HeaderAvailableServices": "Available Services",
- "MessageNoServicesInstalled": "No services are currently installed.",
- "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+ "HeaderGrownupsOnly": "\u0395\u03bd\u03ae\u03bb\u03b9\u03ba\u03bf\u03b9 \u03bc\u03cc\u03bd\u03bf!",
+ "DividerOr": "--\u03ae--",
+ "HeaderInstalledServices": "\u0395\u03b3\u03ba\u03b1\u03c4\u03b5\u03c3\u03c4\u03b7\u03bc\u03ad\u03bd\u03b5\u03c2 \u03a5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b5\u03c2",
+ "HeaderAvailableServices": "\u0394\u03b9\u03b1\u03b8\u03ad\u03c3\u03b9\u03bc\u03b5\u03c2 \u03a5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b5\u03c2",
+ "MessageNoServicesInstalled": "\u039a\u03b1\u03bc\u03af\u03b1 \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1 \u03b4\u03b5\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03b3\u03ba\u03b1\u03c4\u03b5\u03c3\u03c4\u03b7\u03bc\u03ad\u03bd\u03b7.",
+ "HeaderToAccessPleaseEnterEasyPinCode": "\u0393\u03b9\u03b1 \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7, \u03c0\u03b1\u03c1\u03b1\u03ba\u03b1\u03bb\u03ce \u03b4\u03ce\u03c3\u03c4\u03b5 \u03c4\u03bf\u03bd \u03ba\u03c9\u03b4\u03b9\u03ba\u03cc \u03c3\u03b1\u03c2",
"KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
"ButtonConfigurePinCode": "Configure pin code",
- "HeaderAdultsReadHere": "Adults Read Here!",
- "RegisterWithPayPal": "Register with PayPal",
+ "HeaderAdultsReadHere": "\u039f\u03b9 \u03b5\u03bd\u03ae\u03bb\u03b9\u03ba\u03bf\u03b9 \u03b4\u03b9\u03b1\u03b2\u03ac\u03c3\u03c4\u03b5!",
+ "RegisterWithPayPal": "\u0395\u03b3\u03b3\u03c1\u03b1\u03c6\u03ae \u03bc\u03b5 Paypal",
"HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
- "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
- "LabelSyncTempPath": "Temporary file path:",
+ "HeaderEnjoyDayTrial": "\u0391\u03c0\u03bf\u03bb\u03b1\u03cd\u03c3\u03c4\u03b5 14 \u039c\u03ad\u03c1\u03b5\u03c2 \u0394\u03bf\u03ba\u03b9\u03bc\u03b1\u03c3\u03c4\u03b9\u03ba\u03ae\u03c2 \u03a0\u03b5\u03c1\u03b9\u03cc\u03b4\u03bf\u03c5",
+ "LabelSyncTempPath": "\u03a6\u03ac\u03ba\u03b5\u03bb\u03bf\u03c2 \u03a0\u03c1\u03bf\u03c3\u03c9\u03c1\u03b9\u03bd\u03ce\u03bd \u0391\u03c1\u03c7\u03b5\u03af\u03c9\u03bd",
"LabelSyncTempPathHelp": "Specify a custom sync working folder. Converted media created during the sync process will be stored here.",
"LabelCustomCertificatePath": "Custom certificate path:",
"LabelCustomCertificatePathHelp": "Supply your own ssl certificate .pfx file. If omitted, the server will create a self-signed certificate.",
- "TitleNotifications": "Notifications",
- "ButtonDonateWithPayPal": "Donate with PayPal",
- "OptionDetectArchiveFilesAsMedia": "Detect archive files as media",
- "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
- "LabelEnterConnectUserName": "User name or email:",
+ "TitleNotifications": "\u0395\u03b9\u03b4\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03b5\u03b9\u03c2",
+ "ButtonDonateWithPayPal": "\u0394\u03c9\u03c1\u03b5\u03ac \u03bc\u03ad\u03c3\u03c9 Paypal",
+ "OptionDetectArchiveFilesAsMedia": "\u0391\u03bd\u03b1\u03b3\u03bd\u03ce\u03c1\u03b9\u03c3\u03b5 \u03a3\u03c5\u03bc\u03c0\u03b9\u03b5\u03c3\u03bc\u03ad\u03bd\u03b1 \u03b1\u03c1\u03c7\u03b5\u03af\u03b1 \u03c9\u03c2 \u03c0\u03bf\u03bb\u03c5\u03bc\u03ad\u03c3\u03b1.",
+ "OptionDetectArchiveFilesAsMediaHelp": "\u0391\u03c1\u03c7\u03b5\u03af\u03b1 \u03bc\u03b5 .rar \u03ba\u03b1\u03b9 .zip \u03ba\u03b1\u03c4\u03b1\u03bb\u03ae\u03be\u03b5\u03b9\u03c2 \u03b8\u03b1 \u03b1\u03bd\u03b1\u03b3\u03bd\u03c9\u03c1\u03af\u03b6\u03bf\u03bd\u03c4\u03b1\u03b9 \u03c9\u03c2 \u03b1\u03c1\u03c7\u03b5\u03af\u03b1 \u03c0\u03bf\u03bb\u03c5\u03bc\u03ad\u03c3\u03c9\u03bd.",
+ "LabelEnterConnectUserName": "\u038c\u03bd\u03bf\u03bc\u03b1 \u03a7\u03c1\u03ae\u03c3\u03c4\u03b7 \u03ae email:",
"LabelEnterConnectUserNameHelp": "This is your Emby online account user name or password.",
"LabelEnableEnhancedMovies": "Enable enhanced movie displays",
"LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
- "HeaderSyncJobInfo": "Sync Job",
- "FolderTypeMixed": "Mixed content",
- "FolderTypeMovies": "Movies",
- "FolderTypeMusic": "Music",
- "FolderTypeAdultVideos": "Adult videos",
- "FolderTypePhotos": "Photos",
- "FolderTypeMusicVideos": "Music videos",
- "FolderTypeHomeVideos": "Home videos",
- "FolderTypeGames": "Games",
- "FolderTypeBooks": "Books",
- "FolderTypeTvShows": "TV",
+ "HeaderSyncJobInfo": "\u0395\u03c1\u03b3\u03b1\u03c3\u03af\u03b1 \u03a3\u03c5\u03b3\u03c7\u03c1\u03bf\u03bd\u03b9\u03c3\u03bc\u03bf\u03cd",
+ "FolderTypeMixed": "\u0391\u03bd\u03ac\u03bc\u03b5\u03b9\u03ba\u03c4\u03bf \u03a0\u03b5\u03c1\u03b9\u03b5\u03c7\u03cc\u03bc\u03b5\u03bd\u03bf",
+ "FolderTypeMovies": "\u03a4\u03b1\u03b9\u03bd\u03af\u03b5\u03c2",
+ "FolderTypeMusic": "\u039c\u03bf\u03c5\u03c3\u03b9\u03ba\u03ae",
+ "FolderTypeAdultVideos": "\u03a4\u03b1\u03b9\u03bd\u03af\u03b5\u03c2 \u0395\u03bd\u03b7\u03bb\u03af\u03ba\u03c9\u03bd",
+ "FolderTypePhotos": "\u03a6\u03c9\u03c4\u03bf\u03b3\u03c1\u03b1\u03c6\u03af\u03b5\u03c2",
+ "FolderTypeMusicVideos": "\u039c\u03bf\u03c5\u03c3\u03b9\u03ba\u03ac \u0392\u03af\u03bd\u03c4\u03b5\u03bf",
+ "FolderTypeHomeVideos": "\u03a0\u03c1\u03bf\u03c3\u03c9\u03c0\u03b9\u03ba\u03ac \u0392\u03af\u03bd\u03c4\u03b5\u03bf",
+ "FolderTypeGames": "\u03a0\u03b1\u03b9\u03c7\u03bd\u03af\u03b4\u03b9\u03b1",
+ "FolderTypeBooks": "\u0392\u03b9\u03b2\u03bb\u03af\u03b1",
+ "FolderTypeTvShows": "\u03a4\u03b7\u03bb\u03b5\u03cc\u03c1\u03b1\u03c3\u03b7",
"FolderTypeInherit": "Inherit",
- "LabelContentType": "Content type:",
- "TitleScheduledTasks": "Scheduled Tasks",
+ "LabelContentType": "\u03a4\u03cd\u03c0\u03bf\u03c2 \u03b1\u03c1\u03c7\u03b5\u03af\u03c9\u03bd:",
+ "TitleScheduledTasks": "\u03a0\u03c1\u03bf\u03b3\u03c1\u03b1\u03bc\u03bc\u03b1\u03c4\u03b9\u03c3\u03bc\u03ad\u03bd\u03b5\u03c2 \u0395\u03c1\u03b3\u03b1\u03c3\u03af\u03b5\u03c2",
"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 ",
+ "LabelFolderType": "\u03a4\u03cd\u03c0\u03bf\u03c2 \u03c6\u03b1\u03ba\u03ad\u03bb\u03bf\u03c5",
"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",
- "LabelTimeLimitHours": "Time limit (hours):",
+ "LabelCountry": "\u03a7\u03ce\u03c1\u03b1",
+ "LabelLanguage": "\u0393\u03bb\u03ce\u03c3\u03c3\u03b1",
+ "LabelTimeLimitHours": "\u038c\u03c1\u03b9\u03bf \u03a7\u03c1\u03cc\u03bd\u03bf\u03c5 (\u038f\u03c1\u03b5\u03c2)",
"ButtonJoinTheDevelopmentTeam": "Join the Development Team",
"HeaderPreferredMetadataLanguage": "\u03a0\u03c1\u03bf\u03c4\u03b9\u03bc\u03ce\u03bc\u03b5\u03bd\u03b7 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b1 \u03bc\u03b5\u03c4\u03b1",
"LabelSaveLocalMetadata": "\u0391\u03c0\u03bf\u03b8\u03b7\u03ba\u03b5\u03cd\u03c3\u03b5\u03c4\u03b5 \u03c4\u03bf \u03ad\u03c1\u03b3\u03bf \u03c4\u03ad\u03c7\u03bd\u03b7\u03c2 \u03ba\u03b1\u03b9 \u03c4\u03b1 \u03bc\u03b5\u03c4\u03b1\u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03b1 \u03c3\u03b5 \u03c6\u03b1\u03ba\u03ad\u03bb\u03bf\u03c5\u03c2 \u03c0\u03bf\u03bb\u03c5\u03bc\u03ad\u03c3\u03c9\u03bd",
@@ -115,59 +117,60 @@
"LabelDownloadInternetMetadata": "\u039a\u03b1\u03c4\u03b5\u03b2\u03ac\u03c3\u03c4\u03b5 \u03ad\u03c1\u03b3\u03b1 \u03c4\u03ad\u03c7\u03bd\u03b7\u03c2 \u03ba\u03b1\u03b9 \u03c4\u03b1 \u03bc\u03b5\u03c4\u03b1-\u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03b1 \u03b1\u03c0\u03cc \u03c4\u03bf internet ",
"LabelDownloadInternetMetadataHelp": "Emby Server can download information about your media to enable rich presentations.",
"TabPreferences": "\u03a0\u03c1\u03bf\u03c4\u03b9\u03bc\u03ae\u03c3\u03b5\u03b9\u03c2 ",
- "TabPassword": "\u03c4\u03bf\u03bd \u03ba\u03c9\u03b4\u03b9\u03ba\u03cc",
+ "TabPassword": "\u039a\u03c9\u03b4\u03b9\u03ba\u03cc\u03c2",
"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 ",
+ "TabAccess": "\u03a0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7",
+ "TabImage": "\u0395\u03b9\u03ba\u03cc\u03bd\u03b1",
+ "TabProfile": "\u03a0\u03c1\u03bf\u03c6\u03af\u03bb",
"TabMetadata": "Metadata",
- "TabImages": "Images",
- "TabNotifications": "Notifications",
- "TabCollectionTitles": "Titles",
- "HeaderDeviceAccess": "Device Access",
- "OptionEnableAccessFromAllDevices": "Enable access from all devices",
+ "TabImages": "\u0395\u03b9\u03ba\u03cc\u03bd\u03b5\u03c2",
+ "TabNotifications": "\u0395\u03b9\u03b4\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03b5\u03b9\u03c2",
+ "TabCollectionTitles": "\u03a4\u03af\u03c4\u03bb\u03bf\u03b9",
+ "HeaderDeviceAccess": "\u03a0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7 \u03a3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae\u03c2",
+ "OptionEnableAccessFromAllDevices": "\u03a0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7 \u03b1\u03c0\u03cc \u03cc\u03bb\u03b5\u03c2 \u03c4\u03b9\u03c2 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ad\u03c2",
"OptionEnableAccessToAllChannels": "Enable access to all channels",
- "OptionEnableAccessToAllLibraries": "Enable access to all libraries",
+ "OptionEnableAccessToAllLibraries": "\u03a0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7 \u03c3\u03b5 \u03cc\u03bb\u03b5\u03c2 \u03c4\u03b9\u03c2 \u0392\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b5\u03c2",
"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.",
- "HeaderPlaybackSettings": "Playback Settings",
- "LabelAudioLanguagePreference": "\u039f\u03bc\u03b9\u03bb\u03bf\u03cd\u03bc\u03b5\u03bd\u03b7 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b1 \u03c0\u03c1\u03bf\u03c4\u03af\u03bc\u03b7\u03c3\u03b7\u03c2",
+ "LabelDisplayMissingEpisodesWithinSeasons": "\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7 \u03b5\u03c0\u03b5\u03b9\u03c3\u03bf\u03b4\u03af\u03c9\u03bd \u03c0\u03bf\u03c5 \u03bb\u03b5\u03af\u03c0\u03bf\u03c5\u03bd \u03b1\u03c0\u03cc \u03c4\u03b7\u03bd \u03c3\u03b1\u03b9\u03b6\u03cc\u03bd",
+ "LabelUnairedMissingEpisodesWithinSeasons": "\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7 \u03ac\u03c0\u03b1\u03b9\u03c7\u03c4\u03c9\u03bd \u03b5\u03c0\u03b5\u03b9\u03c3\u03bf\u03b4\u03af\u03c9\u03bd \u03b1\u03c0\u03cc \u03c4\u03b7\u03bd \u03c3\u03b1\u03b9\u03b6\u03cc\u03bd",
+ "HeaderVideoPlaybackSettings": "\u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2 \u0391\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2 \u0392\u03af\u03bd\u03c4\u03b5\u03bf",
+ "HeaderPlaybackSettings": "\u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2 \u0391\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2",
+ "LabelAudioLanguagePreference": "\u03a0\u03c1\u03bf\u03c4\u03af\u03bc\u03b7\u03c3\u03b7 \u0393\u03bb\u03ce\u03c3\u03c3\u03b1\u03c2 \u0389\u03c7\u03bf\u03c5",
"LabelSubtitleLanguagePreference": "\u0393\u03bb\u03ce\u03c3\u03c3\u03b1 \u03c5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03c9\u03bd \u03c0\u03c1\u03bf\u03c4\u03af\u03bc\u03b7\u03c3\u03b7\u03c2",
- "OptionDefaultSubtitles": "Default",
+ "OptionDefaultSubtitles": "\u03a0\u03c1\u03bf\u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae",
"OptionOnlyForcedSubtitles": "Only forced subtitles",
- "OptionAlwaysPlaySubtitles": "Always play subtitles",
- "OptionNoSubtitles": "No Subtitles",
+ "OptionAlwaysPlaySubtitles": "\u03a0\u03ac\u03bd\u03c4\u03b1 \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae \u03a5\u03c0\u03bf\u03c4\u03af\u03c4\u03bb\u03c9\u03bd",
+ "OptionNoSubtitles": "\u03a7\u03c9\u03c1\u03af\u03c2 \u03a5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03c5\u03c2",
"OptionDefaultSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.",
"OptionOnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.",
"OptionAlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.",
"OptionNoSubtitlesHelp": "Subtitles will not be loaded by default.",
- "TabProfiles": "\u03c4\u03b1 \u03c0\u03c1\u03bf\u03c6\u03af\u03bb",
+ "TabProfiles": "\u03a0\u03c1\u03bf\u03c6\u03af\u03bb",
"TabSecurity": "A\u03c3\u03c6\u03ac\u03bb\u03b5\u03b9\u03b1 ",
"ButtonAddUser": "\u03a0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7 \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7",
- "ButtonAddLocalUser": "Add Local User",
- "ButtonInviteUser": "Invite User",
- "ButtonSave": "\u0391\u03c0\u03bf\u03b8\u03b7\u03ba\u03b5\u03cd\u03c3\u03c4\u03b5",
+ "ButtonAddLocalUser": "\u03a0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7 \u03a4\u03bf\u03c0\u03b9\u03ba\u03bf\u03cd \u03a7\u03c1\u03ae\u03c3\u03c4\u03b7",
+ "ButtonInviteUser": "\u03a0\u03c1\u03cc\u03c3\u03ba\u03bb\u03b7\u03c3\u03b7 \u03a7\u03c1\u03ae\u03c3\u03c4\u03b7",
+ "ButtonSave": "\u0391\u03c0\u03bf\u03b8\u03ae\u03ba\u03b5\u03c5\u03c3\u03b7",
"ButtonResetPassword": "\u0395\u03c0\u03b1\u03bd\u03b1\u03c6\u03bf\u03c1\u03ac \u03c4\u03bf\u03c5 \u03ba\u03c9\u03b4\u03b9\u03ba\u03bf\u03cd \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7\u03c2",
- "LabelNewPassword": "\u039d\u03ad\u03bf \u03ba\u03c9\u03b4\u03b9\u03ba\u03cc \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7\u03c2 ",
- "LabelNewPasswordConfirm": "\u0395\u03c0\u03b9\u03b2\u03b5\u03b2\u03b1\u03b9\u03ce\u03c3\u03c4\u03b5 \u03c4\u03bf \u03bd\u03ad\u03bf \u03ba\u03c9\u03b4\u03b9\u03ba\u03cc \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7\u03c2 ",
+ "LabelNewPassword": "\u039d\u03ad\u03bf\u03c2 \u03ba\u03c9\u03b4\u03b9\u03ba\u03cc \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7\u03c2",
+ "LabelNewPasswordConfirm": "\u0395\u03c0\u03b9\u03b2\u03b5\u03b2\u03b1\u03af\u03c9\u03c3\u03b7 \u03bd\u03ad\u03bf\u03c5 \u03ba\u03c9\u03b4\u03b9\u03ba\u03bf\u03cd \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7\u03c2",
"HeaderCreatePassword": "\u0394\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03af\u03b1 \u03ba\u03c9\u03b4\u03b9\u03ba\u03bf\u03cd \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7\u03c2 ",
- "LabelCurrentPassword": "\u03a4\u03c1\u03ad\u03c7\u03bf\u03bd\u03c4\u03b1 \u03ba\u03c9\u03b4\u03b9\u03ba\u03cc \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7\u03c2",
+ "LabelCurrentPassword": "\u03a4\u03c1\u03ad\u03c7\u03bf\u03bd\u03c4\u03b1\u03c2 \u03ba\u03c9\u03b4\u03b9\u03ba\u03cc\u03c2 \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7\u03c2",
"LabelMaxParentalRating": "\u039c\u03ad\u03b3\u03b9\u03c3\u03c4\u03bf \u03b5\u03c0\u03b9\u03c4\u03c1\u03b5\u03c0\u03cc\u03bc\u03b5\u03bd\u03bf \u03b3\u03bf\u03bd\u03b9\u03ba\u03ae \u03b2\u03b1\u03b8\u03bc\u03bf\u03bb\u03bf\u03b3\u03af\u03b1:",
"MaxParentalRatingHelp": "\u03a4\u03bf \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03cc\u03bc\u03b5\u03bd\u03bf \u03bc\u03b5 \u03c4\u03b7\u03bd \u03c5\u03c8\u03b7\u03bb\u03cc\u03c4\u03b5\u03c1\u03b7 \u03b2\u03b1\u03b8\u03bc\u03bf\u03bb\u03bf\u03b3\u03af\u03b1 \u03b8\u03b1 \u03b5\u03af\u03bd\u03b1\u03b9 \u03ba\u03c1\u03c5\u03bc\u03bc\u03ad\u03bd\u03b1 \u03b1\u03c0\u03cc \u03b1\u03c5\u03c4\u03cc\u03bd \u03c4\u03bf\u03bd \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7",
"LibraryAccessHelp": "\u0395\u03c0\u03b9\u03bb\u03ad\u03be\u03c4\u03b5 \u03c4\u03bf\u03c5\u03c2 \u03c6\u03b1\u03ba\u03ad\u03bb\u03bf\u03c5\u03c2 \u03bc\u03ad\u03c3\u03c9\u03bd \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03c4\u03bf \u03bc\u03bf\u03b9\u03c1\u03b1\u03c3\u03c4\u03b5\u03af\u03c4\u03b5 \u03bc\u03b5 \u03b1\u03c5\u03c4\u03cc\u03bd \u03c4\u03bf \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7. \u039f\u03b9 \u03b4\u03b9\u03b1\u03c7\u03b5\u03b9\u03c1\u03b9\u03c3\u03c4\u03ad\u03c2 \u03b8\u03b1 \u03ad\u03c7\u03bf\u03c5\u03bd \u03c4\u03b7 \u03b4\u03c5\u03bd\u03b1\u03c4\u03cc\u03c4\u03b7\u03c4\u03b1 \u03bd\u03b1 \u03b5\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03ac\u03b6\u03b5\u03c3\u03c4\u03b5 \u03cc\u03bb\u03b1 \u03c6\u03b1\u03ba\u03ad\u03bb\u03bf\u03c5\u03c2 \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03ce\u03bd\u03c4\u03b1\u03c2 \u03c4\u03b1 \u03bc\u03b5\u03c4\u03b1\u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03b1 manager.",
"ChannelAccessHelp": "Select the channels to share with this user. Administrators will be able to edit all channels using the metadata manager.",
"ButtonDeleteImage": "\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae \u03b5\u03b9\u03ba\u03cc\u03bd\u03b1\u03c2",
- "LabelSelectUsers": "Select users:",
+ "LabelSelectUsers": "\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u03a7\u03c1\u03b7\u03c3\u03c4\u03ce\u03bd:",
"ButtonUpload": "\u0391\u03bd\u03b5\u03b2\u03ac\u03c3\u03c4\u03b5 ",
"HeaderUploadNewImage": "\u0391\u03bd\u03b5\u03b2\u03ac\u03c3\u03c4\u03b5 \u03bd\u03ad\u03b1 \u03b5\u03b9\u03ba\u03cc\u03bd\u03b1",
- "LabelDropImageHere": "Drop image here",
- "ImageUploadAspectRatioHelp": "1:1 Aspect Ratio Recommended. JPG\/PNG only",
+ "LabelDropImageHere": "\u0391\u03c0\u03bf\u03b8\u03ad\u03c3\u03c4\u03b5 \u03b5\u03b9\u03ba\u03cc\u03bd\u03b1 \u03b5\u03b4\u03ce",
+ "ImageUploadAspectRatioHelp": "\u03a0\u03c1\u03bf\u03c4\u03b5\u03b9\u03bd\u03cc\u03bc\u03b5\u03bd\u03bf 1:1 Aspect Ratio. JPG\/PNG \u03bc\u03cc\u03bd\u03bf",
"MessageNothingHere": "\u03a4\u03af\u03c0\u03bf\u03c4\u03b1 \u03b5\u03b4\u03ce ",
"MessagePleaseEnsureInternetMetadata": "\u03a0\u03b1\u03c1\u03b1\u03ba\u03b1\u03bb\u03ce \u03b5\u03be\u03b1\u03c3\u03c6\u03b1\u03bb\u03af\u03c3\u03c4\u03b5 \u03c4\u03b7 \u03bb\u03ae\u03c8\u03b7 \u03bc\u03b5\u03c4\u03b1\u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03c9\u03bd \u03c3\u03c4\u03bf internet \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7.\n",
"TabSuggested": "\u03a0\u03c1\u03bf\u03c4\u03b5\u03b9\u03bd\u03cc\u03bc\u03b5\u03bd\u03b7",
- "TabLatest": "\u03c4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03bf\u03c2",
+ "TabSuggestions": "Suggestions",
+ "TabLatest": "\u03a4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03bf\u03c2",
"TabUpcoming": "\u0395\u03c0\u03b5\u03c1\u03c7\u03cc\u03bc\u03b5\u03bd\u03b7",
"TabShows": "\u0395\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1",
"TabEpisodes": "\u0395\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1",
@@ -176,88 +179,88 @@
"TabNetworks": "\u0394\u03af\u03ba\u03c4\u03c5\u03b1",
"HeaderUsers": "\u03a7\u03c1\u03ae\u03c3\u03c4\u03b5\u03c2 ",
"HeaderFilters": "\u03a6\u03af\u03bb\u03c4\u03c1\u03b1",
- "ButtonFilter": "\u03c6\u03af\u03bb\u03c4\u03c1\u03bf",
+ "ButtonFilter": "\u03a6\u03af\u03bb\u03c4\u03c1\u03bf",
"OptionFavorite": "\u0391\u03b3\u03b1\u03c0\u03b7\u03bc\u03ad\u03bd\u03b1",
"OptionLikes": "\u03a3\u03c5\u03bc\u03c0\u03b1\u03b8\u03b5\u03af",
"OptionDislikes": "\u0391\u03bd\u03c4\u03b9\u03c0\u03b1\u03b8\u03b5\u03af",
"OptionActors": "\u0397\u03b8\u03bf\u03c0\u03bf\u03b9\u03bf\u03af",
- "OptionGuestStars": "\u0393\u03ba\u03b5\u03c3\u03c4 \u03c3\u03c4\u03b1\u03c1",
+ "OptionGuestStars": "\u03a6\u03b9\u03bb\u03b9\u03ba\u03ae \u03a3\u03c5\u03bc\u03bc\u03b5\u03c4\u03bf\u03c7\u03ae",
"OptionDirectors": "\u03b4\u03b9\u03b5\u03c5\u03b8\u03c5\u03bd\u03c4\u03ad\u03c2",
"OptionWriters": "\u03a3\u03c5\u03b3\u03b3\u03c1\u03b1\u03c6\u03b5\u03af\u03c2",
- "OptionProducers": "\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03bf\u03af",
- "HeaderResume": "\u03a3\u03c5\u03bd\u03b5\u03c7\u03af\u03c3\u03b5\u03b9 ",
+ "OptionProducers": "\u03a0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03bf\u03af",
+ "HeaderResume": "\u0395\u03c0\u03b1\u03bd\u03b5\u03ba\u03ba\u03af\u03bd\u03b7\u03c3\u03b7",
"HeaderNextUp": "\u0395\u03c0\u03cc\u03bc\u03b5\u03bd\u03bf",
- "NoNextUpItemsMessage": "\u0394\u03b5\u03bd \u03b2\u03c1\u03ad\u03b8\u03b7\u03ba\u03b5 \u03ba\u03b1\u03bd\u03ad\u03bd\u03b1. \u039e\u03b5\u03ba\u03b9\u03bd\u03ae\u03c3\u03c4\u03b5 \u03c0\u03b1\u03c1\u03b1\u03ba\u03bf\u03bb\u03bf\u03c5\u03b8\u03ce\u03bd\u03c4\u03b1\u03c2 \u03b5\u03c0\u03b9\u03b4\u03b5\u03af\u03be\u03b5\u03b9\u03c2 \u03c3\u03b1\u03c2!",
- "HeaderLatestEpisodes": "\u03c4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03b1 \u03b5\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1",
+ "NoNextUpItemsMessage": "\u0394\u03b5\u03bd \u03b2\u03c1\u03ad\u03b8\u03b7\u03ba\u03b5 \u03ba\u03b1\u03bd\u03ad\u03bd\u03b1. \u039e\u03b5\u03ba\u03b9\u03bd\u03ae\u03c3\u03c4\u03b5 \u03c0\u03b1\u03c1\u03b1\u03ba\u03bf\u03bb\u03bf\u03c5\u03b8\u03ce\u03bd\u03c4\u03b1\u03c2 \u03c4\u03b9\u03c2 \u03b5\u03ba\u03c0\u03bf\u03bc\u03c0\u03ad\u03c2 \u03c3\u03b1\u03c2!",
+ "HeaderLatestEpisodes": "\u03a4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03b1 \u03b5\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1",
"HeaderPersonTypes": "Person Types:",
- "TabSongs": "\u03c4\u03c1\u03b1\u03b3\u03bf\u03cd\u03b4\u03b9\u03b1",
- "TabAlbums": "\u03ac\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc",
+ "TabSongs": "\u03a4\u03c1\u03b1\u03b3\u03bf\u03cd\u03b4\u03b9\u03b1",
+ "TabAlbums": "\u0386\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc",
"TabArtists": "\u039a\u03b1\u03bb\u03bb\u03b9\u03c4\u03ad\u03c7\u03bd\u03b5\u03c2",
- "TabAlbumArtists": "\u03ac\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc \u039a\u03b1\u03bb\u03bb\u03b9\u03c4\u03ad\u03c7\u03bd\u03b5\u03c2",
+ "TabAlbumArtists": "\u0386\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc \u039a\u03b1\u03bb\u03bb\u03b9\u03c4\u03ad\u03c7\u03bd\u03b5\u03c2",
"TabMusicVideos": "\u039c\u03bf\u03c5\u03c3\u03b9\u03ba\u03ac \u03b2\u03af\u03bd\u03c4\u03b5\u03bf",
- "ButtonSort": "\u03c4\u03b1\u03be\u03b9\u03bd\u03bf\u03bc\u03ae\u03c3\u03b5\u03c4\u03b5",
- "HeaderSortBy": "\u03a4\u03b1\u03be\u03b9\u03bd\u03cc\u03bc\u03b7\u03c3\u03b7 \u03ba\u03b1\u03c4\u03ac",
- "HeaderSortOrder": "\u03a3\u03b5\u03b9\u03c1\u03ac \u03c4\u03b1\u03be\u03b9\u03bd\u03cc\u03bc\u03b7\u03c3\u03b7\u03c2",
- "OptionPlayed": "\u03a0\u03b1\u03af\u03c7\u03b8\u03b7\u03ba\u03b5",
- "OptionUnplayed": "\u03b4\u03b5\u03bd \u03c0\u03b1\u03af\u03c7\u03b8\u03b7\u03ba\u03b5",
- "OptionAscending": "\u03b1\u03cd\u03be\u03bf\u03c5\u03c3\u03b1",
- "OptionDescending": "\u03c6\u03b8\u03af\u03bd\u03bf\u03c5\u03c3\u03b1 ",
+ "ButtonSort": "\u03a4\u03b1\u03be\u03b9\u03bd\u03cc\u03bc\u03b7\u03c3\u03b7",
+ "HeaderSortBy": "\u03a4\u03b1\u03be\u03b9\u03bd\u03cc\u03bc\u03b7\u03c3\u03b7 \u03ba\u03b1\u03c4\u03ac:",
+ "HeaderSortOrder": "\u03a3\u03b5\u03b9\u03c1\u03ac \u03c4\u03b1\u03be\u03b9\u03bd\u03cc\u03bc\u03b7\u03c3\u03b7\u03c2:",
+ "OptionPlayed": "\u0391\u03bd\u03b1\u03c0\u03b1\u03c1\u03ac\u03c7\u03b8\u03b7\u03ba\u03b5",
+ "OptionUnplayed": "\u0394\u03b5\u03bd \u03c0\u03b1\u03af\u03c7\u03b8\u03b7\u03ba\u03b5",
+ "OptionAscending": "\u0391\u03cd\u03be\u03bf\u03c5\u03c3\u03b1",
+ "OptionDescending": "\u03a6\u03b8\u03af\u03bd\u03bf\u03c5\u03c3\u03b1",
"OptionRuntime": "Runtime",
- "OptionReleaseDate": "Release Date",
- "OptionPlayCount": "Play Count",
- "OptionDatePlayed": "Date Played",
- "OptionDateAdded": "\u03b7\u03bc\u03b5\u03c1\u03bf\u03bc\u03b7\u03bd\u03af\u03b1 \u03c0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7\u03c2",
+ "OptionReleaseDate": "\u0397\u03bc\u03b5\u03c1\u03bf\u03bc\u03b7\u03bd\u03af\u03b1 \u03a0\u03c1\u03bf\u03b2\u03bf\u03bb\u03ae\u03c2",
+ "OptionPlayCount": "\u03a6\u03bf\u03c1\u03ad\u03c2 \u0391\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2",
+ "OptionDatePlayed": "\u0397\u03bc\u03b5\u03c1\u03bf\u03bc\u03b7\u03bd\u03af\u03b1 \u0391\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2",
+ "OptionDateAdded": "\u0397\u03bc\u03b5\u03c1\u03bf\u03bc\u03b7\u03bd\u03af\u03b1 \u03c0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7\u03c2",
"OptionAlbumArtist": "\u03ac\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc \u039a\u03b1\u03bb\u03bb\u03b9\u03c4\u03ad\u03c7\u03bd\u03b5\u03c2",
"OptionArtist": " \u039a\u03b1\u03bb\u03bb\u03b9\u03c4\u03ad\u03c7\u03bd\u03b5\u03c2",
- "OptionAlbum": "\u03ac\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc",
- "OptionTrackName": "Track Name",
- "OptionCommunityRating": "Community Rating",
- "OptionNameSort": "Name",
- "OptionFolderSort": "Folders",
- "OptionBudget": "Budget",
+ "OptionAlbum": "\u0386\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc",
+ "OptionTrackName": "\u038c\u03bd\u03bf\u03bc\u03b1 \u0391\u03c1\u03c7\u03b5\u03af\u03bf\u03c5",
+ "OptionCommunityRating": "\u0392\u03b1\u03b8\u03bc\u03bf\u03bb\u03bf\u03b3\u03af\u03b1 \u039a\u03bf\u03b9\u03bd\u03cc\u03c4\u03b7\u03c4\u03b1\u03c2",
+ "OptionNameSort": "\u038c\u03bd\u03bf\u03bc\u03b1",
+ "OptionFolderSort": "\u03a6\u03ac\u03ba\u03b5\u03bb\u03bf\u03b9",
+ "OptionBudget": "\u03a0\u03c1\u03bf\u03c5\u03c0\u03bf\u03bb\u03bf\u03b3\u03b9\u03c3\u03bc\u03cc\u03c2",
"OptionRevenue": "Revenue",
- "OptionPoster": "Poster",
+ "OptionPoster": "\u0391\u03c6\u03af\u03c3\u03b1",
"OptionPosterCard": "Poster card",
"OptionBackdrop": "Backdrop",
- "OptionTimeline": "Timeline",
+ "OptionTimeline": "\u03a7\u03c1\u03bf\u03bd\u03bf\u03b4\u03b9\u03ac\u03b3\u03c1\u03b1\u03bc\u03bc\u03b1",
"OptionThumb": "Thumb",
"OptionThumbCard": "Thumb card",
"OptionBanner": "Banner",
- "OptionCriticRating": "Critic Rating",
+ "OptionCriticRating": "\u0392\u03b1\u03b8\u03bc\u03bf\u03bb\u03bf\u03b3\u03af\u03b1 \u03ba\u03c1\u03b9\u03c4\u03b9\u03ba\u03ce\u03bd",
"OptionVideoBitrate": "Video Bitrate",
"OptionResumable": "Resumable",
- "ScheduledTasksHelp": "Click a task to adjust its schedule.",
- "ScheduledTasksTitle": "Scheduled Tasks",
- "TabMyPlugins": "My Plugins",
- "TabCatalog": "Catalog",
- "TitlePlugins": "Plugins",
- "HeaderAutomaticUpdates": "Automatic Updates",
- "HeaderNowPlaying": "Now Playing",
- "HeaderLatestAlbums": "Latest Albums",
- "HeaderLatestSongs": "Latest Songs",
+ "ScheduledTasksHelp": "\u0395\u03c0\u03b9\u03bb\u03ad\u03be\u03c4\u03b5 \u0395\u03c1\u03b3\u03b1\u03c3\u03af\u03b1 \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03c4\u03b5 \u03c4\u03bf \u03c0\u03c1\u03cc\u03b3\u03c1\u03b1\u03bc\u03bc\u03b1",
+ "ScheduledTasksTitle": "\u03a0\u03c1\u03bf\u03b3\u03c1\u03b1\u03bc\u03bc\u03b1\u03c4\u03b9\u03c3\u03bc\u03ad\u03bd\u03b5\u03c2 \u0395\u03c1\u03b3\u03b1\u03c3\u03af\u03b5\u03c2",
+ "TabMyPlugins": "\u03a4\u03b1 \u03c0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c4\u03b1 \u03bc\u03bf\u03c5",
+ "TabCatalog": "\u039a\u03b1\u03c4\u03ac\u03bb\u03bf\u03b3\u03bf\u03c2",
+ "TitlePlugins": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c4\u03b1",
+ "HeaderAutomaticUpdates": "\u0391\u03c5\u03c4\u03cc\u03bc\u03b1\u03c4\u03b5\u03c2 \u0391\u03bd\u03b1\u03bd\u03b5\u03ce\u03c3\u03b5\u03b9\u03c2",
+ "HeaderNowPlaying": "\u03a4\u03ce\u03c1\u03b1 \u03a0\u03b1\u03af\u03b6\u03b5\u03b9:",
+ "HeaderLatestAlbums": "\u03a4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03b1 \u0386\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc",
+ "HeaderLatestSongs": "\u03a4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03b1 \u03a4\u03c1\u03b1\u03b3\u03bf\u03cd\u03b4\u03b9\u03b1",
"HeaderRecentlyPlayed": "Recently Played",
"HeaderFrequentlyPlayed": "Frequently Played",
"DevBuildWarning": "Dev builds are the bleeding edge. Released often, these build have not been tested. The application may crash and entire features may not work at all.",
- "LabelVideoType": "Video Type:",
+ "LabelVideoType": "\u03a4\u03cd\u03c0\u03bf\u03c2 \u0392\u03af\u03bd\u03c4\u03b5\u03bf:",
"OptionBluray": "Bluray",
"OptionDvd": "Dvd",
"OptionIso": "Iso",
"Option3D": "3D",
"LabelFeatures": "Features:",
- "LabelService": "Service:",
- "LabelStatus": "Status:",
- "LabelVersion": "Version:",
- "LabelLastResult": "Last result:",
- "OptionHasSubtitles": "Subtitles",
- "OptionHasTrailer": "Trailer",
+ "LabelService": "\u03a5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1:",
+ "LabelStatus": "\u039a\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7:",
+ "LabelVersion": "\u0388\u03ba\u03b4\u03bf\u03c3\u03b7:",
+ "LabelLastResult": "\u03a4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03bf \u03b1\u03c0\u03bf\u03c4\u03ad\u03bb\u03b5\u03c3\u03bc\u03b1:",
+ "OptionHasSubtitles": "\u03a5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03b9",
+ "OptionHasTrailer": "\u03a4\u03c1\u03ad\u03ca\u03bb\u03b5\u03c1",
"OptionHasThemeSong": "Theme Song",
"OptionHasThemeVideo": "Theme Video",
- "TabMovies": "Movies",
- "TabStudios": "Studios",
+ "TabMovies": "\u03a4\u03b1\u03b9\u03bd\u03af\u03b5\u03c2",
+ "TabStudios": "\u03a3\u03c4\u03bf\u03cd\u03bd\u03c4\u03b9\u03bf",
"TabTrailers": "Trailers",
- "LabelArtists": "Artists:",
+ "LabelArtists": "\u039a\u03b1\u03bb\u03bb\u03b9\u03c4\u03ad\u03c7\u03bd\u03b5\u03c2",
"LabelArtistsHelp": "Separate multiple using ;",
- "HeaderLatestMovies": "Latest Movies",
+ "HeaderLatestMovies": "\u03a4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03b5\u03c2 \u03a4\u03b1\u03b9\u03bd\u03af\u03b5\u03c2",
"HeaderLatestTrailers": "Latest Trailers",
"OptionHasSpecialFeatures": "Special Features",
"OptionImdbRating": "IMDb Rating",
@@ -284,23 +287,23 @@
"OptionFileMetadataYearMismatch": "File\/Metadata Years Mismatched",
"TabGeneral": "General",
"TitleSupport": "Support",
- "TabLog": "Log",
- "TabAbout": "About",
- "TabSupporterKey": "Supporter Key",
- "TabBecomeSupporter": "Become a Supporter",
+ "TabLog": "\u0391\u03c1\u03c7\u03b5\u03af\u03bf \u039a\u03b1\u03c4\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2",
+ "TabAbout": "\u03a0\u03b5\u03c1\u03af..",
+ "TabSupporterKey": "\u03a3\u03b5\u03b9\u03c1\u03b9\u03b1\u03ba\u03cc\u03c2 \u03a5\u03c0\u03bf\u03c3\u03c4\u03ae\u03c1\u03b9\u03be\u03b7\u03c2",
+ "TabBecomeSupporter": "\u0393\u03af\u03bd\u03b5 \u03a5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03b9\u03ba\u03c4\u03ae\u03c2",
"ProjectHasCommunity": "Emby has a thriving community of users and contributors.",
"CheckoutKnowledgeBase": "Check out our knowledge base to help you get the most out of Emby.",
- "SearchKnowledgeBase": "Search the Knowledge Base",
+ "SearchKnowledgeBase": "\u0391\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b5 \u03c3\u03c4\u03b7 \u0392\u03ac\u03c3\u03b7",
"VisitTheCommunity": "Visit the Community",
- "VisitProjectWebsite": "Visit the Emby Web Site",
+ "VisitProjectWebsite": "\u0395\u03c0\u03b9\u03c3\u03ba\u03ad\u03c8\u03bf\u03c5 \u03c4\u03b7 \u03a3\u03b5\u03bb\u03af\u03b4\u03b1 \u03c4\u03bf\u03c5 Emby",
"VisitProjectWebsiteLong": "Visit the Emby Web site to catch the latest news and keep up with the developer blog.",
"OptionHideUser": "Hide this user from login screens",
"OptionHideUserFromLoginHelp": "Useful for private or hidden administrator accounts. The user will need to sign in manually by entering their username and password.",
- "OptionDisableUser": "Disable this user",
+ "OptionDisableUser": "\u0391\u03c0\u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03b7 \u03a7\u03c1\u03ae\u03c3\u03c4\u03b7",
"OptionDisableUserHelp": "If disabled the server will not allow any connections from this user. Existing connections will be abruptly terminated.",
"HeaderAdvancedControl": "Advanced Control",
- "LabelName": "Name:",
- "ButtonHelp": "Help",
+ "LabelName": "\u038c\u03bd\u03bf\u03bc\u03b1:",
+ "ButtonHelp": "\u0392\u03bf\u03ae\u03b8\u03b5\u03b9\u03b1",
"OptionAllowUserToManageServer": "Allow this user to manage the server",
"HeaderFeatureAccess": "Feature Access",
"OptionAllowMediaPlayback": "Allow media playback",
@@ -310,33 +313,33 @@
"OptionAllowRemoteControlOthers": "Allow remote control of other users",
"OptionAllowRemoteSharedDevices": "Allow remote control of shared devices",
"OptionAllowRemoteSharedDevicesHelp": "Dlna devices are considered shared until a user begins controlling it.",
- "HeaderRemoteControl": "Remote Control",
+ "HeaderRemoteControl": "\u03a4\u03b7\u03bb\u03b5\u03c7\u03b5\u03b9\u03c1\u03b9\u03c3\u03c4\u03ae\u03c1\u03b9\u03bf",
"OptionMissingTmdbId": "Missing Tmdb Id",
"OptionIsHD": "HD",
"OptionIsSD": "SD",
- "OptionMetascore": "Metascore",
- "ButtonSelect": "Select",
+ "OptionMetascore": "\u0392\u03b1\u03b8\u03bc\u03bf\u03bb\u03bf\u03b3\u03af\u03b1",
+ "ButtonSelect": "\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae",
"ButtonGroupVersions": "Group Versions",
- "ButtonAddToCollection": "Add to Collection",
+ "ButtonAddToCollection": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c3\u03b5 \u03c3\u03c4\u03b7 \u03a3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ae",
"PismoMessage": "Utilizing Pismo File Mount through a donated license.",
"TangibleSoftwareMessage": "Utilizing Tangible Solutions Java\/C# converters through a donated license.",
"HeaderCredits": "Credits",
"PleaseSupportOtherProduces": "Please support other free products we utilize:",
- "VersionNumber": "Version {0}",
- "TabPaths": "Paths",
- "TabServer": "Server",
+ "VersionNumber": "\u0388\u03ba\u03b4\u03bf\u03c3\u03b7 {0}",
+ "TabPaths": "\u0394\u03b9\u03b1\u03b4\u03c1\u03bf\u03bc\u03ae",
+ "TabServer": "\u0394\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae\u03c2",
"TabTranscoding": "Transcoding",
"TitleAdvanced": "Advanced",
"LabelAutomaticUpdateLevel": "Automatic update level",
"OptionRelease": "\u0397 \u03b5\u03c0\u03af\u03c3\u03b7\u03bc\u03b7 \u03ad\u03ba\u03b4\u03bf\u03c3\u03b7",
- "OptionBeta": "\u03b2\u03ae\u03c4\u03b1",
- "OptionDev": "\u03b1\u03bd\u03ac\u03c0\u03c4\u03c5\u03be\u03b7 (\u03b1\u03c3\u03c4\u03b1\u03b8\u03ae\u03c2)",
- "LabelAllowServerAutoRestart": "Allow the server to restart automatically to apply updates",
- "LabelAllowServerAutoRestartHelp": "The server will only restart during idle periods, when no users are active.",
+ "OptionBeta": "\u0394\u03bf\u03ba\u03b9\u03bc\u03b1\u03c3\u03c4\u03b9\u03ba\u03ae",
+ "OptionDev": "\u0391\u03bd\u03ac\u03c0\u03c4\u03c5\u03be\u03b7 (\u03b1\u03c3\u03c4\u03b1\u03b8\u03ae\u03c2)",
+ "LabelAllowServerAutoRestart": "\u0391\u03c5\u03c4\u03cc\u03bc\u03b1\u03c4\u03b7 \u03b5\u03c0\u03b1\u03bd\u03b5\u03ba\u03ba\u03af\u03bd\u03b7\u03c3\u03b7 \u03c4\u03bf\u03c5 \u03c3\u03ad\u03c1\u03b2\u03b5\u03c1 \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03b5\u03b3\u03ba\u03b1\u03c4\u03b1\u03c3\u03c4\u03ae\u03c3\u03b5\u03b9 \u03c4\u03b9\u03c2 \u03b1\u03bd\u03b1\u03b2\u03b1\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2",
+ "LabelAllowServerAutoRestartHelp": "\u039f \u03a3\u03b5\u03c1\u03b2\u03b5\u03c1 \u03b8\u03b1 \u03ba\u03ac\u03bd\u03b5\u03b9 \u03bc\u03cc\u03bd\u03bf \u03b5\u03c0\u03b1\u03bd\u03b5\u03ba\u03ba\u03b9\u03bd\u03ae\u03c3\u03b5\u03b9\u03c2 \u03c4\u03b9\u03c2 \u03bc\u03b7 \u03b5\u03bd\u03b5\u03c1\u03b3\u03ad\u03c2 \u03c0\u03b5\u03c1\u03b9\u03cc\u03b4\u03bf\u03c5\u03c2, \u03cc\u03c4\u03b1\u03bd \u03ba\u03b1\u03bd\u03b5\u03af\u03c2 \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7\u03c2 \u03b4\u03b5\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03cc\u03c2.",
"LabelEnableDebugLogging": "Enable debug logging",
- "LabelRunServerAtStartup": "Run server at startup",
+ "LabelRunServerAtStartup": "\u039e\u03b5\u03ba\u03af\u03bd\u03b7\u03c3\u03b5 \u03c4\u03bf\u03bd \u03a3\u03b5\u03c1\u03b2\u03b5\u03c1 \u03ba\u03b1\u03c4\u03ac \u03c4\u03b7\u03bd \u03b5\u03ba\u03ba\u03af\u03bd\u03b7\u03c3\u03b7",
"LabelRunServerAtStartupHelp": "This will start the tray icon on windows startup. To start the windows service, uncheck this and run the service from the windows control panel. Please note that you cannot run both at the same time, so you will need to exit the tray icon before starting the service.",
- "ButtonSelectDirectory": "Select Directory",
+ "ButtonSelectDirectory": "\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u03a6\u03b1\u03ba\u03ad\u03bb\u03bf\u03c5",
"LabelCustomPaths": "Specify custom paths where desired. Leave fields empty to use the defaults.",
"LabelCachePath": "Cache path:",
"LabelCachePathHelp": "Specify a custom location for server cache files, such as images.",
@@ -346,17 +349,17 @@
"LabelMetadataPathHelp": "Specify a custom location for downloaded artwork and metadata, if not saving within media folders.",
"LabelTranscodingTempPath": "Transcoding temporary path:",
"LabelTranscodingTempPathHelp": "This folder contains working files used by the transcoder. Specify a custom path, or leave empty to use the default within the server's data folder.",
- "TabBasics": "Basics",
- "TabTV": "TV",
- "TabGames": "Games",
- "TabMusic": "Music",
- "TabOthers": "Others",
+ "TabBasics": "\u0392\u03b1\u03c3\u03b9\u03ba\u03ac",
+ "TabTV": "\u03a4\u03b7\u03bb\u03b5\u03cc\u03c1\u03b1\u03c3\u03b7",
+ "TabGames": "\u03a0\u03b1\u03b9\u03c7\u03bd\u03af\u03b4\u03b9\u03b1",
+ "TabMusic": "\u039c\u03bf\u03c5\u03c3\u03b9\u03ba\u03ae",
+ "TabOthers": "\u0386\u03bb\u03bb\u03b1",
"HeaderExtractChapterImagesFor": "Extract chapter images for:",
- "OptionMovies": "Movies",
- "OptionEpisodes": "Episodes",
- "OptionOtherVideos": "Other Videos",
+ "OptionMovies": "\u03a4\u03b1\u03b9\u03bd\u03af\u03b5\u03c2",
+ "OptionEpisodes": "\u0395\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1",
+ "OptionOtherVideos": "\u0386\u03bb\u03bb\u03b1 \u0392\u03af\u03bd\u03c4\u03b5\u03bf",
"TitleMetadata": "Metadata",
- "LabelAutomaticUpdates": "Enable automatic updates",
+ "LabelAutomaticUpdates": "\u0391\u03c5\u03c4\u03cc\u03bc\u03b1\u03c4\u03b5\u03c2 \u0395\u03bd\u03b7\u03bc\u03b5\u03c1\u03ce\u03c3\u03b5\u03b9\u03c2",
"LabelAutomaticUpdatesTmdb": "Enable automatic updates from TheMovieDB.org",
"LabelAutomaticUpdatesTvdb": "Enable automatic updates from TheTVDB.com",
"LabelAutomaticUpdatesFanartHelp": "If enabled, new images will be downloaded automatically as they're added to fanart.tv. Existing images will not be replaced.",
@@ -371,19 +374,19 @@
"LabelImageSavingConventionHelp": "Emby recognizes images from most major media applications. Choosing your downloading convention is useful if you also use other products.",
"OptionImageSavingCompatible": "Compatible - Emby\/Kodi\/Plex",
"OptionImageSavingStandard": "Standard - MB2",
- "ButtonSignIn": "Sign In",
- "TitleSignIn": "Sign In",
- "HeaderPleaseSignIn": "Please sign in",
- "LabelUser": "User:",
- "LabelPassword": "Password:",
- "ButtonManualLogin": "Manual Login",
+ "ButtonSignIn": "\u0395\u03af\u03c3\u03bf\u03b4\u03bf\u03c2",
+ "TitleSignIn": "\u0395\u03af\u03c3\u03bf\u03b4\u03bf\u03c2",
+ "HeaderPleaseSignIn": "\u03a0\u03b1\u03c1\u03b1\u03ba\u03b1\u03bb\u03ce \u03b5\u03b9\u03c3\u03ad\u03bb\u03b8\u03b5\u03c4\u03b5",
+ "LabelUser": "\u03a7\u03c1\u03ae\u03c3\u03c4\u03b7\u03c2:",
+ "LabelPassword": "\u039a\u03c9\u03b4\u03b9\u03ba\u03cc\u03c2:",
+ "ButtonManualLogin": "\u03a7\u03b5\u03b9\u03c1\u03bf\u03ba\u03af\u03bd\u03b7\u03c4\u03b7 \u0395\u03af\u03c3\u03bf\u03b4\u03bf\u03c2",
"PasswordLocalhostMessage": "Passwords are not required when logging in from localhost.",
- "TabGuide": "Guide",
- "TabChannels": "Channels",
- "TabCollections": "Collections",
- "HeaderChannels": "Channels",
- "TabRecordings": "Recordings",
- "TabScheduled": "Scheduled",
+ "TabGuide": "\u039f\u03b4\u03b7\u03b3\u03cc\u03c2",
+ "TabChannels": "\u039a\u03b1\u03bd\u03ac\u03bb\u03b9\u03b1",
+ "TabCollections": "\u03a3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ad\u03c2",
+ "HeaderChannels": "\u039a\u03b1\u03bd\u03ac\u03bb\u03b9\u03b1",
+ "TabRecordings": "\u0395\u03b3\u03b3\u03c1\u03b1\u03c6\u03ad\u03c2",
+ "TabScheduled": "\u03a0\u03c1\u03bf\u03b3\u03c1\u03b1\u03bc\u03bc\u03b1\u03c4\u03b9\u03c3\u03bc\u03ad\u03bd\u03b1",
"TabSeries": "Series",
"TabFavorites": "Favorites",
"TabMyLibrary": "My Library",
@@ -401,9 +404,10 @@
"ButtonRefresh": "Refresh",
"ButtonAdvancedRefresh": "Advanced Refresh",
"OptionPriority": "Priority",
- "OptionRecordOnAllChannels": "Record program on all channels",
- "OptionRecordAnytime": "Record program at any time",
+ "OptionRecordOnAllChannels": "Record on all channels",
+ "OptionRecordAnytime": "Record at any time",
"OptionRecordOnlyNewEpisodes": "Record only new episodes",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "Days",
"HeaderActiveRecordings": "Active Recordings",
"HeaderLatestRecordings": "Latest Recordings",
@@ -430,65 +434,65 @@
"OptionDownloadDiscImage": "Disc",
"OptionDownloadBannerImage": "Banner",
"OptionDownloadBackImage": "Back",
- "OptionDownloadArtImage": "Art",
- "OptionDownloadPrimaryImage": "Primary",
+ "OptionDownloadArtImage": "\u03a4\u03ad\u03c7\u03bd\u03b7",
+ "OptionDownloadPrimaryImage": "\u03a0\u03c1\u03ce\u03c4\u03bf",
"HeaderFetchImages": "Fetch Images:",
- "HeaderImageSettings": "Image Settings",
- "TabOther": "Other",
+ "HeaderImageSettings": "\u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2 \u0395\u03b9\u03ba\u03cc\u03bd\u03b1\u03c2",
+ "TabOther": "\u0386\u03bb\u03bb\u03b1",
"LabelMaxBackdropsPerItem": "Maximum number of backdrops per item:",
"LabelMaxScreenshotsPerItem": "Maximum number of screenshots per item:",
"LabelMinBackdropDownloadWidth": "Minimum backdrop download width:",
"LabelMinScreenshotDownloadWidth": "Minimum screenshot download width:",
"ButtonAddScheduledTaskTrigger": "Add Trigger",
"HeaderAddScheduledTaskTrigger": "Add Trigger",
- "ButtonAdd": "Add",
+ "ButtonAdd": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c3\u03b5",
"LabelTriggerType": "Trigger Type:",
- "OptionDaily": "Daily",
- "OptionWeekly": "Weekly",
+ "OptionDaily": "\u039a\u03b1\u03b8\u03b7\u03bc\u03b5\u03c1\u03b9\u03bd\u03ac",
+ "OptionWeekly": "\u0395\u03b2\u03b4\u03bf\u03bc\u03b1\u03b4\u03b9\u03b1\u03af\u03b1",
"OptionOnInterval": "On an interval",
"OptionOnAppStartup": "On application startup",
"OptionAfterSystemEvent": "After a system event",
- "LabelDay": "Day:",
- "LabelTime": "Time:",
- "LabelEvent": "Event:",
- "OptionWakeFromSleep": "Wake from sleep",
- "LabelEveryXMinutes": "Every:",
+ "LabelDay": "\u0397\u03bc\u03ad\u03c1\u03b1:",
+ "LabelTime": "\u038f\u03c1\u03b1:",
+ "LabelEvent": "\u0393\u03b5\u03b3\u03bf\u03bd\u03cc\u03c2:",
+ "OptionWakeFromSleep": "\u0395\u03c0\u03b1\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03b7",
+ "LabelEveryXMinutes": "\u039a\u03ac\u03b8\u03b5:",
"HeaderTvTuners": "Tuners",
"HeaderGallery": "Gallery",
- "HeaderLatestGames": "Latest Games",
- "HeaderRecentlyPlayedGames": "Recently Played Games",
+ "HeaderLatestGames": "\u03a4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03b1 \u03a0\u03b1\u03b9\u03c7\u03bd\u03af\u03b4\u03b9\u03b1",
+ "HeaderRecentlyPlayedGames": "\u03a4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03b1 \u03a0\u03b1\u03b9\u03c7\u03bd\u03af\u03b4\u03b9\u03b1 \u03c0\u03bf\u03c5 \u03c0\u03b1\u03af\u03c7\u03c4\u03b7\u03ba\u03b1\u03bd",
"TabGameSystems": "Game Systems",
- "TitleMediaLibrary": "Media Library",
- "TabFolders": "Folders",
+ "TitleMediaLibrary": "\u0392\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7 \u03a0\u03bf\u03bb\u03c5\u03bc\u03ad\u03c3\u03c9\u03bd",
+ "TabFolders": "\u03a6\u03ac\u03ba\u03b5\u03bb\u03bf\u03b9",
"TabPathSubstitution": "Path Substitution",
"LabelSeasonZeroDisplayName": "Season 0 display name:",
"LabelEnableRealtimeMonitor": "Enable real time monitoring",
"LabelEnableRealtimeMonitorHelp": "Changes will be processed immediately, on supported file systems.",
- "ButtonScanLibrary": "Scan Library",
- "HeaderNumberOfPlayers": "Players:",
- "OptionAnyNumberOfPlayers": "Any",
+ "ButtonScanLibrary": "\u03a8\u03ac\u03be\u03b5 \u0392\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7",
+ "HeaderNumberOfPlayers": "\u03a0\u03c1\u03bf\u03b3\u03c1\u03ac\u03bc\u03bc\u03b1\u03c4\u03b1 \u0391\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2:",
+ "OptionAnyNumberOfPlayers": "\u038c\u03bb\u03b1",
"Option1Player": "1+",
"Option2Player": "2+",
"Option3Player": "3+",
"Option4Player": "4+",
- "HeaderMediaFolders": "Media Folders",
- "HeaderThemeVideos": "Theme Videos",
- "HeaderThemeSongs": "Theme Songs",
- "HeaderScenes": "Scenes",
- "HeaderAwardsAndReviews": "Awards and Reviews",
- "HeaderSoundtracks": "Soundtracks",
- "HeaderMusicVideos": "Music Videos",
- "HeaderSpecialFeatures": "Special Features",
- "HeaderCastCrew": "Cast & Crew",
- "HeaderAdditionalParts": "Additional Parts",
+ "HeaderMediaFolders": "\u03a6\u03ac\u03ba\u03b5\u03bb\u03bf\u03b9 \u03a0\u03bf\u03bb\u03c5\u03bc\u03ad\u03c3\u03c9\u03bd",
+ "HeaderThemeVideos": "\u0398\u03b5\u03bc\u03b1\u03c4\u03b9\u03ba\u03ac \u0392\u03af\u03bd\u03c4\u03b5\u03bf",
+ "HeaderThemeSongs": "\u0398\u03b5\u03bc\u03b1\u03c4\u03b9\u03ba\u03ac \u03a4\u03c1\u03b1\u03b3\u03bf\u03cd\u03b4\u03b9\u03b1",
+ "HeaderScenes": "\u03a3\u03ba\u03b7\u03bd\u03ad\u03c2",
+ "HeaderAwardsAndReviews": "\u0392\u03c1\u03b1\u03b2\u03b5\u03af\u03b1 \u03ba\u03b1\u03b9 \u0392\u03b1\u03b8\u03bc\u03bf\u03bb\u03bf\u03b3\u03af\u03b1",
+ "HeaderSoundtracks": "\u039c\u03bf\u03c5\u03c3\u03b9\u03ba\u03ae \u03a4\u03b1\u03b9\u03bd\u03af\u03b1\u03c2",
+ "HeaderMusicVideos": "\u0392\u03af\u03bd\u03c4\u03b5\u03bf \u039c\u03bf\u03c5\u03c3\u03b9\u03ba\u03ae\u03c2",
+ "HeaderSpecialFeatures": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c4\u03b5\u03c2 \u03a3\u03ba\u03b7\u03bd\u03ad\u03c2",
+ "HeaderCastCrew": "\u0397\u03b8\u03bf\u03c0\u03bf\u03b9\u03bf\u03af \u03ba\u03b1\u03b9 \u03c3\u03c5\u03bd\u03b5\u03c1\u03b3\u03b5\u03af\u03bf",
+ "HeaderAdditionalParts": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c4\u03b1 \u039c\u03ad\u03c1\u03b7",
"ButtonSplitVersionsApart": "Split Versions Apart",
"ButtonPlayTrailer": "Trailer",
"LabelMissing": "Missing",
- "LabelOffline": "Offline",
+ "LabelOffline": "\u0395\u03ba\u03c4\u03cc\u03c2",
"PathSubstitutionHelp": "Path substitutions are used for mapping a path on the server to a path that clients are able to access. By allowing clients direct access to media on the server they may be able to play them directly over the network and avoid using server resources to stream and transcode them.",
- "HeaderFrom": "From",
+ "HeaderFrom": "\u0391\u03c0\u03cc",
"HeaderTo": "To",
- "LabelFrom": "From:",
+ "LabelFrom": "\u0391\u03c0\u03cc:",
"LabelFromHelp": "Example: D:\\Movies (on the server)",
"LabelTo": "To:",
"LabelToHelp": "Example: \\\\MyServer\\Movies (a path clients can access)",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "Web socket port number:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Home page section 2:",
"LabelHomePageSection3": "Home page section 3:",
"LabelHomePageSection4": "Home page section 4:",
- "OptionMyViewsButtons": "My views (buttons)",
- "OptionMyViews": "My views",
- "OptionMyViewsSmall": "My views (small)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Resume",
"OptionLatestMedia": "Latest media",
"OptionLatestChannelMedia": "Latest channel items",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Default",
"OptionCommunityMostWatchedSort": "Most Watched",
"TabNextUp": "Next Up",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
"MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favorites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Display Settings",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "More...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ 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 81bee1153..60eadcd17 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/en_GB.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/en_GB.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Add User",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
"LabelPinCode": "Pin code:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "Ok",
"ButtonCancel": "Cancel",
"ButtonExit": "Exit",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Nothing here.",
"MessagePleaseEnsureInternetMetadata": "Please ensure downloading of internet metadata is enabled.",
"TabSuggested": "Suggested",
+ "TabSuggestions": "Suggestions",
"TabLatest": "Latest",
"TabUpcoming": "Upcoming",
"TabShows": "Shows",
@@ -404,6 +407,7 @@
"OptionRecordOnAllChannels": "Record programme on all channels",
"OptionRecordAnytime": "Record programme at any time",
"OptionRecordOnlyNewEpisodes": "Record only new episodes",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "Days",
"HeaderActiveRecordings": "Active Recordings",
"HeaderLatestRecordings": "Latest Recordings",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "Web socket port number:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Home page section 2:",
"LabelHomePageSection3": "Home page section 3:",
"LabelHomePageSection4": "Home page section 4:",
- "OptionMyViewsButtons": "My views (buttons)",
- "OptionMyViews": "My views",
- "OptionMyViewsSmall": "My views (small)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Resume",
"OptionLatestMedia": "Latest media",
"OptionLatestChannelMedia": "Latest channel items",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Default",
"OptionCommunityMostWatchedSort": "Most Watched",
"TabNextUp": "Next Up",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
"MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favourites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Display Settings",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "More...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ 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 86cb406b5..038b9b8e1 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/en_US.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/en_US.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Add User",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
"LabelPinCode": "Pin code:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "Ok",
"ButtonCancel": "Cancel",
"ButtonExit": "Exit",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Nothing here.",
"MessagePleaseEnsureInternetMetadata": "Please ensure downloading of internet metadata is enabled.",
"TabSuggested": "Suggested",
+ "TabSuggestions": "Suggestions",
"TabLatest": "Latest",
"TabUpcoming": "Upcoming",
"TabShows": "Shows",
@@ -401,9 +404,10 @@
"ButtonRefresh": "Refresh",
"ButtonAdvancedRefresh": "Advanced Refresh",
"OptionPriority": "Priority",
- "OptionRecordOnAllChannels": "Record program on all channels",
- "OptionRecordAnytime": "Record program at any time",
+ "OptionRecordOnAllChannels": "Record on all channels",
+ "OptionRecordAnytime": "Record at any time",
"OptionRecordOnlyNewEpisodes": "Record only new episodes",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "Days",
"HeaderActiveRecordings": "Active Recordings",
"HeaderLatestRecordings": "Latest Recordings",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "Web socket port number:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Home page section 2:",
"LabelHomePageSection3": "Home page section 3:",
"LabelHomePageSection4": "Home page section 4:",
- "OptionMyViewsButtons": "My views (buttons)",
- "OptionMyViews": "My views",
- "OptionMyViewsSmall": "My views (small)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Resume",
"OptionLatestMedia": "Latest media",
"OptionLatestChannelMedia": "Latest channel items",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Default",
"OptionCommunityMostWatchedSort": "Most Watched",
"TabNextUp": "Next Up",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
"MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favorites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Display Settings",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "More...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ 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 c1c3605b7..6e2bf2efe 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/es.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/es.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Add User",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
"LabelPinCode": "Pin code:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "OK",
"ButtonCancel": "Cancelar",
"ButtonExit": "Exit",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Nada aqu\u00ed.",
"MessagePleaseEnsureInternetMetadata": "Por favor aseg\u00farese que la descarga de metadata de internet esta habilitada",
"TabSuggested": "Sugerencia",
+ "TabSuggestions": "Suggestions",
"TabLatest": "Novedades",
"TabUpcoming": "Pr\u00f3ximos",
"TabShows": "Programas",
@@ -401,9 +404,10 @@
"ButtonRefresh": "Refrescar",
"ButtonAdvancedRefresh": "Advanced Refresh",
"OptionPriority": "Prioridad",
- "OptionRecordOnAllChannels": "Grabar programa en cualquier canal",
- "OptionRecordAnytime": "Grabar programa a cualquier hora",
+ "OptionRecordOnAllChannels": "Grabar en cualquier canal",
+ "OptionRecordAnytime": "Grabar a cualquier hora",
"OptionRecordOnlyNewEpisodes": "Grabar s\u00f3lo nuevos episodios",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "D\u00edas",
"HeaderActiveRecordings": "Grabaciones activas",
"HeaderLatestRecordings": "\u00daltimas grabaciones",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "N\u00famero de puerto WebSocket:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Home page section 2:",
"LabelHomePageSection3": "Home page section 3:",
"LabelHomePageSection4": "Home page section 4:",
- "OptionMyViewsButtons": "Mis vistas (botones)",
- "OptionMyViews": "Mis vistas",
- "OptionMyViewsSmall": "Mis vistas (peque\u00f1o)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Continuar",
"OptionLatestMedia": "\u00daltimos medios",
"OptionLatestChannelMedia": "Ultimos elementos de canales",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Por defecto",
"OptionCommunityMostWatchedSort": "M\u00e1s visto",
"TabNextUp": "Siguiendo",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"MessageNoMovieSuggestionsAvailable": "No hay sugerencias de pel\u00edculas disponibles. Comience ver y calificar sus pel\u00edculas y vuelva para ver las recomendaciones.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
"MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favorites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Configuraci\u00f3n de pantalla",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "More...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ 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 26a7e7f17..d78da7f54 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/es_MX.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/es_MX.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Agregar Usuario",
"LabelAddConnectSupporterHelp": "Para agregar un usuario que no esta listado, necesita primero enlazar su cuenta a Emby Connect desde su pagina de perfil de usuario.",
"LabelPinCode": "C\u00f3digo pin:",
+ "OptionHideWatchedContentFromLatestMedia": "Ocultar contenido ya visto de medios recientes",
+ "HeaderSync": "Sinc",
"ButtonOk": "Ok",
"ButtonCancel": "Cancelar",
"ButtonExit": "Salir",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Nada aqu\u00ed.",
"MessagePleaseEnsureInternetMetadata": "Por favor aseg\u00farese que la descarga de metadatos de internet esta habilitada.",
"TabSuggested": "Sugerencias",
+ "TabSuggestions": "Sugerencias",
"TabLatest": "Recientes",
"TabUpcoming": "Por Estrenar",
"TabShows": "Programas",
@@ -401,9 +404,10 @@
"ButtonRefresh": "Actualizar",
"ButtonAdvancedRefresh": "Actualizaci\u00f3n Avanzada",
"OptionPriority": "Prioridad",
- "OptionRecordOnAllChannels": "Grabar programa en todos los canales",
- "OptionRecordAnytime": "Grabar programa en cualquier momento",
+ "OptionRecordOnAllChannels": "Grabar en todos los canales",
+ "OptionRecordAnytime": "Grabar en cualquier momento",
"OptionRecordOnlyNewEpisodes": "Grabar s\u00f3lo nuevos episodios",
+ "HeaderRepeatingOptions": "Opciones de repetici\u00f3n",
"HeaderDays": "D\u00edas",
"HeaderActiveRecordings": "Grabaciones Activas",
"HeaderLatestRecordings": "Grabaciones Recientes",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "N\u00famero de puerto https publico:",
"LabelPublicHttpsPortHelp": "El n\u00famero de puerto p\u00fablico que deber\u00e1 ser mapeado al puerto local de https.",
"LabelEnableHttps": "Reportar https como una direcci\u00f3n externa",
- "LabelEnableHttpsHelp": "Si se habilita, el servidor reportara a los clientes una url https como su direcci\u00f3n externa. Esto podr\u00eda inutilizar a los clientes que aun no soporten https.",
+ "LabelEnableHttpsHelp": "Al habilitarse, el servidor reportara un URL https a los clientes como su direcci\u00f3n externa.",
"LabelHttpsPort": "N\u00famero de puerto https local:",
"LabelHttpsPortHelp": "El numero de puerto tcp con el que se deber\u00e1 vincular el servidor https de Emby.",
"LabelWebSocketPortNumber": "N\u00famero de puerto WebSocket:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Pagina de Inicio secci\u00f3n dos:",
"LabelHomePageSection3": "Pagina de Inicio secci\u00f3n tres:",
"LabelHomePageSection4": "Pagina de Inicio secci\u00f3n cuatro:",
- "OptionMyViewsButtons": "Mis vistas (botones)",
- "OptionMyViews": "Mis vistas",
- "OptionMyViewsSmall": "Mis vistas (peque\u00f1o)",
+ "OptionMyMediaButtons": "Mis medios (botones)",
+ "OptionMyMedia": "Mis medios",
+ "OptionMyMediaSmall": "Mis medios (peque\u00f1o)",
"OptionResumablemedia": "Continuar",
"OptionLatestMedia": "Medios recientes",
"OptionLatestChannelMedia": "Elementos recientes de canales",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Por defecto",
"OptionCommunityMostWatchedSort": "M\u00e1s Visto",
"TabNextUp": "A Continuaci\u00f3n",
+ "PlaceholderUsername": "Nombre de Usuario",
"HeaderBecomeProjectSupporter": "Convi\u00e9rtete en un Fan\u00e1tico Emby",
- "TextEnjoyBonusFeatures": "Disfruta de Caracter\u00edsticas Premium",
"MessageNoMovieSuggestionsAvailable": "No hay sugerencias de pel\u00edculas disponibles en este momento. Comienza a ver y a calificar tus pel\u00edculas, y regresa para ver tus recomendaciones.",
"MessageNoCollectionsAvailable": "Las colecciones le permiten disfrutar de agrupaciones personalizadas de Pel\u00edculas, Series, \u00c1lbumes, Libros y Juegos. Haga clic en el bot\u00f3n + para iniciar la creaci\u00f3n de Colecciones.",
"MessageNoPlaylistsAvailable": "Las listas de reproducci\u00f3n le permiten crear listas de contenidos a ser reproducidos de manera consecutiva. Para agregar \u00edtems a una lista de reproducci\u00f3n, haga clic derecho o seleccione y mantenga, despu\u00e9s seleccione Agregar a Lista de Reproducci\u00f3n.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favoritos",
"ViewTypeMovieGenres": "G\u00e9neros",
"ViewTypeMusicLatest": "Recientes",
+ "ViewTypeMusicPlaylists": "Listas",
"ViewTypeMusicAlbums": "\u00c1lbumes",
"ViewTypeMusicAlbumArtists": "Artistas del \u00c1lbum",
"HeaderOtherDisplaySettings": "Configuraci\u00f3n de Pantalla",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Descargar metadatos de Internet para:",
"OptionTVMovies": "Pel\u00edculas de TV",
"HeaderUpcomingMovies": "Pel\u00edculas por Estrenar",
+ "HeaderUpcomingSports": "Deportes por Estrenar",
"HeaderUpcomingPrograms": "Programas por Estrenar",
"ButtonMoreItems": "M\u00e1s...",
"LabelShowLibraryTileNames": "Mostrar nombres de t\u00edtulo de las bibliotecas",
"LabelShowLibraryTileNamesHelp": "Determina si se desplegar\u00e1n etiquetas debajo de los t\u00edtulos de las bibliotecas con la p\u00e1gina principal",
- "OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottle": "Habilitar contenci\u00f3n",
+ "OptionEnableTranscodingThrottleHelp": "La contenci\u00f3n permite ajustar autom\u00e1ticamente la velocidad de transcodificaci\u00f3n para minimizar la utilizaci\u00f3n del procesador en el servidor durante la reproducci\u00f3n.",
+ "LabelUploadSpeedLimit": "L\u00edmite de velocidad de subida (mbps):",
+ "OptionAllowSyncTranscoding": "Permitir sincronizaci\u00f3n que requiera de transcodificaci\u00f3n",
+ "HeaderPlayback": "Reproducci\u00f3n de Medios",
+ "OptionAllowAudioPlaybackTranscoding": "Permitir la reproducci\u00f3n de audio que requiera de transcodificaci\u00f3n",
+ "OptionAllowVideoPlaybackTranscoding": "Permitir la reproducci\u00f3n de video que requiera de transcodificaci\u00f3n",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Los usuarios recibir\u00e1n mensajes amigables cuando el contenido no pueda ser reproducido de acuerdo a su pol\u00edtica.",
+ "TabStreaming": "Transmisi\u00f3n",
+ "LabelRemoteClientBitrateLimit": "Limite de tasa de bits para clientes remotos (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "L\u00edmite opcional en la tasa de bits de transmisi\u00f3n para todos los clientes remotos. Esto es \u00fatil para evitar que los clientes soliciten una tasa de bits mayor a la que su conexi\u00f3n puede soportar.",
+ "LabelConversionCpuCoreLimit": "L\u00edmite de n\u00facleos de CPU:",
+ "LabelConversionCpuCoreLimitHelp": "L\u00edmitar el n\u00famero de n\u00facleos del CPI que ser\u00e1n utilizados durante la conversi\u00f3n de sincronizaci\u00f3n.",
+ "OptionEnableFullSpeedConversion": "Habilitar conversi\u00f3n a m\u00e1xima velocidad",
+ "OptionEnableFullSpeedConversionHelp": "Por defecto, la conversi\u00f3n es realizada a baja velocidad para minimizar el consumo de recursos.",
+ "HeaderPlaylists": "Listas",
+ "HeaderSelectDate": "Seleccionar fecha",
+ "HeaderWelcomeExclamation": "\u00a1Bienvenido!",
+ "HeaderMyPreferences": "Mi Configuraci\u00f3n",
+ "ButtonMyPreferencesWelcomeYes": "Si, me gustar\u00eda ajustar mi configuraci\u00f3n ahora.",
+ "ButtonMyPreferencesWelcomeNo": "No gracias, lo har\u00e9 luego.",
+ "MyPreferencesWelcomeMessage1": "Configuramos la apariencia de tu biblioteca de una forma que pensamos que te gustar\u00eda. Puedes cambiar la apariencia y agrupaci\u00f3n del contenido cuando quieras en tu configuraci\u00f3n. Tu configuraci\u00f3n se aplicar\u00e1 a todas las aplicaciones de Emby.",
+ "MyPreferencesWelcomeMessage2": "\u00bfTe gustar\u00eda ajustar tu configuraci\u00f3n ahora?",
+ "ToAccessPreferencesHelp": "Para acceder a tu configuraci\u00f3n luego, haz clic en tu icono de usuario en la esquina superior derecha y selecciona Mi Configuraci\u00f3n.",
+ "HeaderViewStyles": "Ver Estilos",
+ "LabelSelectViewStyles": "Activar presentaciones completas para:",
+ "LabelSelectViewStylesHelp": "Si se activa, las diferentes vistas usar\u00e1n metada para mostrar categor\u00edas como Sugerencias, \u00daltimos, G\u00e9neros, y m\u00e1s. Si est\u00e1 desactivado, se mostrar\u00e1n como carpetas comunes."
} \ 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 4e7d9b552..3b43dbb1f 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/fi.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/fi.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Add User",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
"LabelPinCode": "Pin code:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "Ok",
"ButtonCancel": "Lopeta",
"ButtonExit": "Exit",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Nothing here.",
"MessagePleaseEnsureInternetMetadata": "Please ensure downloading of internet metadata is enabled.",
"TabSuggested": "Suggested",
+ "TabSuggestions": "Suggestions",
"TabLatest": "Latest",
"TabUpcoming": "Upcoming",
"TabShows": "Shows",
@@ -401,9 +404,10 @@
"ButtonRefresh": "Refresh",
"ButtonAdvancedRefresh": "Advanced Refresh",
"OptionPriority": "Priority",
- "OptionRecordOnAllChannels": "Record program on all channels",
- "OptionRecordAnytime": "Record program at any time",
+ "OptionRecordOnAllChannels": "Record on all channels",
+ "OptionRecordAnytime": "Record at any time",
"OptionRecordOnlyNewEpisodes": "Record only new episodes",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "Days",
"HeaderActiveRecordings": "Active Recordings",
"HeaderLatestRecordings": "Latest Recordings",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "Web socket port number:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Home page section 2:",
"LabelHomePageSection3": "Home page section 3:",
"LabelHomePageSection4": "Home page section 4:",
- "OptionMyViewsButtons": "My views (buttons)",
- "OptionMyViews": "My views",
- "OptionMyViewsSmall": "My views (small)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Resume",
"OptionLatestMedia": "Latest media",
"OptionLatestChannelMedia": "Latest channel items",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Default",
"OptionCommunityMostWatchedSort": "Most Watched",
"TabNextUp": "Next Up",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
"MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favorites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Display Settings",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "More...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ 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 9b7a58996..d93fe51ce 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/fr.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/fr.json
@@ -24,7 +24,7 @@
"UserProfilesIntro": "Emby supporte nativement les profils utilisateurs, les pr\u00e9f\u00e9rences d'affichage, la sauvegarde de l'\u00e9tat de lecture et le contr\u00f4le parental.",
"LabelWindowsService": "Service Windows",
"AWindowsServiceHasBeenInstalled": "Un service Windows a \u00e9t\u00e9 install\u00e9.",
- "WindowsServiceIntro1": "Le serveur Emby fonctionne comme une application de bureau avec une icone de notification, mais si vous pr\u00e9f\u00e9rer qu'il tourne comme un service en tache de fond, il peut \u00eatre d\u00e9marrer \u00e0 partir du panneau de controle des services windows.",
+ "WindowsServiceIntro1": "Le serveur Emby fonctionne comme une application de bureau avec une icone de notification, mais si vous pr\u00e9f\u00e9rez qu'il tourne comme un service en tache de fond, il peut \u00eatre d\u00e9marrer \u00e0 partir du panneau de controle des services windows.",
"WindowsServiceIntro2": "Si le service Windows est utilis\u00e9, veuillez noter qu'il ne peut pas fonctionner en m\u00eame temps que l'application dans la barre des t\u00e2ches, vous devrez donc fermer l'application de la barre des t\u00e2ches pour pouvoir ex\u00e9cuter le service. Le service devra aussi \u00eatre configur\u00e9 avec les droits administrateurs via le panneau de configuration. Veuillez noter qu'actuellement, la mise \u00e0 jour automatique du service n'est pas disponible, les mises \u00e0 jour devront donc se faire manuellement.",
"WizardCompleted": "C'est tout ce dont nous avons besoin pour l'instant. Emby a commenc\u00e9 \u00e0 collecter les informations de votre biblioth\u00e8que de m\u00e9dias. Jetez un oeil \u00e0 quelques unes de nos applications, puis cliquez sur <b>Terminer<\/b> pour consulter le <b>Tableau de bord du serveur<\/b>.",
"LabelConfigureSettings": "Configurer les param\u00e8tres",
@@ -52,6 +52,8 @@
"HeaderAddUser": "Ajouter un utilisateur",
"LabelAddConnectSupporterHelp": "Pour ajouter un utilisateur non list\u00e9, vous devrez d'abord lier son compte \u00e0 Emby Connect depuis sa page de profil utilisateur.",
"LabelPinCode": "Code PIN:",
+ "OptionHideWatchedContentFromLatestMedia": "Masquer le contenu d\u00e9j\u00e0 vu dans les derniers m\u00e9dias",
+ "HeaderSync": "Sync",
"ButtonOk": "Ok",
"ButtonCancel": "Annuler",
"ButtonExit": "Sortie",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Rien ici.",
"MessagePleaseEnsureInternetMetadata": "Veuillez vous assurer que le t\u00e9l\u00e9chargement des m\u00e9tadonn\u00e9es depuis Internet est activ\u00e9.",
"TabSuggested": "Sugg\u00e9r\u00e9s",
+ "TabSuggestions": "Suggestions",
"TabLatest": "Plus r\u00e9cents",
"TabUpcoming": "\u00c0 venir",
"TabShows": "S\u00e9ries",
@@ -401,9 +404,10 @@
"ButtonRefresh": "Actualiser",
"ButtonAdvancedRefresh": "Mise \u00e0 jour avanc\u00e9e",
"OptionPriority": "Priorit\u00e9",
- "OptionRecordOnAllChannels": "Enregistrer le programme sur toutes les cha\u00eenes",
- "OptionRecordAnytime": "Enregistrer le programme \u00e0 n'importe quelle heure\/journ\u00e9e",
+ "OptionRecordOnAllChannels": "Enregistrer sur toutes les cha\u00eenes",
+ "OptionRecordAnytime": "Enregistrer \u00e0 n'importe quelle heure\/journ\u00e9e",
"OptionRecordOnlyNewEpisodes": "Enregistrer seulement les nouveaux \u00e9pisodes",
+ "HeaderRepeatingOptions": "Options de r\u00e9p\u00e9tition",
"HeaderDays": "Jours",
"HeaderActiveRecordings": "Enregistrements actifs",
"HeaderLatestRecordings": "Derniers enregistrements",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Num\u00e9ro de port https public :",
"LabelPublicHttpsPortHelp": "Le num\u00e9ro de port public \u00e0 mapper sur le port https local.",
"LabelEnableHttps": "Renvoyer une url https en tant qu'adresse externe",
- "LabelEnableHttpsHelp": "Activez cette option pour que le serveur renvoie une adresse https aux clients pour son adresse externe. Ceci pourrait faire planter les clients qui ne supportent pas encore l'https.",
+ "LabelEnableHttpsHelp": "Activez cette option pour que le serveur renvoie une adresse https aux clients pour son adresse externe.",
"LabelHttpsPort": "Num\u00e9ro de port https local :",
"LabelHttpsPortHelp": "Le port TCP que le serveur https d'Emby doit utiliser.",
"LabelWebSocketPortNumber": "Num\u00e9ro de port \"Web socket\":",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Seconde section du portail :",
"LabelHomePageSection3": "Troisi\u00e8me section du portail :",
"LabelHomePageSection4": "Quatri\u00e8me section du portail:",
- "OptionMyViewsButtons": "Mes vues (bouttons)",
- "OptionMyViews": "Mes vues",
- "OptionMyViewsSmall": "Mes vues (petit)",
+ "OptionMyMediaButtons": "Mes m\u00e9dias (boutons)",
+ "OptionMyMedia": "Mes m\u00e9dias",
+ "OptionMyMediaSmall": "Mes m\u00e9dias (petit)",
"OptionResumablemedia": "Reprendre",
"OptionLatestMedia": "Les plus r\u00e9cents",
"OptionLatestChannelMedia": "Items de cha\u00eene les plus r\u00e9cents",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Par d\u00e9faut",
"OptionCommunityMostWatchedSort": "Les plus lus",
"TabNextUp": "Prochains \u00e0 voir",
+ "PlaceholderUsername": "Identifiant",
"HeaderBecomeProjectSupporter": "Devenir un fan d'Emby",
- "TextEnjoyBonusFeatures": "Profitez bien des fonctionnalit\u00e9s bonus",
"MessageNoMovieSuggestionsAvailable": "Aucune suggestion de film n'est actuellement disponible. Commencez \u00e0 regarder et notez vos films pour avoir des suggestions.",
"MessageNoCollectionsAvailable": "Les collections vous permettent de tirer parti de groupements personnalis\u00e9s de films, de s\u00e9ries, d'albums audio, de livres et de jeux. Cliquez sur le bouton + pour commencer \u00e0 cr\u00e9er des Collections.",
"MessageNoPlaylistsAvailable": "Les listes de lectures vous permettent de cr\u00e9er des listes de contenus \u00e0 lire en continu en une fois. Pour ajouter un \u00e9l\u00e9ment \u00e0 la liste, faire un clic droit ou appuyer et maintenez, puis s\u00e9lectionnez Ajouter \u00e0 la liste de lecture",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favoris",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Dernier",
+ "ViewTypeMusicPlaylists": "Listes de lectures",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Artiste de l'album",
"HeaderOtherDisplaySettings": "Param\u00e8tres d'affichage",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "T\u00e9l\u00e9charger les m\u00e9ta-donn\u00e9es depuis Internet pour :",
"OptionTVMovies": "T\u00e9l\u00e9films",
"HeaderUpcomingMovies": "Films \u00e0 venir",
+ "HeaderUpcomingSports": "Ev\u00e9nements sportifs \u00e0 venir",
"HeaderUpcomingPrograms": "Programmes \u00e0 venir",
"ButtonMoreItems": "Plus...",
"LabelShowLibraryTileNames": "Voir les noms des affiches de la biblioth\u00e8que",
"LabelShowLibraryTileNamesHelp": "D\u00e9termine si les noms doivent \u00eatre affich\u00e9s en dessous des affiches de la biblioth\u00e8que sur la page d'accueil",
- "OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottle": "Activer le throttling",
+ "OptionEnableTranscodingThrottleHelp": "Le throttling consiste \u00e0 ajuster automatiquement la fr\u00e9quence de transcodage afin de minimiser l'utilisation CPU pendant la lecture.",
+ "LabelUploadSpeedLimit": "D\u00e9bit max d'upload (Mbps) :",
+ "OptionAllowSyncTranscoding": "Autoriser la synchronisation quand elle n\u00e9cessite un transcodage",
+ "HeaderPlayback": "Lecture du m\u00e9dia",
+ "OptionAllowAudioPlaybackTranscoding": "Autoriser la lecture de musique n\u00e9cessitant un transcodage",
+ "OptionAllowVideoPlaybackTranscoding": "Autoriser la lecture de vid\u00e9os n\u00e9cessitant un transcodage",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Les utilisateurs recevront un message d'erreur compr\u00e9hensible lorsque le contenu n'est pas lisible en raison des restrictions appliqu\u00e9es.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Limite de d\u00e9bit du client distant (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "Une limite de d\u00e9bit optionnelle du streaming pour tous les clients distant. Utile pour \u00e9viter que les clients demandent une bande passante sup\u00e9rieure \u00e0 ce que votre connexion peu fournir.",
+ "LabelConversionCpuCoreLimit": "Limite de c\u0153ur CPU:",
+ "LabelConversionCpuCoreLimitHelp": "Limite le nombre de c\u0153ur du processeur utilis\u00e9s pendant le transcodage.",
+ "OptionEnableFullSpeedConversion": "Autoriser le transcodage rapide",
+ "OptionEnableFullSpeedConversionHelp": "Par d\u00e9faut, le transcodage est r\u00e9alis\u00e9 de mani\u00e8re lente pour minimiser la consommation de ressources.",
+ "HeaderPlaylists": "Listes de lecture",
+ "HeaderSelectDate": "S\u00e9lectionnez la date",
+ "HeaderWelcomeExclamation": "Bienvenue !",
+ "HeaderMyPreferences": "Mes pr\u00e9f\u00e9rences",
+ "ButtonMyPreferencesWelcomeYes": "Oui, je voudrais d\u00e9finir mes pr\u00e9f\u00e9rences maintenant.",
+ "ButtonMyPreferencesWelcomeNo": "Non merci, je le ferai plus tard.",
+ "MyPreferencesWelcomeMessage1": "Nous avons pr\u00e9sent\u00e9 votre biblioth\u00e8que d'une mani\u00e8re que nous pensons agr\u00e9able. L'apparence et les regroupements de contenus peuvent \u00eatre modifi\u00e9s \u00e0 tout moment en ajustant vos pr\u00e9f\u00e9rences. Vos pr\u00e9f\u00e9rences s'appliqueront \u00e0 toutes vos applications Emby.",
+ "MyPreferencesWelcomeMessage2": "Voulez-vous d\u00e9finir vos pr\u00e9f\u00e9rences maintenant ?",
+ "ToAccessPreferencesHelp": "Pour acc\u00e9der plus tard \u00e0 vos pr\u00e9f\u00e9rences, cliquez sur l'ic\u00f4ne utilisateur dans le bandeau en haut \u00e0 droite et s\u00e9lectionnez Mes pr\u00e9f\u00e9rences.",
+ "HeaderViewStyles": "Styles d'affichage",
+ "LabelSelectViewStyles": "Activer les pr\u00e9sentations enrichies",
+ "LabelSelectViewStylesHelp": "Si vous activez cette option, l'affichage utilisera les m\u00e9tadonn\u00e9es pour ajouter des cat\u00e9gories telles que Suggestions, Derni\u00e8res, Genres, ... Si vous d\u00e9sactivez cette option, l'affichage sera simplement bas\u00e9 sur les dossiers."
} \ 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 6ccbee4a7..4d9c2f3ee 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/he.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/he.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Add User",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
"LabelPinCode": "Pin code:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "\u05d0\u05e9\u05e8",
"ButtonCancel": "\u05d1\u05d8\u05dc",
"ButtonExit": "Exit",
@@ -167,6 +169,7 @@
"MessageNothingHere": "\u05d0\u05d9\u05df \u05db\u05d0\u05df \u05db\u05dc\u05d5\u05dd.",
"MessagePleaseEnsureInternetMetadata": "\u05d1\u05d1\u05e7\u05e9\u05d4 \u05d5\u05d5\u05d3\u05d0 \u05db\u05d9 \u05d4\u05d5\u05e8\u05d3\u05ea \u05de\u05d9\u05d3\u05e2 \u05de\u05d4\u05d0\u05d9\u05e0\u05d8\u05e8\u05e0\u05d8 \u05de\u05d0\u05d5\u05e4\u05e9\u05e8\u05ea",
"TabSuggested": "\u05de\u05de\u05d5\u05dc\u05e5",
+ "TabSuggestions": "Suggestions",
"TabLatest": "\u05d0\u05d7\u05e8\u05d5\u05df",
"TabUpcoming": "\u05d1\u05e7\u05e8\u05d5\u05d1",
"TabShows": "\u05ea\u05d5\u05db\u05e0\u05d9\u05d5\u05ea",
@@ -404,6 +407,7 @@
"OptionRecordOnAllChannels": "\u05d4\u05e7\u05dc\u05d8 \u05ea\u05d5\u05db\u05e0\u05d9\u05d5\u05ea \u05d1\u05db\u05dc \u05d4\u05e2\u05e8\u05d5\u05e6\u05d9\u05dd",
"OptionRecordAnytime": "\u05d4\u05e7\u05dc\u05d8 \u05ea\u05d5\u05db\u05e0\u05d9\u05ea \u05d1\u05db\u05dc \u05d6\u05de\u05df",
"OptionRecordOnlyNewEpisodes": "\u05d4\u05e7\u05dc\u05d8 \u05e8\u05e7 \u05e4\u05e8\u05e7\u05d9\u05dd \u05d7\u05d3\u05e9\u05d9\u05dd",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "\u05d9\u05de\u05d9\u05dd",
"HeaderActiveRecordings": "\u05d4\u05e7\u05dc\u05d8\u05d5\u05ea \u05e4\u05e2\u05d9\u05dc\u05d5\u05ea",
"HeaderLatestRecordings": "\u05d4\u05e7\u05dc\u05d8\u05d5\u05ea \u05d0\u05d7\u05e8\u05d5\u05e0\u05d5\u05ea",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "\u05e4\u05d5\u05e8\u05d8 Web socket:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Home page section 2:",
"LabelHomePageSection3": "Home page section 3:",
"LabelHomePageSection4": "Home page section 4:",
- "OptionMyViewsButtons": "My views (buttons)",
- "OptionMyViews": "My views",
- "OptionMyViewsSmall": "My views (small)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Resume",
"OptionLatestMedia": "Latest media",
"OptionLatestChannelMedia": "Latest channel items",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Default",
"OptionCommunityMostWatchedSort": "Most Watched",
"TabNextUp": "Next Up",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
"MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favorites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Display Settings",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "More...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ 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 c9de0acda..dc9f6b563 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/hr.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/hr.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Add User",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
"LabelPinCode": "Pin code:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "Ok",
"ButtonCancel": "Odustani",
"ButtonExit": "Exit",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Ni\u0161ta ovdje.",
"MessagePleaseEnsureInternetMetadata": "Molimo provjerite da je preuzimanje metadata sa interneta omogu\u0107eno.",
"TabSuggested": "Preporu\u010deno",
+ "TabSuggestions": "Suggestions",
"TabLatest": "Zadnje",
"TabUpcoming": "Uskoro",
"TabShows": "Emisije",
@@ -404,6 +407,7 @@
"OptionRecordOnAllChannels": "Snimi emisiju na svim kanalima",
"OptionRecordAnytime": "Snimi emisiju u bilo koje vrijeme",
"OptionRecordOnlyNewEpisodes": "Snimi samo nove epizode",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "Dani",
"HeaderActiveRecordings": "Aktivna snimanja",
"HeaderLatestRecordings": "Zadnje snimke",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "Port Web priklju\u010dka:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Home page section 2:",
"LabelHomePageSection3": "Home page section 3:",
"LabelHomePageSection4": "Home page section 4:",
- "OptionMyViewsButtons": "My views (buttons)",
- "OptionMyViews": "My views",
- "OptionMyViewsSmall": "My views (small)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Resume",
"OptionLatestMedia": "Latest media",
"OptionLatestChannelMedia": "Latest channel items",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Default",
"OptionCommunityMostWatchedSort": "Most Watched",
"TabNextUp": "Next Up",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
"MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favorites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Display Settings",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "More...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ 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 79be970d6..5d3beeca1 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/it.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/it.json
@@ -1,16 +1,16 @@
{
"LabelExit": "Esci",
- "LabelVisitCommunity": "Visita Comunit\u00e0",
+ "LabelVisitCommunity": "Visita la Community",
"LabelGithub": "Github",
"LabelSwagger": "Swagger",
"LabelStandard": "Standard",
- "LabelApiDocumentation": "Documentazione Api",
- "LabelDeveloperResources": "Risorse programmatori",
+ "LabelApiDocumentation": "Documentazione sulle Api",
+ "LabelDeveloperResources": "Risorse per i programmatori",
"LabelBrowseLibrary": "Esplora la libreria",
"LabelConfigureServer": "Configura Emby",
"LabelOpenLibraryViewer": "Apri visualizzatore libreria",
"LabelRestartServer": "Riavvia Server",
- "LabelShowLogWindow": "Mostra Finestra log",
+ "LabelShowLogWindow": "Mostra finestra dei log",
"LabelPrevious": "Precedente",
"LabelFinish": "Finito",
"LabelNext": "Prossimo",
@@ -21,37 +21,39 @@
"ButtonQuickStartGuide": "Guida rapida",
"LabelYourFirstName": "Nome",
"MoreUsersCanBeAddedLater": "Puoi aggiungere altri utenti in un secondo momento all'interno del pannello di configurazione",
- "UserProfilesIntro": "Emby includes built-in support for user profiles, enabling each user to have their own display settings, playstate and parental controls.",
+ "UserProfilesIntro": "Emby include il supporto integrato per i profili utente, che permette ad ogni utente di avere le proprie impostazioni di visualizzazione, stato di riproduzione e parental control.",
"LabelWindowsService": "Servizio Windows",
"AWindowsServiceHasBeenInstalled": "Servizio Windows Installato",
- "WindowsServiceIntro1": "Emby Server normally runs as a desktop application with a tray icon, but if you prefer to run it as a background service, it can be started from the windows services control panel instead.",
+ "WindowsServiceIntro1": "Il Server Emby normalmente viene eseguito come un'applicazione del desktop con un'icona sulla barra in basso a destra, ma in alternativa, se si preferisce farlo funzionare come servizio in background, pu\u00f2 essere avviato dal pannello di controllo dei servizi di Windows.",
"WindowsServiceIntro2": "Se si utilizza il servizio di Windows, si ricorda che non pu\u00f2 essere eseguito allo stesso tempo con l'icona di sistema, quindi devi chiudere l'applicazione al fine di eseguire il servizio. Il servizio dovr\u00e0 anche essere configurato con privilegi amministrativi tramite il pannello di controllo. Si prega di notare che in questo momento il servizio non \u00e8 in grado di Autoaggiornarsi, quindi le nuove versioni richiedono l'interazione manuale",
- "WizardCompleted": "That's all we need for now. Emby has begun collecting information about your media library. Check out some of our apps, and then click <b>Finish<\/b> to view the <b>Server Dashboard<\/b>.",
- "LabelConfigureSettings": "Configura",
+ "WizardCompleted": "Questo \u00e8 tutto ci\u00f2 che serve per ora. Emby ha iniziato a raccogliere informazioni sulla tua libreria di file multimediali. Scopri alcune delle nostre app, quindi clicca su <b>Fine<\/b> per visualizzare il <b>Pannello di controllo del server<\/b>",
+ "LabelConfigureSettings": "Configura le impostazioni",
"LabelEnableVideoImageExtraction": "Abilita estrazione immagine video",
- "VideoImageExtractionHelp": "Per i video che sono sprovvisti di immagini, e per i quali non siamo riusciti a trovare immagini su Internet.Questo aggiunger\u00e0 del tempo addizionale alla scansione della tua libreria ma si tradurr\u00e0 in una presentazione pi\u00f9 piacevole.",
- "LabelEnableChapterImageExtractionForMovies": "Estrazione immagine capitolo estratto per i Film",
+ "VideoImageExtractionHelp": "Per i video che sono sprovvisti di immagini, e per i quali non siamo riusciti a trovare immagini su Internet. Questa opzione allungher\u00e0 il tempo di scansione della tua libreria ma si tradurr\u00e0 in una presentazione pi\u00f9 gradevole.",
+ "LabelEnableChapterImageExtractionForMovies": "Estrazione immagine del capitolo per i Film",
"LabelChapterImageExtractionForMoviesHelp": "L'estrazione delle immagini dai capitoli permetter\u00e0 ai client di avere un men\u00f9 grafico per la selezione delle scene. Il processo potrebbe essere lento, con uso intensivo della CPU e potrebbe richiedere diversi gigabyte di spazio. Viene avviato durante la notte, ad ogni modo \u00e8 configurabile nella sezione azioni pianificate. Non \u00e8 raccomandato l'avvio di questo processo durante le ore di massimo utilizzo.",
- "LabelEnableAutomaticPortMapping": "Abilita mappatura delle porte automatiche",
- "LabelEnableAutomaticPortMappingHelp": "UPnP consente la configurazione automatica del router per l'accesso remoto facile. Questo potrebbe non funzionare con alcuni modelli di router.",
- "HeaderTermsOfService": "Emby termini di servizio",
+ "LabelEnableAutomaticPortMapping": "Abilita mappatura automatica delle porte",
+ "LabelEnableAutomaticPortMappingHelp": "UPnP consente la configurazione automatica del router per facilitare l'accesso remoto. Questa opzione potrebbe non funzionare con alcuni modelli di router.",
+ "HeaderTermsOfService": "Termini di servizio di Emby",
"MessagePleaseAcceptTermsOfService": "Per favore accetta i termini di servizio e l'informativa sulla privacy prima di continuare.",
"OptionIAcceptTermsOfService": "Accetto i termini di servizio",
"ButtonPrivacyPolicy": "Informativa sulla privacy",
"ButtonTermsOfService": "Termini di Servizio",
- "HeaderDeveloperOptions": "Opzioni Sviluppatore",
- "OptionEnableWebClientResponseCache": "Abilita la cache del client web",
+ "HeaderDeveloperOptions": "Opzioni per il programmatore",
+ "OptionEnableWebClientResponseCache": "Abilita il caching delle risposte del client",
"OptionDisableForDevelopmentHelp": "Configura questi parametri per sviluppatori del client web",
"OptionEnableWebClientResourceMinification": "Abilita la minimizzazione delle risorse del client web",
- "LabelDashboardSourcePath": "Percorso sorgente client web",
+ "LabelDashboardSourcePath": "Percorso del codice sorgente del client web:",
"LabelDashboardSourcePathHelp": "se si sta eseguendo il server da una sorgente, specifica il percorso dell'interfaccia. Tutti i file per i client saranno presi da questo percorso",
"ButtonConvertMedia": "Converti media",
"ButtonOrganize": "Organizza",
"LinkedToEmbyConnect": "Collegato a Emby Connect",
- "HeaderSupporterBenefits": "Supporter Benefits",
- "HeaderAddUser": "Add User",
- "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
+ "HeaderSupporterBenefits": "Benefici per il Supporter",
+ "HeaderAddUser": "Aggiungi utente",
+ "LabelAddConnectSupporterHelp": "Per aggiungere un utente non in lista, dovrai prima collegare il suo account a Emby Connect dalla pagina del suo profilo",
"LabelPinCode": "Codice Pin",
+ "OptionHideWatchedContentFromLatestMedia": "Nasconde i contenuti visti dagli Ultimi Media",
+ "HeaderSync": "Sincronizza",
"ButtonOk": "OK",
"ButtonCancel": "Annulla",
"ButtonExit": "Esci",
@@ -60,31 +62,31 @@
"HeaderAudio": "Audio",
"HeaderVideo": "Video",
"HeaderPaths": "Percorsi",
- "CategorySync": "Sinc.zza",
+ "CategorySync": "Sincronizza",
"TabPlaylist": "Playlist",
- "HeaderEasyPinCode": "Codice pin",
+ "HeaderEasyPinCode": "Codice pin semplificato",
"HeaderGrownupsOnly": "Solo adulti",
- "DividerOr": "- o -",
+ "DividerOr": "-- o --",
"HeaderInstalledServices": "Servizi installati",
"HeaderAvailableServices": "Servizi disponibili",
"MessageNoServicesInstalled": "Nessun servizio attualmente installato",
- "HeaderToAccessPleaseEnterEasyPinCode": "Per accedere per favore inserisci il tuo codice pin",
+ "HeaderToAccessPleaseEnterEasyPinCode": "Per accedere per favore inserisci il tuo codice pin semplificato",
"KidsModeAdultInstruction": "Clicca sull'icona del lucchetto nell'angolo in basso a destra per configurare o abbandonare la modalit\u00e0 bambini. Verr\u00e0 richiesto il tuo codice pin",
"ButtonConfigurePinCode": "Configura codice pin",
"HeaderAdultsReadHere": "Adulti leggete qui!",
- "RegisterWithPayPal": "Registra con PayPal",
+ "RegisterWithPayPal": "Registrati con PayPal",
"HeaderSyncRequiresSupporterMembership": "La sincronizzazione richiede un'iscrizione come supporter",
- "HeaderEnjoyDayTrial": "Goditi la tua prova gratuita di 14 giorni",
- "LabelSyncTempPath": "Percorso file temporanei",
- "LabelSyncTempPathHelp": "Specifica una cartella per la sincronizzazione. I file multimediali convertiti durante la sincronizzazione verranno collocati qui.",
+ "HeaderEnjoyDayTrial": "Goditi una prova gratuita per 14 giorni",
+ "LabelSyncTempPath": "Percorso file temporanei:",
+ "LabelSyncTempPathHelp": "Specifica una cartella per la sincronizzazione. I file multimediali convertiti durante la sincronizzazione verranno memorizzati qui.",
"LabelCustomCertificatePath": "Percorso certificati personalizzato:",
- "LabelCustomCertificatePathHelp": "Fornire un tuo file .pfx certificato SSL. Se omesso, il server creer\u00e0 un certificato auto-firmato.",
+ "LabelCustomCertificatePathHelp": "Fornisci il tuo file .pfx certificato SSL. Se omesso, il server creer\u00e0 un certificato auto-firmato.",
"TitleNotifications": "Notifiche",
"ButtonDonateWithPayPal": "Effettua una donazione con PayPal",
"OptionDetectArchiveFilesAsMedia": "Considera gli archivi come file multimediali",
"OptionDetectArchiveFilesAsMediaHelp": "se attivato, i file con estensione .rar e .zip saranno considerati come file multimediali.",
"LabelEnterConnectUserName": "Nome Utente o email:",
- "LabelEnterConnectUserNameHelp": "This is your Emby online account user name or password.",
+ "LabelEnterConnectUserNameHelp": "Questa \u00e8 la username o la password del tuo account online Emby",
"LabelEnableEnhancedMovies": "Abilita le visuali film migliorate",
"LabelEnableEnhancedMoviesHelp": "Quando abilitato, i film verranno mostrati come cartelle che includono i trailer, gli extra, il cast & crew, e altri contenuti correlati.",
"HeaderSyncJobInfo": "Attiv. di Sinc.",
@@ -100,8 +102,8 @@
"FolderTypeTvShows": "Tv",
"FolderTypeInherit": "ereditare",
"LabelContentType": "Tipo di contenuto:",
- "TitleScheduledTasks": "Compiti Pianificati",
- "HeaderSetupLibrary": "Configura la tua libreria",
+ "TitleScheduledTasks": "Task pianificati",
+ "HeaderSetupLibrary": "Configura la tua libreria di contenuti multimediali",
"ButtonAddMediaFolder": "Aggiungi cartella",
"LabelFolderType": "Tipo cartella",
"ReferToMediaLibraryWiki": "Fare riferimento alla wiki libreria multimediale.",
@@ -109,14 +111,14 @@
"LabelLanguage": "Lingua:",
"LabelTimeLimitHours": "Tempo limite (ore):",
"ButtonJoinTheDevelopmentTeam": "Unisciti al Team di Sviluppo",
- "HeaderPreferredMetadataLanguage": "Lingua dei metadati preferita:",
+ "HeaderPreferredMetadataLanguage": "Lingua preferita per i metadati:",
"LabelSaveLocalMetadata": "Salva immagini e metadati nelle cartelle multimediali",
- "LabelSaveLocalMetadataHelp": "Il salvataggio di immagini e dei metadati direttamente nelle cartelle multimediali verranno messe in un posto dove possono essere facilmente modificate.",
+ "LabelSaveLocalMetadataHelp": "Il salvataggio di immagini e metadati direttamente nelle cartelle multimediali consentir\u00e0 di tenerli in un posto dove possono essere facilmente modificati.",
"LabelDownloadInternetMetadata": "Scarica immagini e metadati da internet",
- "LabelDownloadInternetMetadataHelp": "Emby Server can download information about your media to enable rich presentations.",
+ "LabelDownloadInternetMetadataHelp": "Il Server Emby pu\u00f2 scaricare informazioni sui tuoi media per ottenere presentazioni pi\u00f9 complete",
"TabPreferences": "Preferenze",
"TabPassword": "Password",
- "TabLibraryAccess": "Accesso libreria",
+ "TabLibraryAccess": "Accesso alla libreria",
"TabAccess": "Accesso",
"TabImage": "Immagine",
"TabProfile": "Profilo",
@@ -124,24 +126,24 @@
"TabImages": "Immagini",
"TabNotifications": "Notifiche",
"TabCollectionTitles": "Titolo",
- "HeaderDeviceAccess": "Accesso dispositivo",
+ "HeaderDeviceAccess": "Accesso al dispositivo",
"OptionEnableAccessFromAllDevices": "Abilitare l'accesso da tutti i dispositivi",
"OptionEnableAccessToAllChannels": "Abilita l'accesso a tutti i canali",
"OptionEnableAccessToAllLibraries": "Abilita l'accesso a tutte le librerie",
"DeviceAccessHelp": "Questo vale solo per i dispositivi che possono essere identificati in modo univoco e non impedire l'accesso del browser. Filtraggio di accesso al dispositivo dell'utente impedir\u00e0 loro di usare nuovi dispositivi fino a quando non sono state approvate qui.",
"LabelDisplayMissingEpisodesWithinSeasons": "Visualizza gli episodi mancanti nelle stagioni",
"LabelUnairedMissingEpisodesWithinSeasons": "Visualizzare episodi mai andati in onda all'interno stagioni",
- "HeaderVideoPlaybackSettings": "Impostazioni di riproduzione video",
- "HeaderPlaybackSettings": "Impostazioni di riproduzione",
- "LabelAudioLanguagePreference": "Preferenze lingua audio:",
- "LabelSubtitleLanguagePreference": "Preferenze lingua dei sottotitoli:",
+ "HeaderVideoPlaybackSettings": "Impostazioni per la riproduzione di video",
+ "HeaderPlaybackSettings": "Impostazioni per la riproduzione",
+ "LabelAudioLanguagePreference": "Preferenza per la lingua dell'audio:",
+ "LabelSubtitleLanguagePreference": "Preferenza per la lingua dei sottotitoli:",
"OptionDefaultSubtitles": "Predefinito",
"OptionOnlyForcedSubtitles": "Solo i sottotitoli forzati",
"OptionAlwaysPlaySubtitles": "Visualizza sempre i sottotitoli",
"OptionNoSubtitles": "Nessun Sottotitolo",
"OptionDefaultSubtitlesHelp": "I sottotitoli corrispondenti alla lingua preferita saranno caricati quando l'audio \u00e8 in una lingua straniera.",
"OptionOnlyForcedSubtitlesHelp": "Solo i sottotitoli contrassegnati come forzati saranno caricati.",
- "OptionAlwaysPlaySubtitlesHelp": "I sottotitoli corrispondenti alla lingua preferita saranno caricati a prescindere dalla lingua audio.",
+ "OptionAlwaysPlaySubtitlesHelp": "I sottotitoli corrispondenti alla lingua preferita saranno caricati a prescindere dalla lingua dell'audio.",
"OptionNoSubtitlesHelp": "I sottotitoli non verranno caricati di default.",
"TabProfiles": "Profili",
"TabSecurity": "Sicurezza",
@@ -162,18 +164,19 @@
"LabelSelectUsers": "Seleziona Utenti:",
"ButtonUpload": "Carica",
"HeaderUploadNewImage": "Carica nuova immagine",
- "LabelDropImageHere": "Trascina l'immagine qui",
+ "LabelDropImageHere": "Rilasciare l'immagine qui",
"ImageUploadAspectRatioHelp": "1:1 Rapporto dimensioni raccomandato. Solo JPG\/PNG.",
"MessageNothingHere": "Niente qui.",
"MessagePleaseEnsureInternetMetadata": "Assicurarsi che il download dei metadati internet sia abilitato.",
"TabSuggested": "Suggeriti",
+ "TabSuggestions": "Suggerimenti",
"TabLatest": "Novit\u00e0",
"TabUpcoming": "In Arrivo",
- "TabShows": "Serie",
+ "TabShows": "Spettacoli",
"TabEpisodes": "Episodi",
"TabGenres": "Generi",
"TabPeople": "Attori",
- "TabNetworks": "Internet",
+ "TabNetworks": "Reti",
"HeaderUsers": "Utenti",
"HeaderFilters": "Filtri",
"ButtonFilter": "Filtro",
@@ -182,18 +185,18 @@
"OptionDislikes": "Brutti",
"OptionActors": "Attori",
"OptionGuestStars": "Personaggi Famosi",
- "OptionDirectors": "Registra",
- "OptionWriters": "Scrittore",
- "OptionProducers": "Produttore",
+ "OptionDirectors": "Registi",
+ "OptionWriters": "Sceneggiatori",
+ "OptionProducers": "Produttori",
"HeaderResume": "Riprendi",
- "HeaderNextUp": "Da vedere",
- "NoNextUpItemsMessage": "Trovato nessuno. Inizia a guardare i tuoi programmi!",
+ "HeaderNextUp": "Prossimo",
+ "NoNextUpItemsMessage": "Trovato niente. Inizia a guardare i tuoi programmi!",
"HeaderLatestEpisodes": "Ultimi Episodi Aggiunti",
"HeaderPersonTypes": "Tipo Persone:",
"TabSongs": "Canzoni",
"TabAlbums": "Album",
"TabArtists": "Artisti",
- "TabAlbumArtists": "Artisti Album",
+ "TabAlbumArtists": "Artisti degli album",
"TabMusicVideos": "Video Musicali",
"ButtonSort": "Ordina",
"HeaderSortBy": "Ordina per:",
@@ -207,7 +210,7 @@
"OptionPlayCount": "Visto N\u00b0",
"OptionDatePlayed": "Visto il",
"OptionDateAdded": "Aggiunto il",
- "OptionAlbumArtist": "Artista Album",
+ "OptionAlbumArtist": "Artista dell'album",
"OptionArtist": "Artista",
"OptionAlbum": "Album",
"OptionTrackName": "Nome Brano",
@@ -217,20 +220,20 @@
"OptionBudget": "Budget",
"OptionRevenue": "Recensione",
"OptionPoster": "Locandina",
- "OptionPosterCard": "scheda poster",
+ "OptionPosterCard": "Scheda locandina",
"OptionBackdrop": "Sfondo",
- "OptionTimeline": "Anno",
- "OptionThumb": "Sfondo",
+ "OptionTimeline": "Cronologia",
+ "OptionThumb": "Pollice",
"OptionThumbCard": "carta Thumb",
"OptionBanner": "Banner",
- "OptionCriticRating": "Voto critica",
+ "OptionCriticRating": "Voto della critica",
"OptionVideoBitrate": "Bitrate Video",
"OptionResumable": "Interrotti",
- "ScheduledTasksHelp": "Fare clic su una voce per cambiare la pianificazione.",
+ "ScheduledTasksHelp": "Fare clic su una voce per cambiare la sua pianificazione.",
"ScheduledTasksTitle": "Operazioni Pianificate",
- "TabMyPlugins": "Plugins Installati",
+ "TabMyPlugins": "Plugin installati",
"TabCatalog": "Catalogo",
- "TitlePlugins": "Plugins",
+ "TitlePlugins": "Plugin",
"HeaderAutomaticUpdates": "Aggiornamenti Automatici",
"HeaderNowPlaying": "In Riproduzione",
"HeaderLatestAlbums": "Ultimi Album",
@@ -286,17 +289,17 @@
"TitleSupport": "Supporto",
"TabLog": "Eventi",
"TabAbout": "Info",
- "TabSupporterKey": "Chiave finanziatore",
- "TabBecomeSupporter": "Diventa finanziatore",
- "ProjectHasCommunity": "Emby has a thriving community of users and contributors.",
- "CheckoutKnowledgeBase": "Check out our knowledge base to help you get the most out of Emby.",
- "SearchKnowledgeBase": "Cerca sulla guida online",
- "VisitTheCommunity": "Visita la nostra comunit\u00e0",
- "VisitProjectWebsite": "Visit the Emby Web Site",
- "VisitProjectWebsiteLong": "Visit the Emby Web site to catch the latest news and keep up with the developer blog.",
+ "TabSupporterKey": "Chiave del Supporter",
+ "TabBecomeSupporter": "Diventa un Supporter",
+ "ProjectHasCommunity": "Emby ha una ricca community di utilizzatori e collaboratori",
+ "CheckoutKnowledgeBase": "Scopri la nostra Knoledge Base per ottenere il massimo da Emby",
+ "SearchKnowledgeBase": "Cerca nella guida online",
+ "VisitTheCommunity": "Visita la nostra Community",
+ "VisitProjectWebsite": "Visita il sito di Emby",
+ "VisitProjectWebsiteLong": "Visita il sito web di Emby per tenerti aggiornato con le ultime novit\u00e0 e le notizie dal blog degli sviluppatori.",
"OptionHideUser": "Nascondi questo utente dalla schermata di Accesso",
"OptionHideUserFromLoginHelp": "Utile per account nascosti o amministratore. L'utente avr\u00e0 bisogno di accedere manualmente utilizzando la propria username e password",
- "OptionDisableUser": "Disabilita utente",
+ "OptionDisableUser": "Disabilita questo utente",
"OptionDisableUserHelp": "Se disabilitato, il server non sar\u00e0 disponibile per questo utente. La connessione corrente verr\u00e0 TERMINATA",
"HeaderAdvancedControl": "Controlli avanzati",
"LabelName": "Nome:",
@@ -304,12 +307,12 @@
"OptionAllowUserToManageServer": "Consenti a questo utente di accedere alla configurazione del SERVER",
"HeaderFeatureAccess": "Accesso alle funzionalit\u00e0",
"OptionAllowMediaPlayback": "Consentire la riproduzione multimediale",
- "OptionAllowBrowsingLiveTv": "Consenti accesso TV Live",
+ "OptionAllowBrowsingLiveTv": "Consenti accesso alla TV live",
"OptionAllowDeleteLibraryContent": "Consenti l'eliminazione dei media",
"OptionAllowManageLiveTv": "Consenti la gestione di registrazione Live TV",
"OptionAllowRemoteControlOthers": "Consenti controllo remoto di altri utenti",
"OptionAllowRemoteSharedDevices": "Consenti controllo remoto di dispositivi condivisi",
- "OptionAllowRemoteSharedDevicesHelp": "Dispositivi DLNA sono considerati condivisa fino a quando un utente inizia controllarlo.",
+ "OptionAllowRemoteSharedDevicesHelp": "Dispositivi DLNA sono considerati condivisi fino a quando un utente non inizia a controllarli.",
"HeaderRemoteControl": "telecomando",
"OptionMissingTmdbId": "Tmdb Id mancante",
"OptionIsHD": "HD",
@@ -321,7 +324,7 @@
"PismoMessage": "Dona per avere una licenza di Pismo",
"TangibleSoftwareMessage": "Utilizza Tangible Solutions Java\/C# con una licenza su donazione.",
"HeaderCredits": "Crediti",
- "PleaseSupportOtherProduces": "Per favore supporta gli altri prodotti 'GRATIS' che MB utilizza",
+ "PleaseSupportOtherProduces": "Per favore supporta gli altri prodotti gratuiti che utilizziamo",
"VersionNumber": "Versione {0}",
"TabPaths": "Percorsi",
"TabServer": "Server",
@@ -333,21 +336,21 @@
"OptionDev": "Dev (instabile)",
"LabelAllowServerAutoRestart": "Consenti al server di Riavviarsi automaticamente per applicare gli aggiornamenti",
"LabelAllowServerAutoRestartHelp": "Il server si Riavvier\u00e0 solamente quando nessun utente \u00e8 collegato",
- "LabelEnableDebugLogging": "Abilit\u00e0 registro di DEBUG",
+ "LabelEnableDebugLogging": "Attiva la registrazione degli eventi",
"LabelRunServerAtStartup": "Esegui il server all'avvio di windows",
"LabelRunServerAtStartupHelp": "Verr\u00e0 avviata l'icona della barra all'avvio di Windows. Per avviare il servizio di Windows, deselezionare questa ed eseguire il servizio dal pannello di controllo di Windows. Si prega di notare che non \u00e8 possibile eseguire entrambi allo stesso tempo, quindi sar\u00e0 necessario chiudere l'icona sulla barra prima di avviare il servizio.",
"ButtonSelectDirectory": "Seleziona cartella",
"LabelCustomPaths": "Specifica un percorso personalizzato.Lasciare vuoto per usare quello predefinito",
"LabelCachePath": "Percorso Cache:",
- "LabelCachePathHelp": "Questa cartella contiene la cache come files e immagini .",
+ "LabelCachePathHelp": "Specifica la cartella dove memorizzare i file di cache del server, come le immagini",
"LabelImagesByNamePath": "Percorso immagini per nome:",
"LabelImagesByNamePathHelp": "Specificare un percorso personalizzato per le immagini di attori, artisti, generi e case cinematografiche scaricate.",
- "LabelMetadataPath": "Percorso dei file METADATI:",
- "LabelMetadataPathHelp": "Specificare un percorso personalizzato per artwork e metadati scaricati, se non il si vuole salvare nelle cartelle multimediali.",
+ "LabelMetadataPath": "Percorso dei file con i metadati:",
+ "LabelMetadataPathHelp": "Specificare un percorso personalizzato per le immagini e i metadati scaricati, se non si desidera salvarli nelle cartelle multimediali.",
"LabelTranscodingTempPath": "Cartella temporanea per la trascodifica:",
"LabelTranscodingTempPathHelp": "Questa cartella contiene i file di lavoro utilizzati dal transcoder. Specificare un percorso personalizzato, oppure lasciare vuoto per utilizzare l'impostazione predefinita all'interno della cartella dei dati del server.",
"TabBasics": "Base",
- "TabTV": "Serie Tv",
+ "TabTV": "Serie TV",
"TabGames": "Giochi",
"TabMusic": "Musica",
"TabOthers": "Altri",
@@ -357,19 +360,19 @@
"OptionOtherVideos": "Altri Video",
"TitleMetadata": "Metadati",
"LabelAutomaticUpdates": "Abilita gli aggiornamenti automatici",
- "LabelAutomaticUpdatesTmdb": "Abilita gli aggiornamenti automatici per TheMovieDB.org",
- "LabelAutomaticUpdatesTvdb": "Abilita gli aggiornamenti automatici per TheTVDB.com",
+ "LabelAutomaticUpdatesTmdb": "Abilita gli aggiornamenti automatici da TheMovieDB.org",
+ "LabelAutomaticUpdatesTvdb": "Abilita gli aggiornamenti automatici da TheTVDB.com",
"LabelAutomaticUpdatesFanartHelp": "Se abilitato le nuove immagini verranno scaricate automaticamente da fanart.tv. Le immagini esistenti non verranno sovrascritte.",
"LabelAutomaticUpdatesTmdbHelp": "Se abilitato le nuove immagini verranno scaricate automaticamente da ThemovieDb.org. Le immagini esistenti non verranno sovrascritte.",
"LabelAutomaticUpdatesTvdbHelp": "Se abilitato le nuove immagini verranno scaricate automaticamente da TheTvDB.com. Le immagini esistenti non verranno sovrascritte.",
"LabelFanartApiKey": "Chiavi API personali",
- "LabelFanartApiKeyHelp": "I risultati di richieste per fanart senza una chiave API personale che sono state approvate pi\u00f9 di 7 giorni fa. Con una chiave API personale questo tempo scende a 48 ore, e se sei un membro VIP scender\u00e0 ulteriormente a circa 10 minuti.",
+ "LabelFanartApiKeyHelp": "Le richieste di fanart effettuate senza una chiave API personale restituiranno risultati approvati pi\u00f9 di 7 giorni fa. Con una chiave API personale questo tempo scende a 48 ore, e se sei un membro VIP questo tempo scender\u00e0 ulteriormente a circa 10 minuti.",
"ExtractChapterImagesHelp": "L'estrazione delle immagini dai capitoli permetter\u00e0 ai client di avere un men\u00f9 grafico per la selezione delle scene. Il processo potrebbe essere lento, con uso intensivo della CPU e potrebbe richiedere diversi gigabyte di spazio. Viene avviato quando vengono trovati nuovi video, e anche durante la notte, ad ogni modo \u00e8 configurabile nella sezione azioni pianificate. Non \u00e8 raccomandato l'avvio di questo processo durante le ore di massimo utilizzo.",
"LabelMetadataDownloadLanguage": "Lingua preferita per il download:",
"ButtonAutoScroll": "Scorrimento automatico",
"LabelImageSavingConvention": "Convenzione per il salvataggio di immagini:",
- "LabelImageSavingConventionHelp": "Emby recognizes images from most major media applications. Choosing your downloading convention is useful if you also use other products.",
- "OptionImageSavingCompatible": "Compatible - Emby\/Kodi\/Plex",
+ "LabelImageSavingConventionHelp": "Emby riconosce le immagini fornite dalle principali applicazioni di gestione di media. Scegliere il formato del download \u00e8 utile se usi anche altri prodotti",
+ "OptionImageSavingCompatible": "Compatibile - Emby\/Kodi\/Plex",
"OptionImageSavingStandard": "Standard - MB2",
"ButtonSignIn": "Accedi",
"TitleSignIn": "Accedi",
@@ -389,7 +392,7 @@
"TabMyLibrary": "Mia Libreria",
"ButtonCancelRecording": "Annulla la registrazione",
"HeaderPrePostPadding": "Pre\/Post Registrazione",
- "LabelPrePaddingMinutes": "Pre registrazione minuti",
+ "LabelPrePaddingMinutes": "Minuti di pre-registrazione:",
"OptionPrePaddingRequired": "Attiva pre registrazione",
"LabelPostPaddingMinutes": "Minuti post registrazione",
"OptionPostPaddingRequired": "Attiva post registrazione",
@@ -404,6 +407,7 @@
"OptionRecordOnAllChannels": "Registra su tutti i canali",
"OptionRecordAnytime": "Registra a qualsiasi ora",
"OptionRecordOnlyNewEpisodes": "Registra solo i nuovi episodi",
+ "HeaderRepeatingOptions": "Opzioni di ripetizione",
"HeaderDays": "Giorni",
"HeaderActiveRecordings": "Registrazioni Attive",
"HeaderLatestRecordings": "Ultime registrazioni",
@@ -417,11 +421,11 @@
"HeaderDetails": "Dettagli",
"TitleLiveTV": "Tv in diretta",
"LabelNumberOfGuideDays": "Numero di giorni per i quali scaricare i dati della guida:",
- "LabelNumberOfGuideDaysHelp": "Scaricando pi\u00f9 giorni si avr\u00e0 la possibilit\u00e0 di pianificare in anticipo pi\u00f9 programmi e vedere pi\u00f9 liste. 'Auto': MB sceglier\u00e0 automaticamente in base al numero di canali.",
+ "LabelNumberOfGuideDaysHelp": "Scaricando pi\u00f9 giorni si avr\u00e0 la possibilit\u00e0 di pianificare in anticipo pi\u00f9 programmi e vedere pi\u00f9 liste, ma il tempo di download si allungher\u00e0. 'Auto': MB sceglier\u00e0 automaticamente in base al numero di canali.",
"OptionAutomatic": "Automatico",
- "HeaderServices": "Services",
+ "HeaderServices": "Servizi",
"LiveTvPluginRequired": "E' richiesto il servizio LIVE TV per continuare.",
- "LiveTvPluginRequiredHelp": "Installa un servizio disponibile, come Next Pvr or ServerWMC.",
+ "LiveTvPluginRequiredHelp": "Installa un plugin tra quelli disponibili, come Next Pvr o ServerWMC.",
"LabelCustomizeOptionsPerMediaType": "Personalizza per il tipo di supporto:",
"OptionDownloadThumbImage": "Foto",
"OptionDownloadMenuImage": "Men\u00f9",
@@ -435,7 +439,7 @@
"HeaderFetchImages": "Identifica Immagini:",
"HeaderImageSettings": "Impostazioni Immagini",
"TabOther": "Altro",
- "LabelMaxBackdropsPerItem": "Massimo numero di sfondi per oggetto.",
+ "LabelMaxBackdropsPerItem": "Massimo numero di sfondi per oggetto:",
"LabelMaxScreenshotsPerItem": "Massimo numero di foto per oggetto:",
"LabelMinBackdropDownloadWidth": "Massima larghezza sfondo:",
"LabelMinScreenshotDownloadWidth": "Minima larghezza foto:",
@@ -443,21 +447,21 @@
"HeaderAddScheduledTaskTrigger": "Aggiungi operazione",
"ButtonAdd": "Aggiungi",
"LabelTriggerType": "Tipo Evento:",
- "OptionDaily": "Giornal.",
+ "OptionDaily": "Giornaliero",
"OptionWeekly": "Settimanale",
"OptionOnInterval": "Su intervallo",
"OptionOnAppStartup": "All'avvio",
- "OptionAfterSystemEvent": "Dopo un vento di sistema",
+ "OptionAfterSystemEvent": "Dopo un evento di sistema",
"LabelDay": "Giorno:",
"LabelTime": "Ora:",
"LabelEvent": "Evento:",
"OptionWakeFromSleep": "Risveglio:",
"LabelEveryXMinutes": "Tutti:",
- "HeaderTvTuners": "Schede Tv",
+ "HeaderTvTuners": "Sintonizzatori Tv",
"HeaderGallery": "Galleria",
"HeaderLatestGames": "Ultimi giochi",
- "HeaderRecentlyPlayedGames": "Ultimi giochi recenti",
- "TabGameSystems": "Sistema di Giocho",
+ "HeaderRecentlyPlayedGames": "Ultimi giochi eseguiti",
+ "TabGameSystems": "Sistemi di gioco",
"TitleMediaLibrary": "Libreria",
"TabFolders": "Cartelle",
"TabPathSubstitution": "Percorso da sostiuire",
@@ -509,31 +513,31 @@
"OptionMaxQualityTranscoding": "Massima qualit\u00e0",
"OptionEnableDebugTranscodingLogging": "Abilita la registrazione transcodifica di debug",
"OptionEnableDebugTranscodingLoggingHelp": "Questo creer\u00e0 file di log molto grandi ed \u00e8 consigliato solo se necessario per la risoluzione dei problemi.",
- "EditCollectionItemsHelp": "Aggiungi o rimuovi film, serie, album, libri o giochi e che vuoi raggruppare in questa collezione.",
- "HeaderAddTitles": "Aggiungi Titolo",
+ "EditCollectionItemsHelp": "Aggiungi o rimuovi film, serie, album, libri o giochi che desideri raggruppare in questa collezione.",
+ "HeaderAddTitles": "Aggiungi titoli",
"LabelEnableDlnaPlayTo": "Abilita DLNA su",
- "LabelEnableDlnaPlayToHelp": "Emby can detect devices within your network and offer the ability to remote control them.",
+ "LabelEnableDlnaPlayToHelp": "Emby pu\u00f2 individuare i dispositivi attivi in rete e offrire la possibilit\u00e0 di controllarli da remoto",
"LabelEnableDlnaDebugLogging": "Abilita il debug del DLNA",
"LabelEnableDlnaDebugLoggingHelp": "Questo creer\u00e0 file di log di notevoli dimensioni e deve essere abilitato solo per risolvere eventuali problemi",
"LabelEnableDlnaClientDiscoveryInterval": "Intervallo di ricerca dispositivi (secondi)",
- "LabelEnableDlnaClientDiscoveryIntervalHelp": "Determines the duration in seconds between SSDP searches performed by Emby.",
+ "LabelEnableDlnaClientDiscoveryIntervalHelp": "Determina la durata in secondi tra le ricerche SSDP effettuate da Emby",
"HeaderCustomDlnaProfiles": "Profili personalizzati",
"HeaderSystemDlnaProfiles": "Profili di sistema",
"CustomDlnaProfilesHelp": "Crea un profilo personalizzato per un nuovo dispositivo o sovrascrivi quello di sistema",
"SystemDlnaProfilesHelp": "I profili di sistema sono in sola lettura. Le modifiche ad un profilo di sistema verranno salvate in un nuovo profilo personalizzato.",
- "TitleDashboard": "Dashboard",
+ "TitleDashboard": "Pannello di controllo",
"TabHome": "Home",
"TabInfo": "Info",
"HeaderLinks": "Links",
"HeaderSystemPaths": "Percorsi di sistema",
- "LinkCommunity": "Comunit\u00e0",
+ "LinkCommunity": "Community",
"LinkGithub": "Github",
"LinkApi": "API",
"LinkApiDocumentation": "Documentazione Api",
"LabelFriendlyServerName": "Nome condiviso del server:",
"LabelFriendlyServerNameHelp": "Questo nome \u00e8 usato per identificare il server sulla rete.Se lasciato vuoto verra usato il nome del pc",
"LabelPreferredDisplayLanguage": "Lingua preferita visualizzata",
- "LabelPreferredDisplayLanguageHelp": "Translating Emby is an ongoing project and is not yet complete.",
+ "LabelPreferredDisplayLanguageHelp": "La traduzione di Emby \u00e8 un'attivit\u00e0 in corso e non \u00e8 ancora conclusa",
"LabelReadHowYouCanContribute": "Leggi come puoi contribuire",
"HeaderNewCollection": "Nuova collezione",
"ButtonSubmit": "Invia",
@@ -541,20 +545,20 @@
"LabelCustomCss": "CSS Personalizzato",
"LabelCustomCssHelp": "Applica il tuo CSS personale all'interfaccia web",
"LabelLocalHttpServerPortNumber": "Porta HTTP locale",
- "LabelLocalHttpServerPortNumberHelp": "The tcp port number that Emby's http server should bind to.",
+ "LabelLocalHttpServerPortNumberHelp": "Numero di porta TCP da associare al server http di Emby",
"LabelPublicHttpPort": "Porta HTTP pubblica",
- "LabelPublicHttpPortHelp": "Il numero di porta pubblica dovrebbe essere mappato verso la porta HTTP locale.",
+ "LabelPublicHttpPortHelp": "Numero di porta pubblica che dovrebbe essere mappato sulla porta HTTP locale.",
"LabelPublicHttpsPort": "Numero porta HTTP pubblica",
- "LabelPublicHttpsPortHelp": "Il numero della porta HTTP pubblica dovrebbe essere mappato verso la porta HTTP locale.",
+ "LabelPublicHttpsPortHelp": "Numero della porta pubblica che dovrebbe essere mappato sulla porta HTTPS locale.",
"LabelEnableHttps": "Riporta HTTPS come indirizzo esterno",
- "LabelEnableHttpsHelp": "se abilitato, il server riporter\u00e0 un url HTTPS ai client come il proprio indirizzo esterno. Questo potrebbe non far funzionare i client che ancora non supportano l'HTTPS",
+ "LabelEnableHttpsHelp": "se abilitato, il server riporter\u00e0 un url HTTPS ai client come il proprio indirizzo esterno.",
"LabelHttpsPort": "Porta HTTPS locale",
- "LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
+ "LabelHttpsPortHelp": "Numero di porta TCP da associare al server https di Emby",
"LabelWebSocketPortNumber": "Numero porta web socket:",
- "LabelEnableAutomaticPortMap": "Abilita mappatura delle porte automatiche",
- "LabelEnableAutomaticPortMapHelp": "Tentativo di mappare automaticamente la porta pubblica alla porta locale tramite UPnP. Questo potrebbe non funzionare con alcuni modelli di router.",
+ "LabelEnableAutomaticPortMap": "Abilita mappatura automatica delle porte",
+ "LabelEnableAutomaticPortMapHelp": "Tenta di mappare automaticamente la porta pubblica sulla porta locale tramite UPnP. Questo potrebbe non funzionare con alcuni modelli di router.",
"LabelExternalDDNS": "Indirizzo WAN esterno",
- "LabelExternalDDNSHelp": "If you have a dynamic DNS enter it here. Emby apps will use it when connecting remotely. Leave empty for automatic detection.",
+ "LabelExternalDDNSHelp": "Se hai un DNS dinamico inserisci l'indirizzo qui. Le app di Emby lo utilizzeranno nelle connessioni remote. Lascia il campo vuoto per sfruttare la rilevazione automatica",
"TabResume": "Riprendi",
"TabWeather": "Tempo",
"TitleAppSettings": "Impostazioni delle app",
@@ -564,8 +568,8 @@
"LabelMinResumePercentageHelp": "I film Sono considerati non visti se fermati prima di questo tempo",
"LabelMaxResumePercentageHelp": "I film sono considerati visti se fermati dopo questo tempo",
"LabelMinResumeDurationHelp": "I film pi\u00f9 corti non saranno riprendibili",
- "TitleAutoOrganize": "Organizza Automaticamente",
- "TabActivityLog": "Attivit\u00e0 Eventi",
+ "TitleAutoOrganize": "Organizza Autom.",
+ "TabActivityLog": "Registrazione eventi",
"HeaderName": "Nome",
"HeaderDate": "Data",
"HeaderSource": "Sorgente",
@@ -579,13 +583,13 @@
"LabelSeries": "Serie:",
"LabelSeasonNumber": "Numero Stagione:",
"LabelEpisodeNumber": "Numero Episodio :",
- "LabelEndingEpisodeNumber": "Ultimo Episodio Numero:",
+ "LabelEndingEpisodeNumber": "Numero ultimo episodio:",
"LabelEndingEpisodeNumberHelp": "Richiesto solo se ci sono pi\u00f9 file per espisodio",
- "HeaderSupportTheTeam": "Support the Emby Team",
+ "HeaderSupportTheTeam": "Supporta il Team di Emby",
"LabelSupportAmount": "Ammontare (Dollari)",
- "HeaderSupportTheTeamHelp": "Aiutaci a continuare nello sviluppo di questo progetto tramite una donazione. una parte delle donazioni verranno impiegate per lo sviluppo di Plugins gratuiti.",
- "ButtonEnterSupporterKey": "Inserisci il numero di registrazione",
- "DonationNextStep": "Pe favore rientra ed inserisci la chiave di registrazione che hai ricevuto tramite mail.",
+ "HeaderSupportTheTeamHelp": "Aiutaci a continuare lo sviluppo di questo progetto tramite una donazione. Una parte delle donazioni verr\u00e0 impiegata per lo sviluppo di Plugins gratuiti.",
+ "ButtonEnterSupporterKey": "Inserisci il tuo codice Supporter",
+ "DonationNextStep": "Quando hai terminato, per favore rientra ed inserisci il codice Supporter che riceverai per email",
"AutoOrganizeHelp": "Organizzazione automatica monitorizza le cartelle dei file scaricati e li sposter\u00e0 automaticamente nelle tue cartelle dei media.",
"AutoOrganizeTvHelp": "L'organizzazione della TV aggiunger\u00e0 solo episodi nuovi alle serie esistenti. Non verranno create nuove cartelle delle serie.",
"OptionEnableEpisodeOrganization": "Abilita l'organizzazione dei nuovi episodi",
@@ -595,25 +599,25 @@
"LabelMinFileSizeForOrganize": "Dimensioni minime file (MB):",
"LabelMinFileSizeForOrganizeHelp": "I file al di sotto di questa dimensione verranno ignorati.",
"LabelSeasonFolderPattern": "Modello della cartella Stagione:",
- "LabelSeasonZeroFolderName": "Modello della cartella Stagione ZERO:",
+ "LabelSeasonZeroFolderName": "Nome della cartella Stagione Zero:",
"HeaderEpisodeFilePattern": "Modello del file Episodio:",
"LabelEpisodePattern": "Modello Episodio:",
"LabelMultiEpisodePattern": "Modello dei multi-file episodio:",
"HeaderSupportedPatterns": "Modelli supportati",
"HeaderTerm": "Termine",
"HeaderPattern": "Modello",
- "HeaderResult": "Resultato",
+ "HeaderResult": "Risultato",
"LabelDeleteEmptyFolders": "Elimina le cartelle vuote dopo l'organizzazione automatica",
"LabelDeleteEmptyFoldersHelp": "Attivare questa opzione per mantenere la directory di download pulita.",
"LabelDeleteLeftOverFiles": "Elimina i file rimasti con le seguenti estensioni:",
- "LabelDeleteLeftOverFilesHelp": "Separare con ; Per esempio:.. Nfo; txt",
- "OptionOverwriteExistingEpisodes": "Sovrascrivere episodi esistenti",
+ "LabelDeleteLeftOverFilesHelp": "Separare con ;. Per esempio: .nfo;.txt",
+ "OptionOverwriteExistingEpisodes": "Sovrascrive gli episodi esistenti",
"LabelTransferMethod": "Metodo di trasferimento",
"OptionCopy": "Copia",
"OptionMove": "Sposta",
"LabelTransferMethodHelp": "Copiare o spostare i file dalla cartella da monitorizzare",
"HeaderLatestNews": "Ultime Novit\u00e0",
- "HeaderHelpImproveProject": "Help Improve Emby",
+ "HeaderHelpImproveProject": "Aiuta a migliorare Emby",
"HeaderRunningTasks": "Operazioni in corso",
"HeaderActiveDevices": "Dispositivi Connessi",
"HeaderPendingInstallations": "installazioni in coda",
@@ -624,8 +628,8 @@
"ButtonUpdateNow": "Aggiorna Adesso",
"TabHosting": "Hosting",
"PleaseUpdateManually": "Per favore Arresta il server ed aggiorna manualmente",
- "NewServerVersionAvailable": "A new version of Emby Server is available!",
- "ServerUpToDate": "Emby Server is up to date",
+ "NewServerVersionAvailable": "E' disponibile una nuova versione del Server Emby!",
+ "ServerUpToDate": "Il Server Emby \u00e8 aggiornato",
"LabelComponentsUpdated": "I seguenti componenti sono stati installati o aggiornati:",
"MessagePleaseRestartServerToFinishUpdating": "Si prega di riavviare il server per completare l'applicazione degli aggiornamenti.",
"LabelDownMixAudioScale": "Boost audio durante il downmix:",
@@ -642,13 +646,13 @@
"LabelSupporterEmailAddress": "La mail che \u00e8 stata utilizzata per acquistare la chiave",
"ButtonRetrieveKey": "Recupera chiave",
"LabelSupporterKey": "Chiave (incollala dalla mail ricevuta)",
- "LabelSupporterKeyHelp": "Enter your supporter key to start enjoying additional benefits the community has developed for Emby.",
+ "LabelSupporterKeyHelp": "Inserisci il tuo codice Supporter per iniziare a goderti ulteriori funzioni che la community ha sviluppato per Emby",
"MessageInvalidKey": "Chiave Sostenitore mancante o non valida.",
- "ErrorMessageInvalidKey": "In order for any premium content to be registered, you must also be an Emby Supporter. Please donate and support the continued development of the core product. Thank you.",
+ "ErrorMessageInvalidKey": "Affinch\u00e8 un contenuto premium venga registrato, tu devi anche essere un Supporter di Emby. Per favore, fai una donazione e supporta il continuo sviluppo del prodotto principale. Grazie",
"HeaderDisplaySettings": "Configurazione Monitor",
"TabPlayTo": "Riproduci su",
"LabelEnableDlnaServer": "Abilita server DLNA",
- "LabelEnableDlnaServerHelp": "Allows UPnP devices on your network to browse and play Emby content.",
+ "LabelEnableDlnaServerHelp": "Consente ai dispositivi UPnP nella tua rete di sfogliare i contenuti di Emby e riprodurli",
"LabelEnableBlastAliveMessages": "Invia segnale di presenza",
"LabelEnableBlastAliveMessagesHelp": "Attivare questa opzione se il server non viene rilevato in modo affidabile da altri dispositivi UPnP in rete.",
"LabelBlastMessageInterval": "Intervallo messaggi di presenza (secondi)",
@@ -676,13 +680,13 @@
"NotificationOptionVideoPlayback": "La riproduzione video \u00e8 iniziata",
"NotificationOptionAudioPlayback": "Riproduzione audio iniziata",
"NotificationOptionGamePlayback": "Gioco avviato",
- "NotificationOptionVideoPlaybackStopped": "Video Fermato",
+ "NotificationOptionVideoPlaybackStopped": "Riproduzione video interrotta",
"NotificationOptionAudioPlaybackStopped": "Audio Fermato",
"NotificationOptionGamePlaybackStopped": "Gioco Fermato",
"NotificationOptionTaskFailed": "Operazione pianificata fallita",
"NotificationOptionInstallationFailed": "Installazione fallita",
"NotificationOptionNewLibraryContent": "Nuovo contenuto aggiunto",
- "NotificationOptionNewLibraryContentMultiple": "Nuovi contenuti aggiunti",
+ "NotificationOptionNewLibraryContentMultiple": "Nuovi contenuti aggiunti (multipli)",
"NotificationOptionCameraImageUploaded": "Immagine fotocamera caricata",
"NotificationOptionUserLockedOut": "Utente bloccato",
"HeaderSendNotificationHelp": "Per impostazione predefinita, le notifiche vengono inviate alla casella della pagina principale. Sfoglia il catalogo plugin da installare opzioni di notifica aggiuntive.",
@@ -764,7 +768,7 @@
"LabelUserLibrary": "Libreria utente:",
"LabelUserLibraryHelp": "Selezionare la libreria utente da visualizzare sul dispositivo. Lasciare vuoto per ereditare l'impostazione predefinita.",
"OptionPlainStorageFolders": "Visualizzare tutte le cartelle come normali cartelle di archiviazione",
- "OptionPlainStorageFoldersHelp": "Se abilitato, tutte le cartelle sono rappresentati in DIDL come \"object.container.storageFolder\" invece che di tipo pi\u00f9 specifico, come \"object.container.person.musicArtist\".",
+ "OptionPlainStorageFoldersHelp": "Se abilitato, tutte le cartelle sono rappresentate in DIDL come \"object.container.storageFolder\" invece che di tipo pi\u00f9 specifico, come \"object.container.person.musicArtist\".",
"OptionPlainVideoItems": "Mostra tutti i video come normali file video",
"OptionPlainVideoItemsHelp": "Se attivato, tutti i video sono rappresentati in DIDL come \"object.item.videoItem\" invece che di tipo pi\u00f9 specifico, come \"object.item.videoItem.movie\".",
"LabelSupportedMediaTypes": "Tipi di media supportati:",
@@ -788,7 +792,7 @@
"LabelIconMaxHeight": "Altezza Icona massima:",
"LabelIconMaxHeightHelp": "Risoluzione massima delle icone inviate tramite upnp:icon.",
"LabelIdentificationFieldHelp": "Una stringa o espressione regex sensibile a maiuscole e minuscole.",
- "HeaderProfileServerSettingsHelp": "These values control how Emby Server will present itself to the device.",
+ "HeaderProfileServerSettingsHelp": "Questi valori controllano come il Server Emby si presenter\u00e0 ad un dispositivo.",
"LabelMaxBitrate": "Bitrate Massimo:",
"LabelMaxBitrateHelp": "Specificare un bitrate massimo in presenza di larghezza di banda limitata, o se il dispositivo impone il proprio limite.",
"LabelMaxStreamingBitrate": "Massimo Bitrate streaming",
@@ -829,7 +833,7 @@
"OptionEstimateContentLength": "Stimare la lunghezza contenuto durante la transcodifica",
"OptionReportByteRangeSeekingWhenTranscoding": "Segnala che il server supporta la ricerca di byte durante la transcodifica",
"OptionReportByteRangeSeekingWhenTranscodingHelp": "Questo \u00e8 necessario per alcuni dispositivi che non hanno l'avanzamento rapido che funziona bene.",
- "HeaderSubtitleDownloadingHelp": "When Emby scans your video files it can search for missing subtitles, and download them using a subtitle provider such as OpenSubtitles.org.",
+ "HeaderSubtitleDownloadingHelp": "Quando Emby fa la scansione dei tuoi file video pu\u00f2 cercare i sottotitoli mancanti e scaricarli usando un provider come OpenSubtitles.org.",
"HeaderDownloadSubtitlesFor": "Scarica sottotitoli per:",
"MessageNoChapterProviders": "Installare un plugin provider capitoli come ChapterDb per attivare le opzioni capitolo aggiuntive.",
"LabelSkipIfGraphicalSubsPresent": "Salta se il video contiene gi\u00e0 i sottotitoli grafici",
@@ -839,7 +843,7 @@
"HeaderDownloadChaptersFor": "Scarica i nomi dei capitoli per:",
"LabelOpenSubtitlesUsername": "Nome utente Open Subtitles:",
"LabelOpenSubtitlesPassword": "Password Open Subtitles:",
- "HeaderChapterDownloadingHelp": "When Emby scans your video files it can download friendly chapter names from the internet using chapter plugins such as ChapterDb.",
+ "HeaderChapterDownloadingHelp": "Quando Emby esegue la scansione dei file video pu\u00f2 scaricare i nomi dei capitoli in modo semplice da internet utilizzando plugin di ricerca capitoli come ChapterDb.",
"LabelPlayDefaultAudioTrack": "Riprodurre la traccia audio di default indipendentemente dalla lingua",
"LabelSubtitlePlaybackMode": "Modalit\u00e0 Sottotitolo:",
"LabelDownloadLanguages": "Scarica lingue:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Pagina Iniziale Sezione 2:",
"LabelHomePageSection3": "Pagina Iniziale Sezione 3:",
"LabelHomePageSection4": "Pagina Iniziale Sezione 4:",
- "OptionMyViewsButtons": "Mie Viste (pulsanti)",
- "OptionMyViews": "Mie Viste",
- "OptionMyViewsSmall": "Mie Viste (piccola)",
+ "OptionMyMediaButtons": "I mei media (pulsanti)",
+ "OptionMyMedia": "I mei media",
+ "OptionMyMediaSmall": "I mei media (piccolo)",
"OptionResumablemedia": "Riprendi",
"OptionLatestMedia": "Ultimi media",
"OptionLatestChannelMedia": "Ultime voci del canale",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Predefinito",
"OptionCommunityMostWatchedSort": "Pi\u00f9 visti",
"TabNextUp": "Da vedere",
- "HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Goditi le caratteristiche aggiuntive",
+ "PlaceholderUsername": "Username",
+ "HeaderBecomeProjectSupporter": "Diventa un Supporter di Emby",
"MessageNoMovieSuggestionsAvailable": "Nessun suggerimento di film attualmente disponibile. Iniziare a guardare e valutare i vostri film, e poi tornare per i suggerimenti.",
"MessageNoCollectionsAvailable": "Le collezioni ti permettono di goderti raccolte personalizzate di Film, Serie TV, Album, Libri e Giochi. Clicca sul + per iniziare a creare le tue Collezioni",
"MessageNoPlaylistsAvailable": "Playlist ti permettere di mettere in coda gli elementi da riprodurre.Usa il tasto destro o tap e tieni premuto quindi seleziona elemento da aggiungere",
@@ -921,7 +925,7 @@
"LabelChannelDownloadAgeHelp": "Contenuti scaricati pi\u00f9 vecchi di questo limite sarnno cancellati. Rimarranno riproducibili via internet in streaming.",
"ChannelSettingsFormHelp": "Installare canali come Trailer e Vimeo nel catalogo plugin.",
"ButtonOptions": "Opzioni",
- "ViewTypePlaylists": "Playlists",
+ "ViewTypePlaylists": "Playlist",
"ViewTypeMovies": "Film",
"ViewTypeTvShows": "Serie Tv",
"ViewTypeGames": "Giochi",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Preferiti",
"ViewTypeMovieGenres": "Generi",
"ViewTypeMusicLatest": "Ultimi",
+ "ViewTypeMusicPlaylists": "Playlist",
"ViewTypeMusicAlbums": "Album",
"ViewTypeMusicAlbumArtists": "Album Artisti",
"HeaderOtherDisplaySettings": "Impostazioni Video",
@@ -969,9 +974,9 @@
"LabelProtocolInfo": "Info protocollo:",
"LabelProtocolInfoHelp": "Il valore che verr\u00e0 utilizzato quando si risponde a richieste GetProtocolInfo dal dispositivo.",
"TabNfo": "Nfo",
- "HeaderKodiMetadataHelp": "Emby includes native support for Nfo metadata files. To enable or disable Nfo metadata, use the Advanced tab to configure options for your media types.",
+ "HeaderKodiMetadataHelp": "Emby include il supporto nativo per i file di metadati di tipo NFO. Per attivare o disattivare i metadati NFO, utilizza la scheda Avanzate per configurare le opzioni per i tuoi tipi di file multimediali.",
"LabelKodiMetadataUser": "Sincronizza i dati utente a nfo di per:",
- "LabelKodiMetadataUserHelp": "Enable this to keep watch data in sync between Emby Server and Nfo files.",
+ "LabelKodiMetadataUserHelp": "Abilita questa opzione per mantenere i dati di orologio sincronizzati tra il Server Emby e i file NFO.",
"LabelKodiMetadataDateFormat": "Data di uscita Formato:",
"LabelKodiMetadataDateFormatHelp": "Tutte le date all'interno del nfo verranno letti e scritti utilizzando questo formato.",
"LabelKodiMetadataSaveImagePaths": "Salva percorsi delle immagini all'interno dei file NFO",
@@ -989,7 +994,7 @@
"TabLogs": "Logs",
"HeaderServerLogFiles": "File log del Server:",
"TabBranding": "Personalizza",
- "HeaderBrandingHelp": "Customize the appearance of Emby to fit the needs of your group or organization.",
+ "HeaderBrandingHelp": "Personalizza l'aspetto di Emby per soddisfare le esigenze del tuo gruppo o della tua organizzazione.",
"LabelLoginDisclaimer": "Avviso Login:",
"LabelLoginDisclaimerHelp": "Questo verr\u00e0 visualizzato nella parte inferiore della pagina di accesso.",
"LabelAutomaticallyDonate": "Donare automaticamente questo importo ogni mese",
@@ -999,13 +1004,13 @@
"TitleServer": "Server",
"LabelCache": "Cache:",
"LabelLogs": "Log:",
- "LabelMetadata": "Metadata:",
+ "LabelMetadata": "Metadati:",
"LabelImagesByName": "Immagini per nome:",
"LabelTranscodingTemporaryFiles": "Transcodifica file temporanei:",
"HeaderLatestMusic": "Musica Recente",
"HeaderBranding": "Personalizza",
"HeaderApiKeys": "Chiavi Api",
- "HeaderApiKeysHelp": "External applications are required to have an Api key in order to communicate with Emby Server. Keys are issued by logging in with an Emby account, or by manually granting the application a key.",
+ "HeaderApiKeysHelp": "Le Applicazioni esterne devono avere una chiave API per comunicare con il Server Emby. Le chiavi sono emesse accedendo con un account Emby, o fornendo manualmente una chiave all'applicazione.",
"HeaderApiKey": "Chiave Api",
"HeaderApp": "App",
"HeaderDevice": "Dispositivo",
@@ -1015,8 +1020,8 @@
"HeaderNewApiKey": "Nuova Chiave Api",
"LabelAppName": "Nome app",
"LabelAppNameExample": "Esempio: Sickbeard, NzbDrone",
- "HeaderNewApiKeyHelp": "Grant an application permission to communicate with Emby Server.",
- "HeaderHttpHeaders": "Http Headers",
+ "HeaderNewApiKeyHelp": "Concedere un permesso per applicazione al fine di comunicare con il Server Emby.",
+ "HeaderHttpHeaders": "Intestazioni Http",
"HeaderIdentificationHeader": "Identification Header",
"LabelValue": "valore:",
"LabelMatchType": "Match type:",
@@ -1119,7 +1124,7 @@
"UserDeletedWithName": "Utente {0} \u00e8 stato cancellato",
"MessageServerConfigurationUpdated": "Configurazione server aggioprnata",
"MessageNamedServerConfigurationUpdatedWithValue": "La sezione {0} \u00e8 stata aggiornata",
- "MessageApplicationUpdated": "Emby Server has been updated",
+ "MessageApplicationUpdated": "Il Server Emby \u00e8 stato aggiornato",
"AuthenticationSucceededWithUserName": "{0} Autenticati con successo",
"FailedLoginAttemptWithUserName": "Login fallito da {0}",
"UserDownloadingItemWithValues": "{0} sta scaricando {1}",
@@ -1140,14 +1145,14 @@
"ViewTypeLiveTvRecordingGroups": "Registrazioni",
"ViewTypeLiveTvChannels": "canali",
"LabelEasyPinCode": "Codice Pin",
- "EasyPasswordHelp": "Your easy pin code is used for offline access with supported Emby apps, and can also be used for easy in-network sign in.",
+ "EasyPasswordHelp": "Il codice pin facile viene utilizzato per l'accesso offline con le app Emby supportate, e pu\u00f2 essere utilizzato anche per una facile accesso in rete.",
"LabelInNetworkSignInWithEasyPassword": "Abilita l'accesso da rete locale tramite codice PIN.",
- "LabelInNetworkSignInWithEasyPasswordHelp": "If enabled, you'll be able to use your easy pin code to sign in to Emby apps from inside your home network. Your regular password will only be needed away from home. If the pin code is left blank, you won't need a password within your home network.",
+ "LabelInNetworkSignInWithEasyPasswordHelp": "Se attivata, sarai in grado di utilizzare il tuo codice pin facile per accedere alle app di Emby all'interno della tua rete domestica. La tua password usuale sar\u00e0 necessaria solo per accedere alle app quando sei fuori casa. Se il codice PIN viene lasciato vuoto, non avrai bisogno di una password quando sei all'interno della tua rete domestica.",
"HeaderPassword": "Password",
"HeaderLocalAccess": "Accesso locale",
"HeaderViewOrder": "Visualizza ordine",
"ButtonResetEasyPassword": "Resetta codice PIN",
- "LabelSelectUserViewOrder": "Choose the order your views will be displayed in within Emby apps",
+ "LabelSelectUserViewOrder": "Scegli l'ordine in cui le tue viste saranno mostrate all'interno della app di Emby",
"LabelMetadataRefreshMode": "Metadata (modo Aggiornamento)",
"LabelImageRefreshMode": "Immagine (modo Aggiornamento)",
"OptionDownloadMissingImages": "Immagini mancanti",
@@ -1164,7 +1169,7 @@
"LabelIfYouWishToContinueWithDeletion": "Se si desidera continuare, si prega di confermare inserendo il valore di:",
"ButtonIdentify": "Identifica",
"LabelAlbumArtist": "Artista Album",
- "LabelAlbumArtists": "Album artists:",
+ "LabelAlbumArtists": "Artisti:",
"LabelAlbum": "Album:",
"LabelCommunityRating": "Voto Comunit\u00e0:",
"LabelVoteCount": "Totale Voti:",
@@ -1249,10 +1254,10 @@
"OptionSaveMetadataAsHidden": "Salvare i metadati e le immagini come file nascosti",
"LabelExtractChaptersDuringLibraryScan": "Estrarre immagini capitolo durante la scansione biblioteca",
"LabelExtractChaptersDuringLibraryScanHelp": "Se abilitata, le immagini capitolo verranno estratti quando i video vengono importati durante la scansione della libreria. Se disabilitata verranno estratti durante le immagini dei capitoli programmati compito, permettendo la scansione biblioteca regolare per completare pi\u00f9 velocemente.",
- "LabelConnectGuestUserName": "Their Emby username or email address:",
- "LabelConnectUserName": "Emby username\/email:",
- "LabelConnectUserNameHelp": "Connect this user to an Emby account to enable easy sign-in access from any Emby app without having to know the server ip address.",
- "ButtonLearnMoreAboutEmbyConnect": "Learn more about Emby Connect",
+ "LabelConnectGuestUserName": "Username di Emby o indirizzo email:",
+ "LabelConnectUserName": "Username\/email di Emby:",
+ "LabelConnectUserNameHelp": "Collegare questo utente a un account Emby per consentire un facile accesso da qualsiasi app Emby senza dover conoscere l'indirizzo IP del server.",
+ "ButtonLearnMoreAboutEmbyConnect": "Scopri di pi\u00f9 su Emby Connect",
"LabelExternalPlayers": "Player esterni:",
"LabelExternalPlayersHelp": "Pulsanti di visualizzazione di riprodurre contenuti in lettori esterni. Questo \u00e8 disponibile solo su dispositivi che supportano schemi URL, generalmente Android e iOS. Con i giocatori esterni vi \u00e8 generalmente alcun supporto per il controllo remoto o ripresa.",
"HeaderSubtitleProfile": "Profilo sottotitolo",
@@ -1300,7 +1305,7 @@
"TitleDevices": "Dispositivi",
"TabCameraUpload": "Caricamenti Fotocamera",
"TabDevices": "Dispositivi",
- "HeaderCameraUploadHelp": "Automatically upload photos and videos taken from your mobile devices into Emby.",
+ "HeaderCameraUploadHelp": "Fa automaticamente l'upload su Emby delle foto e dei video residenti sul tuo telefonino",
"MessageNoDevicesSupportCameraUpload": "Al momento non si dispone di dispositivi che supportano il caricamento della fotocamera.",
"LabelCameraUploadPath": "Fotocamera percorso di upload:",
"LabelCameraUploadPathHelp": "Selezionare un percorso di caricamento personalizzato, se lo si desidera. Se non specificato verr\u00e0 utilizzata una cartella predefinita. Se si utilizza un percorso personalizzato che dovr\u00e0 anche essere aggiunti nella zona di installazione della libreria.",
@@ -1309,10 +1314,10 @@
"LabelCustomDeviceDisplayName": "Nome da visualizzare:",
"LabelCustomDeviceDisplayNameHelp": "Fornire un nome di visualizzazione personalizzato o lasciare vuoto per utilizzare il nome riportato dal dispositivo.",
"HeaderInviteUser": "Invita utente",
- "LabelConnectGuestUserNameHelp": "This is the username that your friend uses to sign in to the Emby website, or their email address.",
- "HeaderInviteUserHelp": "Sharing your media with friends is easier than ever before with Emby Connect.",
+ "LabelConnectGuestUserNameHelp": "Questo \u00e8 lo username che il tuo amico utilizza per accedere al sito web Emby, o il suo indirizzo email.",
+ "HeaderInviteUserHelp": "Condividere i tuo file multimediali con gli amici \u00e8 pi\u00f9 facile che mai con Emby Connect.",
"ButtonSendInvitation": "Invia Invito",
- "HeaderSignInWithConnect": "Sign in with Emby Connect",
+ "HeaderSignInWithConnect": "Accedi con Emby Connect",
"HeaderGuests": "ospiti",
"HeaderLocalUsers": "Utenti locale",
"HeaderPendingInvitations": "Inviti in sospeso",
@@ -1327,8 +1332,8 @@
"OptionEveryday": "Tutti i giorni",
"OptionWeekdays": "Feriali",
"OptionWeekends": "Il Weekend",
- "MessageProfileInfoSynced": "User profile information synced with Emby Connect.",
- "HeaderOptionalLinkEmbyAccount": "Optional: Link your Emby account",
+ "MessageProfileInfoSynced": "Informazioni sul profilo utente sincronizzate con Emby Connect.",
+ "HeaderOptionalLinkEmbyAccount": "Opzionale: collega il tuo account Emby",
"ButtonTrailerReel": "Trailer b.",
"HeaderTrailerReel": "Trailer b.",
"OptionPlayUnwatchedTrailersOnly": "Riproduci solo i trailer non visti",
@@ -1378,13 +1383,39 @@
"LabelTagFilterAllowModeHelp": "Se i tag permessi vengono utilizzati come parte di una struttura di cartelle profondamente nidificate, il contenuto che viene etichettato richieder\u00e0 cartelle principali di essere etichettato come bene.",
"HeaderThisUserIsCurrentlyDisabled": "Questo utente \u00e8 al momento disabilitato",
"MessageReenableUser": "Guarda in basso per ri-abilitare",
- "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
- "OptionTVMovies": "TV Movies",
- "HeaderUpcomingMovies": "Upcoming Movies",
- "HeaderUpcomingPrograms": "Upcoming Programs",
+ "LabelEnableInternetMetadataForTvPrograms": "Fa il download da Internet dei metadati per:",
+ "OptionTVMovies": "Film TV",
+ "HeaderUpcomingMovies": "Film in arrivo",
+ "HeaderUpcomingSports": "Sport in arrivo",
+ "HeaderUpcomingPrograms": "Programmi in arrivo",
"ButtonMoreItems": "Pi\u00f9...",
- "LabelShowLibraryTileNames": "Show library tile names",
- "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
- "OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "LabelShowLibraryTileNames": "Mostra i nomi di file di libreria",
+ "LabelShowLibraryTileNamesHelp": "Determina se le etichette vengono visualizzate sotto le locandine della libreria sulla home page",
+ "OptionEnableTranscodingThrottle": "Abilita il throttling",
+ "OptionEnableTranscodingThrottleHelp": "Il Throttling regola automaticamente la velocit\u00e0 di transcodifica per ridurre al minimo l'utilizzo della CPU del server durante la riproduzione.",
+ "LabelUploadSpeedLimit": "Velocit\u00e0 limite di upload (Mbps)",
+ "OptionAllowSyncTranscoding": "Abilita la sincronizzazione che necessita di transcodifica",
+ "HeaderPlayback": "Riproduzione",
+ "OptionAllowAudioPlaybackTranscoding": "Abilita la riproduzione di audio che necessita di transcodifica",
+ "OptionAllowVideoPlaybackTranscoding": "Abilita la riproduzione di video che necessita di transcodifica",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Gli utenti riceveranno messaggi esplicativi quando il contenuto non \u00e8 riproducibile a causa della policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Bitrate limite del client remoto (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "Limite opzionale al bitrate dello streaming per tutti i client remoti. E' utile per evitare che i client richiedano un bitrate superiore a quello che la tua connessione \u00e8 in grado di gestire.",
+ "LabelConversionCpuCoreLimit": "Limite della CPU:",
+ "LabelConversionCpuCoreLimitHelp": "Limiita il numero di CPU da utilizzare durante l'operazione di sincronizzazione.",
+ "OptionEnableFullSpeedConversion": "Abilita conversione a velocit\u00e0 piena",
+ "OptionEnableFullSpeedConversionHelp": "Per default, la sincronizzazione viene eseguita a bassa velocit\u00e0 per minimizzare il consumo di risorse",
+ "HeaderPlaylists": "Playlist",
+ "HeaderSelectDate": "Seleziona la data",
+ "HeaderWelcomeExclamation": "Benvenuto!",
+ "HeaderMyPreferences": "Le miei preferenze",
+ "ButtonMyPreferencesWelcomeYes": "Grazie, preferisco impostare le mie preferenze adesso",
+ "ButtonMyPreferencesWelcomeNo": "No grazie, provveder\u00f2 in seguito.",
+ "MyPreferencesWelcomeMessage1": "Abbiamo presentato la tua libreria in un modo in cui pensiamo ti possa piacere. L'aspetto e il raggruppamento dei contenuti possono essere cambiati in qualsiasi momento modificando le preferenze. Le preferenze si applicano a tutte le app Emby.",
+ "MyPreferencesWelcomeMessage2": "Desideri impostare le tue preferenze ora?",
+ "ToAccessPreferencesHelp": "Per accedere alle preferenze in un secondo tempo, fare clic sull'icona utente presente in alto a destra e seleziona Le Mie Preferenze.",
+ "HeaderViewStyles": "Stili Viste",
+ "LabelSelectViewStyles": "Abilita presentazioni arricchite per:",
+ "LabelSelectViewStylesHelp": "Se abilitato, le viste verranno create con i metadati per offrire categorie come Suggeriti, Recenti, Generi e altro. Se disabilitato, verranno mostrate come semplici cartelle."
} \ 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 0f9ae2bed..ddcbbfb7f 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/kk.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/kk.json
@@ -29,7 +29,7 @@
"WizardCompleted": "\u04d8\u0437\u0456\u0440\u0448\u0435 \u0431\u04b1\u043b \u0431\u0456\u0437\u0433\u0435 \u043a\u0435\u0440\u0435\u0433\u0456\u043d\u0456\u04a3 \u0431\u04d9\u0440\u0456 \u0431\u043e\u043b\u044b\u043f \u0442\u0430\u0431\u044b\u043b\u0430\u0434\u044b. Emby \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430\u04a3\u044b\u0437 \u0442\u0443\u0440\u0430\u043b\u044b \u043c\u04d9\u043b\u0456\u043c\u0435\u0442\u0442\u0435\u0440\u0434\u0456 \u0436\u0438\u043d\u0430\u0439 \u0431\u0430\u0441\u0442\u0430\u0434\u044b. \u0415\u043d\u0434\u0456 \u043a\u0435\u0439\u0431\u0456\u0440 \u0431\u0456\u0437\u0434\u0456\u04a3 \u049b\u043e\u043b\u0434\u0430\u043d\u0431\u0430\u043b\u0430\u0440\u044b\u043c\u044b\u0437\u0431\u0435\u043d \u0442\u0430\u043d\u044b\u0441\u044b\u04a3\u044b\u0437, \u0436\u04d9\u043d\u0435 \u043a\u0435\u0439\u0456\u043d <b>\u0414\u0430\u0439\u044b\u043d<\/b> \u0442\u04af\u0439\u043c\u0435\u0448\u0456\u0433\u0456\u043d \u0431\u0430\u0441\u044b\u04a3\u044b\u0437, \u0441\u043e\u043d\u0434\u0430 <b>\u0421\u0435\u0440\u0432\u0435\u0440\u0434\u0456\u04a3 \u0411\u0430\u049b\u044b\u043b\u0430\u0443 \u0442\u0430\u049b\u0442\u0430\u0441\u044b<\/b> \u049b\u0430\u0440\u0430\u0443\u0493\u0430 \u0448\u044b\u0493\u044b \u043a\u0435\u043b\u0435\u0434\u0456.",
"LabelConfigureSettings": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440\u0434\u0456 \u0442\u0435\u04a3\u0448\u0435\u0443",
"LabelEnableVideoImageExtraction": "\u0411\u0435\u0439\u043d\u0435 \u0441\u0443\u0440\u0435\u0442\u0456\u043d \u0448\u044b\u0493\u0430\u0440\u044b\u043f \u0430\u043b\u0443\u0434\u044b \u049b\u043e\u0441\u0443",
- "VideoImageExtractionHelp": "\u04d8\u043b\u0456 \u0434\u0435 \u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440\u0456 \u0436\u043e\u049b, \u0436\u04d9\u043d\u0435 \u043e\u043b\u0430\u0440 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0442\u0435 \u0442\u0430\u0431\u044b\u043b\u043c\u0430\u0493\u0430\u043d \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440 \u04af\u0448\u0456\u043d. \u0411\u04b1\u043b \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430\u043d\u044b\u04a3 \u0431\u0430\u0441\u0442\u0430\u043f\u049b\u044b \u0441\u043a\u0430\u043d\u0435\u0440\u043b\u0435\u0443\u0456 \u04af\u0448\u0456\u043d \u049b\u043e\u0441\u044b\u043c\u0448\u0430 \u0443\u0430\u049b\u044b\u0442 \u04af\u0441\u0442\u0435\u0439\u0434\u0456, \u0431\u0456\u0440\u0430\u049b \u043d\u04d9\u0442\u0438\u0436\u0435\u0441\u0456\u043d\u0434\u0435 \u04b1\u043d\u0430\u043c\u0434\u044b\u043b\u0430\u0443 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043c \u0431\u043e\u043b\u0430\u0434\u044b.",
+ "VideoImageExtractionHelp": "\u04d8\u043b\u0456 \u0434\u0435 \u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440\u0456 \u0436\u043e\u049b, \u0436\u04d9\u043d\u0435 \u043e\u043b\u0430\u0440 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0442\u0435 \u0442\u0430\u0431\u044b\u043b\u043c\u0430\u0493\u0430\u043d \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440 \u04af\u0448\u0456\u043d. \u0411\u04b1\u043b \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430\u043d\u044b\u04a3 \u0431\u0430\u0441\u0442\u0430\u043f\u049b\u044b \u0441\u043a\u0430\u043d\u0435\u0440\u043b\u0435\u0443\u0456 \u04af\u0448\u0456\u043d \u049b\u043e\u0441\u044b\u043c\u0448\u0430 \u0443\u0430\u049b\u044b\u0442 \u04af\u0441\u0442\u0435\u0439\u0434\u0456, \u0431\u0456\u0440\u0430\u049b \u043d\u04d9\u0442\u0438\u0436\u0435\u0441\u0456\u043d\u0434\u0435 \u04b1\u043d\u0430\u043c\u0434\u044b\u043b\u0430\u0443 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043c \u0431\u043e\u043b\u0430\u0434\u044b.",
"LabelEnableChapterImageExtractionForMovies": "\u0424\u0438\u043b\u044c\u043c\u0434\u0435\u0440 \u04af\u0448\u0456\u043d \u0441\u0430\u0445\u043d\u0430 \u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440\u0456\u043d \u0448\u044b\u0493\u0430\u0440\u044b\u043f \u0430\u043b\u0443\u0434\u044b \u049b\u043e\u0441\u0443",
"LabelChapterImageExtractionForMoviesHelp": "\u0421\u0430\u0445\u043d\u0430 \u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440\u0456\u043d \u0448\u044b\u0493\u0430\u0440\u044b\u043f \u0430\u043b\u0443 \u043a\u043b\u0438\u0435\u043d\u0442\u0442\u0435\u0440\u0433\u0435 \u0441\u0430\u0445\u043d\u0430 \u0431\u04e9\u043b\u0435\u043a\u0442\u0435\u0443\u0433\u0435 \u0430\u0440\u043d\u0430\u043b\u0493\u0430\u043d \u0441\u044b\u0437\u0431\u0430\u043b\u044b\u049b \u043c\u04d9\u0437\u0456\u0440\u043b\u0435\u0440\u0434\u0456 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0443 \u04af\u0448\u0456\u043d \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0435\u0434\u0456. \u0411\u04b1\u043b \u043f\u0440\u043e\u0446\u0435\u0441 \u0431\u0430\u044f\u0443, \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u0434\u044b \u0442\u043e\u0437\u0434\u044b\u0440\u0430\u0442\u044b\u043d \u0436\u04d9\u043d\u0435 \u0431\u0456\u0440\u0430\u0437 \u0433\u0438\u0433\u0430\u0431\u0430\u0439\u0442 \u043a\u0435\u04a3\u0456\u0441\u0442\u0456\u043a\u0442\u0456 \u049b\u0430\u0436\u0435\u0442 \u0435\u0442\u0435\u0442\u0456\u043d \u0431\u043e\u043b\u0443\u044b \u043c\u04af\u043c\u043a\u0456\u043d. \u0411\u04b1\u043b \u0442\u04af\u043d\u0433\u0456 \u0443\u0430\u049b\u044b\u0442\u044b\u043d\u0430 \u0436\u043e\u0441\u043f\u0430\u0440\u043b\u0430\u0493\u0430\u043d \u0442\u0430\u043f\u0441\u044b\u0440\u043c\u0430 \u0440\u0435\u0442\u0456\u043d\u0434\u0435 \u0436\u04b1\u043c\u044b\u0441 \u0456\u0441\u0442\u0435\u0439\u0434\u0456, \u0434\u0435\u0433\u0435\u043d\u043c\u0435\u043d \u0431\u04b1\u043b \u0416\u043e\u0441\u043f\u0430\u0440\u043b\u0430\u0443\u0448\u044b \u0430\u0439\u043c\u0430\u0493\u044b\u043d\u0434\u0430 \u0442\u0435\u04a3\u0448\u0435\u043b\u0435\u0434\u0456. \u0411\u04b1\u043b \u0442\u0430\u043f\u0441\u044b\u0440\u043c\u0430\u043d\u044b \u049b\u0430\u0440\u0431\u0430\u043b\u0430\u0441 \u0441\u0430\u0493\u0430\u0442\u0442\u0430\u0440\u044b\u043d\u0434\u0430 \u043e\u0440\u044b\u043d\u0434\u0430\u0443 \u04b1\u0441\u044b\u043d\u044b\u043b\u043c\u0430\u0439\u0434\u044b.",
"LabelEnableAutomaticPortMapping": "\u041f\u043e\u0440\u0442 \u0430\u0432\u0442\u043e\u0441\u0430\u043b\u0493\u0430\u0441\u0442\u044b\u0440\u0443\u044b\u043d \u049b\u043e\u0441\u0443",
@@ -52,6 +52,8 @@
"HeaderAddUser": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043d\u044b \u04af\u0441\u0442\u0435\u0443",
"LabelAddConnectSupporterHelp": "\u0422\u0456\u0437\u0456\u043c\u0434\u0435 \u0436\u043e\u049b \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043d\u044b \u04af\u0441\u0442\u0435\u0443 \u04af\u0448\u0456\u043d, \u0430\u043b\u0434\u044b\u043c\u0435\u043d \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043b\u044b\u049b \u043f\u0440\u043e\u0444\u0430\u0439\u043b\u044b \u0431\u0435\u0442\u0456\u043d\u0435\u043d Emby Connect \u0430\u0440\u0430\u0441\u044b\u043d\u0434\u0430 \u043e\u043d\u044b\u04a3 \u0442\u0456\u0440\u043a\u0435\u043b\u0433\u0456\u0441\u0456\u043d \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u0442\u0440\u0443\u044b\u04a3\u044b\u0437 \u049b\u0430\u0436\u0435\u0442.",
"LabelPinCode": "PIN-\u043a\u043e\u0434:",
+ "OptionHideWatchedContentFromLatestMedia": "\u0415\u04a3 \u043a\u0435\u0439\u0456\u043d\u0433\u0456 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0435\u043d \u049b\u0430\u0440\u0430\u043b\u0493\u0430\u043d \u043c\u0430\u0437\u043c\u04b1\u043d\u0434\u044b \u0436\u0430\u0441\u044b\u0440\u0443",
+ "HeaderSync": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443",
"ButtonOk": "\u0416\u0430\u0440\u0430\u0439\u0434\u044b",
"ButtonCancel": "\u0411\u043e\u043b\u0434\u044b\u0440\u043c\u0430\u0443",
"ButtonExit": "\u0428\u044b\u0493\u0443",
@@ -76,7 +78,7 @@
"HeaderSyncRequiresSupporterMembership": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u04af\u0448\u0456\u043d \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u043b\u044b\u049b \u043c\u04af\u0448\u0435\u043b\u0456\u043a \u049b\u0430\u0436\u0435\u0442",
"HeaderEnjoyDayTrial": "\u0422\u0435\u0433\u0456\u043d \u0441\u044b\u043d\u0430\u0443\u0434\u044b 14 \u043a\u04af\u043d \u0442\u0430\u043c\u0430\u0448\u0430\u043b\u0430\u04a3\u044b\u0456\u0437",
"LabelSyncTempPath": "\u0423\u0430\u049b\u044b\u0442\u0448\u0430 \u0444\u0430\u0439\u043b \u0436\u043e\u043b\u044b:",
- "LabelSyncTempPathHelp": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u04af\u0448\u0456\u043d \u0442\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u0436\u04b1\u043c\u044b\u0441 \u049b\u0430\u043b\u0442\u0430\u043d\u044b \u0430\u043d\u044b\u049b\u0442\u0430\u04a3\u044b\u0437. \u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u0436\u0430\u0441\u0430\u043b\u0493\u0430\u043d \u0442\u04af\u0440\u043b\u0435\u043d\u0434\u0456\u0440\u0456\u043b\u0433\u0435\u043d \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u043e\u0441\u044b \u043e\u0440\u044b\u043d\u0434\u0430 \u0441\u0430\u049b\u0442\u0430\u043b\u0430\u0434\u044b.",
+ "LabelSyncTempPathHelp": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u04af\u0448\u0456\u043d \u0442\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u0436\u04b1\u043c\u044b\u0441 \u049b\u0430\u043b\u0442\u0430\u043d\u044b \u0430\u043d\u044b\u049b\u0442\u0430\u04a3\u044b\u0437. \u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u043f\u0440\u043e\u0446\u0435\u0441\u0456 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u0436\u0430\u0441\u0430\u043b\u0493\u0430\u043d \u0442\u04af\u0440\u043b\u0435\u043d\u0434\u0456\u0440\u0456\u043b\u0433\u0435\u043d \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u043e\u0441\u044b \u043e\u0440\u044b\u043d\u0434\u0430 \u0441\u0430\u049b\u0442\u0430\u043b\u0430\u0434\u044b.",
"LabelCustomCertificatePath": "\u041a\u0443\u04d9\u043b\u0456\u043a \u0436\u043e\u043b\u044b:",
"LabelCustomCertificatePathHelp": "\u04e8\u0437 SSL-\u043a\u0443\u04d9\u043b\u0456\u0433\u0456\u04a3\u0456\u0437\u0434\u0456\u04a3 .pfx \u0444\u0430\u0439\u043b\u044b\u043d \u0436\u0435\u0442\u043a\u0456\u0437\u0456\u04a3\u0456\u0437. \u0415\u0433\u0435\u0440 \u0442\u04af\u0441\u0456\u0440\u0456\u043b\u0441\u0435, \u0441\u0435\u0440\u0432\u0435\u0440 \u043c\u0435\u043d\u0448\u0456\u043a \u049b\u043e\u043b\u0442\u0430\u04a3\u0431\u0430\u0441\u044b \u0431\u0430\u0440 \u043a\u0443\u04d9\u043b\u0456\u043a\u0442\u0456 \u0436\u0430\u0441\u0430\u0439\u0434\u044b.",
"TitleNotifications": "\u0425\u0430\u0431\u0430\u0440\u043b\u0430\u043d\u0434\u044b\u0440\u0443\u043b\u0430\u0440",
@@ -112,14 +114,14 @@
"HeaderPreferredMetadataLanguage": "\u041c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u0442\u0456\u043b\u0456\u043d\u0456\u04a3 \u0442\u0435\u04a3\u0448\u0435\u043b\u0456\u043c\u0456:",
"LabelSaveLocalMetadata": "\u0421\u0443\u0440\u0435\u0442\u0442\u0435\u043c\u0435\u043b\u0435\u0440 \u0431\u0435\u043d \u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u0442\u0430\u0441\u044b\u0493\u044b\u0448 \u049b\u0430\u043b\u0442\u0430\u043b\u0430\u0440\u044b \u0456\u0448\u0456\u043d\u0434\u0435 \u0441\u0430\u049b\u0442\u0430\u0443",
"LabelSaveLocalMetadataHelp": "\u0421\u0443\u0440\u0435\u0442\u0442\u0435\u043c\u0435\u043b\u0435\u0440 \u0431\u0435\u043d \u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u0442\u0456\u043a\u0435\u043b\u0435\u0439 \u0442\u0430\u0441\u044b\u0493\u044b\u0448 \u049b\u0430\u043b\u0442\u0430\u043b\u0430\u0440\u044b \u0456\u0448\u0456\u043d\u0434\u0435 \u0441\u0430\u049b\u0442\u0430\u043b\u0443\u044b \u043e\u043b\u0430\u0440\u0434\u044b \u0436\u0435\u04a3\u0456\u043b \u04e9\u04a3\u0434\u0435\u0439 \u0430\u043b\u0430\u0442\u044b\u043d \u043e\u0440\u044b\u043d\u0493\u0430 \u049b\u043e\u044f\u0434\u044b.",
- "LabelDownloadInternetMetadata": "\u0421\u0443\u0440\u0435\u0442\u0442\u0435\u043c\u0435\u043b\u0435\u0440 \u0431\u0435\u043d \u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0442\u0435\u043d \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443",
- "LabelDownloadInternetMetadataHelp": "\u0422\u043e\u043b\u044b \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u0456\u043c\u0434\u0435\u0440\u0434\u0456 \u049b\u043e\u0441\u0443 \u04af\u0448\u0456\u043d Emby Server \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u0442\u0443\u0440\u0430\u043b\u044b \u043c\u04d9\u043b\u0456\u043c\u0435\u0442\u0442\u0435\u0440\u0434\u0456 \u0436\u04af\u043a\u0442\u0435\u0443\u0456 \u043c\u04af\u043c\u043a\u0456\u043d.",
+ "LabelDownloadInternetMetadata": "\u0421\u0443\u0440\u0435\u0442\u0442\u0435\u043c\u0435\u043b\u0435\u0440 \u0431\u0435\u043d \u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0442\u0435\u043d \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443",
+ "LabelDownloadInternetMetadataHelp": "\u041c\u0430\u0437\u043c\u04b1\u043d\u0434\u044b \u043a\u04e9\u0440\u043c\u0435\u043b\u0435\u0440\u0434\u0456 \u049b\u043e\u0441\u0443 \u04af\u0448\u0456\u043d Emby Server \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u0442\u0443\u0440\u0430\u043b\u044b \u043c\u04d9\u043b\u0456\u043c\u0435\u0442\u0442\u0435\u0440\u0434\u0456 \u0436\u04af\u043a\u0442\u0435\u0443\u0456 \u043c\u04af\u043c\u043a\u0456\u043d.",
"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\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430\u0493\u0430 \u049b\u0430\u0442\u044b\u043d\u0430\u0443",
"TabAccess": "\u049a\u0430\u0442\u044b\u043d\u0430\u0443",
"TabImage": "\u0421\u0443\u0440\u0435\u0442",
- "TabProfile": "\u041f\u0440\u043e\u0444\u0438\u043b\u044c",
+ "TabProfile": "\u041f\u0440\u043e\u0444\u0430\u0439\u043b",
"TabMetadata": "\u041c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440",
"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",
@@ -143,7 +145,7 @@
"OptionOnlyForcedSubtitlesHelp": "\u0422\u0435\u043a \u049b\u0430\u043d\u0430 \u043c\u04d9\u0436\u0431\u04af\u0440\u043b\u0456 \u0434\u0435\u043f \u0431\u0435\u043b\u0433\u0456\u043b\u0435\u043d\u0433\u0435\u043d \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 \u0436\u04af\u043a\u0442\u0435\u043b\u0435\u0434\u0456.",
"OptionAlwaysPlaySubtitlesHelp": "\u0422\u0456\u043b \u0442\u0435\u04a3\u0448\u0435\u043b\u0456\u043c\u0456\u043d\u0435 \u0441\u04d9\u0439\u043a\u0435\u0441 \u043a\u0435\u043b\u0433\u0435\u043d \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 \u0434\u044b\u0431\u044b\u0441 \u0442\u0456\u043b\u0456\u043d\u0435 \u049b\u0430\u0442\u044b\u0441\u0441\u044b\u0437 \u0436\u04af\u043a\u0442\u0435\u043b\u0435\u0434\u0456.",
"OptionNoSubtitlesHelp": "\u04d8\u0434\u0435\u043f\u043a\u0456\u0434\u0435 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 \u0436\u04af\u043a\u0442\u0435\u043b\u043c\u0435\u0439\u0434\u0456.",
- "TabProfiles": "\u041f\u0440\u043e\u0444\u0438\u043b\u044c\u0434\u0435\u0440",
+ "TabProfiles": "\u041f\u0440\u043e\u0444\u0430\u0439\u043b\u0434\u0430\u0440",
"TabSecurity": "\u049a\u0430\u0443\u0456\u043f\u0441\u0456\u0437\u0434\u0456\u043a",
"ButtonAddUser": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043d\u044b \u04af\u0441\u0442\u0435\u0443",
"ButtonAddLocalUser": "\u0416\u0435\u0440\u0433\u0456\u043b\u0456\u043a\u0442\u0456 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043d\u044b \u04af\u0441\u0442\u0435\u0443",
@@ -167,6 +169,7 @@
"MessageNothingHere": "\u041e\u0441\u044b\u043d\u0434\u0430 \u0435\u0448\u0442\u0435\u043c\u0435 \u0436\u043e\u049b.",
"MessagePleaseEnsureInternetMetadata": "\u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0442\u0435\u043d \u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0456 \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443\u044b \u049b\u043e\u0441\u044b\u043b\u0493\u0430\u043d\u044b\u043d\u0430 \u043a\u04e9\u0437 \u0436\u0435\u0442\u043a\u0456\u0437\u0456\u04a3\u0456\u0437.",
"TabSuggested": "\u04b0\u0441\u044b\u043d\u044b\u043b\u0493\u0430\u043d",
+ "TabSuggestions": "\u04b0\u0441\u044b\u043d\u044b\u0441\u0442\u0430\u0440",
"TabLatest": "\u0415\u04a3 \u043a\u0435\u0439\u0456\u043d\u0433\u0456",
"TabUpcoming": "\u041a\u04af\u0442\u0456\u043b\u0433\u0435\u043d",
"TabShows": "\u041a\u04e9\u0440\u0441\u0435\u0442\u0456\u043c\u0434\u0435\u0440",
@@ -300,7 +303,7 @@
"OptionDisableUserHelp": "\u0415\u0433\u0435\u0440 \u0442\u044b\u0439\u044b\u043c \u0441\u0430\u043b\u044b\u043d\u0441\u0430, \u0441\u0435\u0440\u0432\u0435\u0440 \u0431\u04b1\u043b \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u0434\u0430\u043d \u0435\u0448\u049b\u0430\u043d\u0434\u0430\u0439 \u049b\u043e\u0441\u044b\u043b\u044b\u043c\u0493\u0430 \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u043f\u0435\u0439\u0434\u0456. \u0411\u0430\u0440 \u049b\u043e\u0441\u044b\u043b\u044b\u043c\u0434\u0430\u0440 \u043a\u0435\u043d\u0435\u0442 \u04af\u0437\u0456\u043b\u0435\u0434\u0456.",
"HeaderAdvancedControl": "\u041a\u0435\u04a3\u0435\u0439\u0442\u0456\u043b\u0433\u0435\u043d \u0431\u0430\u0441\u049b\u0430\u0440\u0443",
"LabelName": "\u0410\u0442\u044b:",
- "ButtonHelp": "\u0410\u043d\u044b\u049b\u0442\u0430\u043c\u0430\u0493\u0430",
+ "ButtonHelp": "\u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0442\u0435\u0433\u0456 \u0430\u043d\u044b\u049b\u0442\u0430\u043c\u0430\u0493\u0430",
"OptionAllowUserToManageServer": "\u0411\u0443\u043b \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u0493\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0434\u0456 \u0431\u0430\u0441\u049b\u0430\u0440\u0443 \u04af\u0448\u0456\u043d \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0443",
"HeaderFeatureAccess": "\u0415\u0440\u0435\u043a\u0448\u0435\u043b\u0456\u043a\u0442\u0435\u0440\u0433\u0435 \u049b\u0430\u0442\u044b\u043d\u0430\u0443",
"OptionAllowMediaPlayback": "\u0422\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u043e\u0439\u043d\u0430\u0442\u0443\u0493\u0430 \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0443",
@@ -401,9 +404,10 @@
"ButtonRefresh": "\u0416\u0430\u04a3\u0493\u044b\u0440\u0442\u0443",
"ButtonAdvancedRefresh": "\u041a\u0435\u04a3\u0435\u0439\u0442\u0456\u043b\u0433\u0435\u043d \u0436\u0430\u04a3\u0493\u044b\u0440\u0442\u0443",
"OptionPriority": "\u041f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442",
- "OptionRecordOnAllChannels": "\u0411\u0435\u0440\u0456\u043b\u0456\u043c\u0434\u0456 \u0431\u0430\u0440\u043b\u044b\u049b \u0430\u0440\u043d\u0430\u043b\u0430\u0440\u0434\u0430\u043d \u0436\u0430\u0437\u044b\u043f \u0430\u043b\u0443",
- "OptionRecordAnytime": "\u0411\u0435\u0440\u0456\u043b\u0456\u043c\u0434\u0456 \u04d9\u0440 \u0443\u0430\u049b\u044b\u0442\u0442\u0430 \u0436\u0430\u0437\u044b\u043f \u0430\u043b\u0443",
+ "OptionRecordOnAllChannels": "\u0411\u0430\u0440\u043b\u044b\u049b \u0430\u0440\u043d\u0430\u043b\u0430\u0440\u0434\u0430\u043d \u0436\u0430\u0437\u044b\u043f \u0430\u043b\u0443",
+ "OptionRecordAnytime": "\u04d8\u0440 \u0443\u0430\u049b\u044b\u0442\u0442\u0430 \u0436\u0430\u0437\u044b\u043f \u0430\u043b\u0443",
"OptionRecordOnlyNewEpisodes": "\u0422\u0435\u043a \u049b\u0430\u043d\u0430 \u0436\u0430\u04a3\u0430 \u0431\u04e9\u043b\u0456\u043c\u0434\u0435\u0440\u0434\u0456 \u0436\u0430\u0437\u044b\u043f \u0430\u043b\u0443",
+ "HeaderRepeatingOptions": "\u049a\u0430\u0439\u0442\u0430\u043b\u0430\u043c\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440\u0456",
"HeaderDays": "\u041a\u04af\u043d\u0434\u0435\u0440",
"HeaderActiveRecordings": "\u0411\u0435\u043b\u0441\u0435\u043d\u0434\u0456 \u0436\u0430\u0437\u0443\u043b\u0430\u0440",
"HeaderLatestRecordings": "\u0415\u04a3 \u043a\u0435\u0439\u0456\u04a3\u0433\u0456 \u0436\u0430\u0437\u0431\u0430\u043b\u0430\u0440",
@@ -414,7 +418,7 @@
"ButtonDelete": "\u0416\u043e\u044e",
"ButtonRemove": "\u0410\u043b\u0430\u0441\u0442\u0430\u0443",
"OptionRecordSeries": "\u0422\u0435\u043b\u0435\u0445\u0438\u043a\u0430\u044f\u043d\u044b \u0436\u0430\u0437\u0443",
- "HeaderDetails": "\u041c\u04d9\u043b\u0456\u043c\u0435\u0442\u0442\u0435\u0440",
+ "HeaderDetails": "\u0422\u043e\u043b\u044b\u049b \u043c\u04d9\u043b\u0456\u043c\u0435\u0442\u0442\u0435\u0440",
"TitleLiveTV": "\u042d\u0444\u0438\u0440\u043b\u0456\u043a \u0422\u0414",
"LabelNumberOfGuideDays": "\u0416\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443 \u04af\u0448\u0456\u043d \u0410\u043d\u044b\u049b\u0442\u0430\u0493\u044b\u0448 \u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0456\u043d\u0434\u0435\u0433\u0456 \u043a\u04af\u043d \u0441\u0430\u043d\u044b:",
"LabelNumberOfGuideDaysHelp": "\u041a\u04e9\u0431\u0456\u0440\u0435\u043a \u043a\u04af\u043d\u0434\u0456 \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443 \u0410\u043d\u044b\u049b\u0442\u0430\u0493\u044b\u0448 \u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0456\u043d\u0456\u04a3 \u049b\u04b1\u043d\u0434\u044b\u043b\u044b\u0493\u044b\u043d \u043a\u04e9\u0442\u0435\u0440\u0435\u0434\u0456 \u0434\u0435 \u0430\u043b\u0434\u044b\u043d-\u0430\u043b\u0430 \u0436\u043e\u0441\u043f\u0430\u0440\u043b\u0430\u0443 \u04af\u0448\u0456\u043d \u049b\u0430\u0431\u0456\u043b\u0435\u0442\u0456\u043d \u0436\u04d9\u043d\u0435 \u043a\u04e9\u0431\u0456\u0440\u0435\u043a \u0442\u0456\u0437\u0431\u0435\u043b\u0435\u0440 \u043a\u04e9\u0440\u0443\u0434\u0456 \u049b\u0430\u043c\u0442\u0430\u043c\u0430\u0441\u044b\u0437 \u0435\u0442\u0435\u0434\u0456, \u0431\u0456\u0440\u0430\u049b \u0431\u04b1\u043b \u0436\u04af\u043a\u0442\u0435\u0443 \u0443\u0430\u049b\u044b\u0442\u044b\u043d \u0434\u0430 \u0441\u043e\u0437\u0434\u044b\u0440\u0430\u0434\u044b. \u0410\u0432\u0442\u043e\u0442\u0430\u04a3\u0434\u0430\u0443 \u0430\u0440\u043d\u0430 \u0441\u0430\u043d\u044b\u043d\u0430 \u043d\u0435\u0433\u0456\u0437\u0434\u0435\u043b\u0456\u043d\u0435\u0434\u0456.",
@@ -517,10 +521,10 @@
"LabelEnableDlnaDebugLoggingHelp": "\u04e8\u0442\u0435 \u0430\u0443\u049b\u044b\u043c\u0434\u044b \u0436\u04b1\u0440\u043d\u0430\u043b \u0444\u0430\u0439\u043b\u0434\u0430\u0440\u044b \u0436\u0430\u0441\u0430\u043b\u0430\u0434\u044b \u0436\u04d9\u043d\u0435 \u0442\u0435\u043a \u049b\u0430\u043d\u0430 \u0430\u049b\u0430\u0443\u043b\u044b\u049b\u0442\u0430\u0440\u0434\u044b \u0436\u043e\u044e \u04af\u0448\u0456\u043d \u049b\u0430\u0436\u0435\u0442 \u0431\u043e\u043b\u0493\u0430\u043d \u0440\u0435\u0442\u0456\u043d\u0434\u0435 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u044b\u043b\u0430\u0434\u044b.",
"LabelEnableDlnaClientDiscoveryInterval": "\u041a\u043b\u0438\u0435\u043d\u0442\u0442\u0435\u0440\u0434\u0456 \u0442\u0430\u0443\u044b\u043f \u0430\u0448\u0443 \u0430\u0440\u0430\u043b\u044b\u0493\u044b, \u0441:",
"LabelEnableDlnaClientDiscoveryIntervalHelp": "Emby \u043e\u0440\u044b\u043d\u0434\u0430\u0493\u0430\u043d SSDP \u0441\u0430\u0443\u0430\u043b \u0441\u0430\u043b\u0443 \u0430\u0440\u0430 \u04b1\u0437\u0430\u049b\u0442\u044b\u0493\u044b\u043d \u0441\u0435\u043a\u0443\u043d\u0434\u0442\u0430\u0440 \u0430\u0440\u049b\u044b\u043b\u044b \u0430\u043d\u044b\u049b\u0442\u0430\u0439\u0434\u044b.",
- "HeaderCustomDlnaProfiles": "\u0422\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u043f\u0440\u043e\u0444\u0438\u043b\u044c\u0434\u0435\u0440",
- "HeaderSystemDlnaProfiles": "\u0416\u04af\u0439\u0435\u043b\u0456\u043a \u043f\u0440\u043e\u0444\u0438\u043b\u044c\u0434\u0435\u0440",
- "CustomDlnaProfilesHelp": "\u0416\u0430\u04a3\u0430 \u049b\u04b1\u0440\u044b\u043b\u0493\u044b \u043c\u0430\u049b\u0441\u0430\u0442\u044b \u04af\u0448\u0456\u043d \u0442\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u043f\u0440\u043e\u0444\u0438\u043b\u044c\u0434\u0456 \u0436\u0430\u0441\u0430\u0443 \u043d\u0435 \u0436\u04af\u0439\u0435\u043b\u0456\u043a \u043f\u0440\u043e\u0444\u0438\u043b\u044c\u0434\u0456 \u049b\u0430\u0439\u0442\u0430 \u0430\u043d\u044b\u049b\u0442\u0430\u0443.",
- "SystemDlnaProfilesHelp": "\u0416\u04af\u0439\u0435\u043b\u0456\u043a \u043f\u0440\u043e\u0444\u0438\u043b\u044c\u0434\u0435\u0440 \u0442\u0435\u043a \u043e\u049b\u0443 \u04af\u0448\u0456\u043d. \u0416\u04af\u0439\u0435\u043b\u0456\u043a \u043f\u0440\u043e\u0444\u0438\u043b\u044c\u0434\u0456\u04a3 \u04e9\u0437\u0433\u0435\u0440\u0456\u0441\u0442\u0435\u0440\u0456 \u0436\u0430\u04a3\u0430 \u0442\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u043f\u0440\u043e\u0444\u0438\u043b\u044c\u0433\u0435 \u0436\u0430\u0437\u044b\u043b\u0430\u0434\u044b.",
+ "HeaderCustomDlnaProfiles": "\u0422\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u043f\u0440\u043e\u0444\u0430\u0439\u043b\u0434\u0430\u0440",
+ "HeaderSystemDlnaProfiles": "\u0416\u04af\u0439\u0435\u043b\u0456\u043a \u043f\u0440\u043e\u0444\u0430\u0439\u043b\u0434\u0430\u0440",
+ "CustomDlnaProfilesHelp": "\u0416\u0430\u04a3\u0430 \u049b\u04b1\u0440\u044b\u043b\u0493\u044b \u043c\u0430\u049b\u0441\u0430\u0442\u044b \u04af\u0448\u0456\u043d \u0442\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u043f\u0440\u043e\u0444\u0430\u0439\u043b\u0434\u044b \u0436\u0430\u0441\u0430\u0443 \u043d\u0435 \u0436\u04af\u0439\u0435\u043b\u0456\u043a \u043f\u0440\u043e\u0444\u0430\u0439\u043b\u0434\u044b \u049b\u0430\u0439\u0442\u0430 \u0430\u043d\u044b\u049b\u0442\u0430\u0443.",
+ "SystemDlnaProfilesHelp": "\u0416\u04af\u0439\u0435\u043b\u0456\u043a \u043f\u0440\u043e\u0444\u0430\u0439\u043b\u0434\u0430\u0440 \u0442\u0435\u043a \u043e\u049b\u0443 \u04af\u0448\u0456\u043d. \u0416\u04af\u0439\u0435\u043b\u0456\u043a \u043f\u0440\u043e\u0444\u0430\u0439\u043b\u0434\u044b\u04a3 \u04e9\u0437\u0433\u0435\u0440\u0456\u0441\u0442\u0435\u0440\u0456 \u0436\u0430\u04a3\u0430 \u0442\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u043f\u0440\u043e\u0444\u0430\u0439\u043b\u0493\u0430 \u0436\u0430\u0437\u044b\u043b\u0430\u0434\u044b.",
"TitleDashboard": "\u0411\u0430\u049b\u044b\u043b\u0430\u0443 \u0442\u0430\u049b\u0442\u0430\u0441\u044b",
"TabHome": "\u0411\u0430\u0441\u0442\u044b",
"TabInfo": "\u041f\u0440\u043e\u0444\u0430\u0439\u043b \u0442\u0443\u0440\u0430\u043b\u044b",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "\u0416\u0430\u0440\u0438\u044f https-\u043f\u043e\u0440\u0442 \u043d\u04e9\u043c\u0456\u0440\u0456:",
"LabelPublicHttpsPortHelp": "\u0416\u0435\u0440\u0433\u0456\u043b\u0456\u043a\u0442\u0456 https-\u043f\u043e\u0440\u0442\u044b\u043d\u0430 \u0441\u0430\u043b\u044b\u0441\u0442\u044b\u0440\u044b\u043b\u0443\u044b \u0442\u0438\u0456\u0441 \u0436\u0430\u0440\u0438\u044f \u043f\u043e\u0440\u0442 \u043d\u04e9\u043c\u0456\u0440\u0456.",
"LabelEnableHttps": "HTTPS \u0445\u0430\u0442\u0442\u0430\u043c\u0430\u0441\u044b \u0441\u044b\u0440\u0442\u049b\u044b \u043c\u0435\u043a\u0435\u043d\u0435\u0436\u0430\u0439 \u0440\u0435\u0442\u0456\u043d\u0434\u0435 \u0431\u0430\u044f\u043d\u0434\u0430\u0443",
- "LabelEnableHttpsHelp": "\u0415\u0433\u0435\u0440 \u049b\u043e\u0441\u044b\u043b\u0441\u0430, \u043a\u043b\u0438\u0435\u043d\u0442\u0442\u0435\u0440 \u04af\u0448\u0456\u043d \u0441\u0435\u0440\u0432\u0435\u0440 https url \u0441\u044b\u0440\u0442\u049b\u044b \u043c\u0435\u043a\u0435\u043d\u0436\u0430\u0439 \u0440\u0435\u0442\u0456\u043d\u0434\u0435 \u0431\u0430\u044f\u043d\u0434\u0430\u0439\u0434\u044b. \u0411\u04b1\u043b \u04d9\u043b\u0456 \u0434\u0435 https \u049b\u043e\u043b\u0434\u0430\u043c\u0430\u0439\u0442\u044b\u043d \u043a\u043b\u0438\u0435\u043d\u0442\u0442\u0435\u0440\u0434\u0456\u04a3 \u0436\u04b1\u043c\u044b\u0441\u044b\u043d \u04af\u0437\u0443\u0456 \u043c\u04af\u043c\u043a\u0456\u043d.",
+ "LabelEnableHttpsHelp": "\u0415\u0433\u0435\u0440 \u049b\u043e\u0441\u044b\u043b\u0441\u0430, \u043a\u043b\u0438\u0435\u043d\u0442\u0442\u0435\u0440 \u04af\u0448\u0456\u043d \u0441\u0435\u0440\u0432\u0435\u0440 HTTPS URL \u0441\u044b\u0440\u0442\u049b\u044b \u043c\u0435\u043a\u0435\u043d\u0436\u0430\u0439 \u0440\u0435\u0442\u0456\u043d\u0434\u0435 \u0431\u0430\u044f\u043d\u0434\u0430\u0439\u0434\u044b.",
"LabelHttpsPort": "\u0416\u0435\u0440\u0433\u0456\u043b\u0456\u043a\u0442\u0456 https-\u043f\u043e\u0440\u0442 \u043d\u04e9\u043c\u0456\u0440\u0456:",
"LabelHttpsPortHelp": "Emby HTTPS-\u0441\u0435\u0440\u0432\u0435\u0440\u0456 \u0431\u0430\u0439\u043b\u0430\u0441\u0442\u044b\u0440\u044b\u043b\u0443\u0493\u0430 \u0442\u0438\u0456\u0441\u0442\u0456 TCP-\u043f\u043e\u0440\u0442 \u043d\u04e9\u043c\u0456\u0440\u0456.",
"LabelWebSocketPortNumber": "\u0412\u0435\u0431-\u0441\u043e\u043a\u0435\u0442 \u043f\u043e\u0440\u0442\u044b\u043d\u044b\u04a3 \u043d\u04e9\u043c\u0456\u0440\u0456:",
@@ -654,7 +658,7 @@
"LabelBlastMessageInterval": "\u0411\u0435\u043b\u0441\u0435\u043d\u0434\u0456\u043b\u0456\u043a\u0442\u0456 \u0442\u0435\u043a\u0441\u0435\u0440\u0443 \u0445\u0430\u0431\u0430\u0440\u043b\u0430\u0440 \u0430\u0440\u0430\u043b\u044b\u0493\u044b, \u0441",
"LabelBlastMessageIntervalHelp": "\u0421\u0435\u0440\u0432\u0435\u0440 \u0431\u0435\u043b\u0441\u0435\u043d\u0434\u0456\u043b\u0456\u0433\u0456\u043d \u0442\u0435\u043a\u0441\u0435\u0440\u0443 \u0445\u0430\u0431\u0430\u0440\u043b\u0430\u0440\u0434\u044b\u04a3 \u0430\u0440\u0430 \u04b1\u0437\u0430\u049b\u0442\u044b\u0493\u044b\u043d \u0441\u0435\u043a\u0443\u043d\u0434\u0442\u0430\u0440 \u0430\u0440\u049b\u044b\u043b\u044b \u0430\u043d\u044b\u049b\u0442\u0430\u0439\u0434\u044b.",
"LabelDefaultUser": "\u04d8\u0434\u0435\u043f\u043a\u0456 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b:",
- "LabelDefaultUserHelp": "\u049a\u04b1\u0440\u044b\u043b\u0493\u044b\u043b\u0430\u0440 \u049b\u043e\u0441\u044b\u043b\u0493\u0430\u043d\u0434\u0430 \u049b\u0430\u0439 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043d\u044b\u04a3 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430\u0441\u044b \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u043d\u0443\u0456 \u0442\u0438\u0456\u0441\u0442\u0456\u043b\u0456\u0433\u0456\u043d \u0430\u043d\u044b\u049b\u0442\u0430\u0439\u0434\u044b. \u041f\u0440\u043e\u0444\u0438\u043b\u044c\u0434\u0435\u0440\u0434\u0456 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0493\u0430\u043d\u0434\u0430 \u0431\u04b1\u043b \u04d9\u0440 \u049b\u04b1\u0440\u044b\u043b\u0493\u044b \u04af\u0448\u0456\u043d \u049b\u0430\u0439\u0442\u0430 \u0442\u0430\u0493\u0430\u0439\u044b\u043d\u0434\u0430\u043b\u0443\u044b \u043c\u04af\u043c\u043a\u0456\u043d.",
+ "LabelDefaultUserHelp": "\u049a\u04b1\u0440\u044b\u043b\u0493\u044b\u043b\u0430\u0440 \u049b\u043e\u0441\u044b\u043b\u0493\u0430\u043d\u0434\u0430 \u049b\u0430\u0439 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043d\u044b\u04a3 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430\u0441\u044b \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u043d\u0443\u0456 \u0442\u0438\u0456\u0441\u0442\u0456\u043b\u0456\u0433\u0456\u043d \u0430\u043d\u044b\u049b\u0442\u0430\u0439\u0434\u044b. \u041f\u0440\u043e\u0444\u0430\u0439\u043b\u0434\u0430\u0440\u0434\u044b \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0493\u0430\u043d\u0434\u0430 \u0431\u04b1\u043b \u04d9\u0440 \u049b\u04b1\u0440\u044b\u043b\u0493\u044b \u04af\u0448\u0456\u043d \u049b\u0430\u0439\u0442\u0430 \u0442\u0430\u0493\u0430\u0439\u044b\u043d\u0434\u0430\u043b\u0443\u044b \u043c\u04af\u043c\u043a\u0456\u043d.",
"TitleDlna": "DLNA",
"TitleChannels": "\u0410\u0440\u043d\u0430\u043b\u0430\u0440",
"HeaderServerSettings": "\u0421\u0435\u0440\u0432\u0435\u0440 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440\u0456",
@@ -839,7 +843,7 @@
"HeaderDownloadChaptersFor": "\u041c\u044b\u043d\u0430\u0493\u0430\u043d \u0441\u0430\u0445\u043d\u0430\u043b\u0430\u0440 \u0430\u0442\u0430\u0443\u043b\u0430\u0440\u044b\u043d \u0436\u04af\u043a\u0442\u0435\u0443:",
"LabelOpenSubtitlesUsername": "Open Subtitles \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b \u0430\u0442\u044b:",
"LabelOpenSubtitlesPassword": "Open Subtitles \u049b\u04b1\u043f\u0438\u044f \u0441\u04e9\u0437\u0456:",
- "HeaderChapterDownloadingHelp": "Emby \u0431\u0435\u0439\u043d\u0435\u0444\u0430\u0439\u043b\u0434\u0430\u0440\u0434\u044b \u0441\u043a\u0430\u043d\u0435\u0440\u043b\u0435\u0433\u0435\u043d\u0434\u0435 \u0431\u04b1\u043b \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0442\u0435\u043d ChapterDb \u0441\u0438\u044f\u049b\u0442\u044b \u0441\u0430\u0445\u043d\u0430 \u043f\u043b\u0430\u0433\u0438\u043d\u0434\u0435\u0440\u0456 \u0430\u0440\u049b\u044b\u043b\u044b \u043e\u04a3\u0430\u0439 \u0441\u0430\u0445\u043d\u0430 \u0442\u0430\u0443\u043b\u0430\u0440\u044b\u043d \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443\u044b \u043c\u04af\u043c\u043a\u0456\u043d.",
+ "HeaderChapterDownloadingHelp": "Emby \u0431\u0435\u0439\u043d\u0435\u0444\u0430\u0439\u043b\u0434\u0430\u0440\u0434\u044b \u0441\u043a\u0430\u043d\u0435\u0440\u043b\u0435\u0433\u0435\u043d\u0434\u0435 \u0431\u04b1\u043b \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0442\u0435\u043d ChapterDb \u0441\u0438\u044f\u049b\u0442\u044b \u0441\u0430\u0445\u043d\u0430 \u043f\u043b\u0430\u0433\u0438\u043d\u0434\u0435\u0440\u0456 \u0430\u0440\u049b\u044b\u043b\u044b \u043e\u04a3\u0430\u0439 \u0441\u0430\u0445\u043d\u0430 \u0442\u0430\u0443\u043b\u0430\u0440\u044b\u043d \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443\u044b \u043c\u04af\u043c\u043a\u0456\u043d.",
"LabelPlayDefaultAudioTrack": "\u0422\u0456\u043b\u0433\u0435 \u049b\u0430\u0442\u044b\u0441\u0441\u044b\u0437 \u04d9\u0434\u0435\u043f\u043a\u0456 \u0434\u044b\u0431\u044b\u0441 \u0436\u043e\u043b\u0448\u044b\u0493\u044b\u043d \u043e\u0439\u043d\u0430\u0442\u0443",
"LabelSubtitlePlaybackMode": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440 \u0440\u0435\u0436\u0456\u043c\u0456:",
"LabelDownloadLanguages": "\u0416\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u044b\u043d\u0430\u0442\u044b\u043d \u0442\u0456\u043b\u0434\u0435\u0440:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "\u0411\u0430\u0441\u0442\u044b \u0431\u0435\u0442 2-\u0431\u04e9\u043b\u0456\u043c:",
"LabelHomePageSection3": "\u0411\u0430\u0441\u0442\u044b \u0431\u0435\u0442 3-\u0431\u04e9\u043b\u0456\u043c:",
"LabelHomePageSection4": "\u0411\u0430\u0441\u0442\u044b \u0431\u0435\u0442 4-\u0431\u04e9\u043b\u0456\u043c:",
- "OptionMyViewsButtons": "\u041c\u0435\u043d\u0456\u04a3 \u0430\u0441\u043f\u0435\u043a\u0442\u0442\u0435\u0440\u0456\u043c (\u0442\u04af\u0439\u043c\u0435\u0448\u0456\u043a\u0442\u0435\u0440)",
- "OptionMyViews": "\u041c\u0435\u043d\u0456\u04a3 \u0430\u0441\u043f\u0435\u043a\u0442\u0442\u0435\u0440\u0456\u043c",
- "OptionMyViewsSmall": "\u041c\u0435\u043d\u0456\u04a3 \u0430\u0441\u043f\u0435\u043a\u0442\u0442\u0435\u0440\u0456\u043c (\u044b\u049b\u0448\u0430\u043c)",
+ "OptionMyMediaButtons": "\u041c\u0435\u043d\u0456\u04a3 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0456\u043c (\u0442\u04af\u0439\u043c\u0435\u0448\u0456\u043a\u0442\u0435\u0440)",
+ "OptionMyMedia": "\u041c\u0435\u043d\u0456\u04a3 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0456\u043c",
+ "OptionMyMediaSmall": "\u041c\u0435\u043d\u0456\u04a3 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0456\u043c (\u044b\u049b\u0448\u0430\u043c)",
"OptionResumablemedia": "\u0416\u0430\u043b\u0493\u0430\u0441\u0442\u044b\u0440\u043c\u0430\u043b\u044b",
"OptionLatestMedia": "\u0415\u04a3 \u043a\u0435\u0439\u043d\u0433\u0456 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440",
"OptionLatestChannelMedia": "\u0410\u0440\u043d\u0430\u043b\u0430\u0440\u0434\u044b\u04a3 \u0435\u04a3 \u043a\u0435\u0439\u0456\u043d\u0433\u0456 \u0442\u0430\u0440\u043c\u0430\u049b\u0442\u0430\u0440\u044b",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "\u04d8\u0434\u0435\u043f\u043a\u0456",
"OptionCommunityMostWatchedSort": "\u0415\u04a3 \u043a\u04e9\u043f \u049b\u0430\u0440\u0430\u043b\u0493\u0430\u043d\u0434\u0430\u0440",
"TabNextUp": "\u041a\u0435\u0437\u0435\u043a\u0442\u0456",
+ "PlaceholderUsername": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b \u0430\u0442\u044b",
"HeaderBecomeProjectSupporter": "Emby \u0436\u0430\u049b\u0442\u0430\u0443\u0448\u044b\u0441\u044b \u0431\u043e\u043b\u044b\u04a3\u044b\u0437",
- "TextEnjoyBonusFeatures": "\u0421\u044b\u0439\u0430\u049b\u044b \u0435\u0440\u0435\u043a\u0448\u0435\u043b\u0456\u043a\u0442\u0435\u0440\u0434\u0456 \u0442\u0430\u043c\u0430\u0448\u0430\u043b\u0430\u043d\u044b\u04a3\u044b\u0437",
"MessageNoMovieSuggestionsAvailable": "\u0415\u0448\u049b\u0430\u043d\u0434\u0430\u0439 \u0444\u0438\u043b\u044c\u043c \u04b1\u0441\u044b\u043d\u044b\u0441\u0442\u0430\u0440\u044b \u0430\u0493\u044b\u043c\u0434\u0430 \u049b\u043e\u043b \u0436\u0435\u0442\u0456\u043c\u0434\u0456 \u0435\u043c\u0435\u0441. \u0424\u0438\u043b\u044c\u043c\u0434\u0435\u0440\u0434\u0456 \u049b\u0430\u0440\u0430\u0443\u0434\u044b \u0436\u04d9\u043d\u0435 \u0431\u0430\u0493\u0430\u043b\u0430\u0443\u0434\u044b \u0431\u0430\u0441\u0442\u0430\u04a3\u044b\u0437, \u0441\u043e\u043d\u0434\u0430 \u0430\u0440\u043d\u0430\u043b\u0493\u0430\u043d \u04b1\u0441\u044b\u043d\u044b\u0442\u0430\u0440\u044b\u04a3\u044b\u0437\u0434\u044b \u043a\u04e9\u0440\u0443 \u04af\u0448\u0456\u043d \u049b\u0430\u0439\u0442\u0430 \u043a\u0435\u043b\u0456\u04a3\u0456\u0437.",
"MessageNoCollectionsAvailable": "\u0416\u0438\u044b\u043d\u0442\u044b\u049b\u0442\u0430\u0440 \u0441\u0456\u0437\u0433\u0435 \u0424\u0438\u043b\u044c\u043c\u0434\u0435\u0440\u0434\u0456\u04a3, \u0422\u0435\u043b\u0435\u0445\u0438\u043a\u0430\u044f\u043b\u0430\u0440\u0434\u044b\u04a3, \u0410\u043b\u044c\u0431\u043e\u043c\u0434\u0430\u0440\u0434\u044b\u04a3, \u041a\u0456\u0442\u0430\u043f\u0442\u0430\u0440\u0434\u044b\u04a3, \u0436\u04d9\u043d\u0435 \u041e\u0439\u044b\u043d\u0434\u0430\u0440\u0434\u044b\u04a3 \u0434\u0435\u0440\u0431\u0435\u0441\u0442\u0435\u043d\u0434\u0456\u0440\u0456\u043b\u0433\u0435\u043d \u0442\u043e\u043f\u0442\u0430\u0443\u043b\u0430\u0440\u044b\u043c\u0435\u043d \u0442\u0430\u043c\u0430\u0448\u0430\u043b\u0430\u043d\u0443 \u04af\u0448\u0456\u043d \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0435\u0434\u0456. \u0416\u0438\u044b\u043d\u0442\u044b\u049b\u0442\u0430\u0440 \u0436\u0430\u0441\u0430\u0443\u044b\u043d \u0431\u0430\u0441\u0442\u0430\u0443 \u04af\u0448\u0456\u043d \"+\" \u0442\u04af\u0439\u043c\u0435\u0448\u0456\u0433\u0456\u043d \u0431\u0430\u0441\u044b\u04a3\u044b\u0437.",
"MessageNoPlaylistsAvailable": "\u041e\u0439\u043d\u0430\u0442\u0443 \u0442\u0456\u0437\u0456\u043c\u0434\u0435\u0440\u0456 \u0431\u0456\u0440 \u043a\u0435\u0437\u0434\u0435 \u043e\u0439\u043d\u0430\u0442\u0443 \u04af\u0448\u0456\u043d \u043c\u0430\u0437\u043c\u04b1\u043d \u0442\u0456\u0437\u0456\u043c\u0456\u043d \u0436\u0430\u0441\u0430\u0443\u0493\u0430 \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0435\u0434\u0456. \u041e\u0439\u043d\u0430\u0442\u0443 \u0442\u0456\u0437\u0456\u043c\u0434\u0435\u0440\u0433\u0435 \u0442\u0430\u0440\u043c\u0430\u049b\u0442\u0430\u0440\u0434\u044b \u04af\u0441\u0442\u0435\u0443 \u04af\u0448\u0456\u043d, \u0442\u0456\u043d\u0442\u0443\u0456\u0440\u0434\u0456\u04a3 \u043e\u04a3 \u0436\u0430\u049b \u0442\u04af\u0439\u043c\u0435\u0448\u0456\u0433\u0456\u043d \u0431\u0430\u0441\u044b\u04a3\u044b\u0437 \u043d\u0435\u043c\u0435\u0441\u0435 \u0442\u04af\u0440\u0442\u0456\u043f \u0436\u04d9\u043d\u0435 \u04b1\u0441\u0442\u0430\u043f \u0442\u04b1\u0440\u044b\u04a3\u044b\u0437, \u0441\u043e\u043d\u0434\u0430 \u041e\u0439\u043d\u0430\u0442\u0443 \u0442\u0456\u0437\u0456\u043c\u0456\u043d\u0435 \u04af\u0441\u0442\u0435\u0443 \u0434\u0435\u0433\u0435\u043d\u0434\u0456 \u0442\u0430\u04a3\u0434\u0430\u04a3\u044b\u0437.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "\u0422\u0430\u04a3\u0434\u0430\u0443\u043b\u044b\u043b\u0430\u0440",
"ViewTypeMovieGenres": "\u0416\u0430\u043d\u0440\u043b\u0430\u0440",
"ViewTypeMusicLatest": "\u0415\u04a3 \u043a\u0435\u0439\u0456\u043d\u0433\u0456",
+ "ViewTypeMusicPlaylists": "\u041e\u0439\u043d\u0430\u0442\u0443 \u0442\u0456\u0437\u0456\u043c\u0434\u0435\u0440\u0456",
"ViewTypeMusicAlbums": "\u0410\u043b\u044c\u0431\u043e\u043c\u0434\u0430\u0440",
"ViewTypeMusicAlbumArtists": "\u0410\u043b\u044c\u0431\u043e\u043c \u043e\u0440\u044b\u043d\u0434\u0430\u0443\u0448\u044b\u043b\u0430\u0440\u044b",
"HeaderOtherDisplaySettings": "\u0411\u0435\u0439\u043d\u0435\u043b\u0435\u0443 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440\u0456",
@@ -1378,13 +1383,39 @@
"LabelTagFilterAllowModeHelp": "\u0415\u0433\u0435\u0440 \u04b1\u0439\u0493\u0430\u0440\u044b\u043d\u0434\u044b \u0442\u0435\u0433\u0442\u0435\u0440 \u0442\u0435\u0440\u0435\u04a3 \u043a\u0456\u0440\u0456\u0441\u0442\u0456\u0440\u0456\u043b\u0433\u0435\u043d \u049b\u0430\u043b\u0442\u0430 \u049b\u04b1\u0440\u044b\u043b\u044b\u043c\u044b\u043d\u044b\u04a3 \u0431\u04e9\u043b\u0456\u0433\u0456 \u0431\u043e\u043b\u0441\u0430, \u043e\u043d\u0434\u0430 \u0442\u0435\u0433\u0442\u0435\u0440\u043c\u0435\u043d \u0431\u0435\u043b\u0433\u0456\u043b\u0435\u043d\u0433\u0435\u043d \u043c\u0430\u0437\u043c\u04b1\u043d\u0493\u0430, \u0441\u043e\u043d\u0434\u0430\u0439-\u0430\u049b \u0431\u0435\u043b\u0433\u0456\u043b\u0435\u043d\u0433\u0435\u043d \u0442\u0435\u043a\u0442\u0456\u043a \u049b\u0430\u043b\u0442\u0430\u043b\u0430\u0440 \u0431\u043e\u043b\u0443\u044b \u0442\u0430\u043b\u0430\u043f \u0435\u0442\u0456\u043b\u0435\u0434\u0456.",
"HeaderThisUserIsCurrentlyDisabled": "\u041e\u0441\u044b \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b \u049b\u0430\u0437\u0456\u0440\u0433\u0456 \u043a\u0435\u0437\u0434\u0435 \u0430\u0436\u044b\u0440\u0430\u0442\u044b\u043b\u0493\u0430\u043d",
"MessageReenableUser": "\u049a\u0430\u0439\u0442\u0430 \u049b\u043e\u0441\u0443 \u04af\u0448\u0456\u043d \u0442\u04e9\u043c\u0435\u043d\u0434\u0435 \u049b\u0430\u0440\u0430\u04a3\u044b\u0437",
- "LabelEnableInternetMetadataForTvPrograms": "\u041c\u044b\u043d\u0430\u0443 \u04af\u0448\u0456\u043d \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443",
+ "LabelEnableInternetMetadataForTvPrograms": "\u041c\u044b\u043d\u0430\u0443 \u04af\u0448\u0456\u043d \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0442\u0435\u043d \u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443",
"OptionTVMovies": "\u0422\u0414-\u0444\u0438\u043b\u044c\u043c\u0434\u0435\u0440",
"HeaderUpcomingMovies": "\u041a\u04af\u0442\u0456\u043b\u0433\u0435\u043d \u0444\u0438\u043b\u044c\u043c\u0434\u0435\u0440",
+ "HeaderUpcomingSports": "\u041a\u04af\u0442\u0456\u043b\u0433\u0435\u043d \u0441\u043f\u043e\u0440\u0442",
"HeaderUpcomingPrograms": "\u041a\u04af\u0442\u0456\u043b\u0433\u0435\u043d \u0431\u0435\u0440\u043b\u0456\u043c\u0434\u0435\u0440",
"ButtonMoreItems": "\u041a\u04e9\u0431\u0456\u0440\u0435\u043a...",
"LabelShowLibraryTileNames": "\u0422\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430 \u0442\u0430\u049b\u0442\u0430\u0439\u0448\u0430\u043b\u0430\u0440\u044b\u043d\u044b\u04a3 \u0430\u0442\u0430\u0443\u043b\u0430\u0440\u044b\u043d \u043a\u04e9\u0440\u0441\u0435\u0442\u0443",
"LabelShowLibraryTileNamesHelp": "\u0411\u0430\u0441\u0442\u044b \u0431\u0435\u0442\u0442\u0435 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430 \u0442\u0430\u049b\u0442\u0430\u0439\u0448\u0430\u043b\u0430\u0440\u044b \u0430\u0441\u0442\u044b\u043d\u0434\u0430 \u0436\u0430\u0437\u0443\u043b\u0430\u0440 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u0435 \u043c\u0435 \u0435\u043a\u0435\u043d\u0456 \u0430\u043d\u044b\u049b\u0442\u0430\u043b\u0430\u0434\u044b.",
"OptionEnableTranscodingThrottle": "\u0420\u0435\u0442\u0442\u0435\u0443\u0434\u0456 \u049b\u043e\u0441\u0443",
- "OptionEnableTranscodingThrottleHelp": "\u041e\u0439\u043d\u0430\u0442\u0443 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0434\u0456\u04a3 \u043e\u0440\u0442\u0430\u043b\u044b\u049b \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u044b\u043d \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u044b\u043d \u0430\u0437\u0430\u0439\u0442\u0443 \u04af\u0448\u0456\u043d \u0440\u0435\u0442\u0442\u0435\u0443 \u049b\u0430\u0439\u0442\u0430 \u043a\u043e\u0434\u0442\u0430\u0443 \u049b\u0430\u0440\u049b\u044b\u043d\u044b\u043d \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0442\u04af\u0440\u0434\u0435 \u043b\u0430\u0439\u044b\u049b\u0442\u0430\u0439\u0434\u044b."
+ "OptionEnableTranscodingThrottleHelp": "\u041e\u0439\u043d\u0430\u0442\u0443 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0434\u0456\u04a3 \u043e\u0440\u0442\u0430\u043b\u044b\u049b \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u044b\u043d \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u044b\u043d \u0430\u0437\u0430\u0439\u0442\u0443 \u04af\u0448\u0456\u043d \u0440\u0435\u0442\u0442\u0435\u0443 \u049b\u0430\u0439\u0442\u0430 \u043a\u043e\u0434\u0442\u0430\u0443 \u049b\u0430\u0440\u049b\u044b\u043d\u044b\u043d \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0442\u04af\u0440\u0434\u0435 \u043b\u0430\u0439\u044b\u049b\u0442\u0430\u0439\u0434\u044b.",
+ "LabelUploadSpeedLimit": "\u0416\u04af\u043a\u0442\u0435\u043f \u0431\u0435\u0440\u0443 \u0436\u044b\u043b\u0434\u0430\u043c\u0434\u044b\u0493\u044b\u043d\u044b\u04a3 \u0448\u0435\u0433\u0456, \u041c\u0431\u0438\u0442\/\u0441",
+ "OptionAllowSyncTranscoding": "\u049a\u0430\u0439\u0442\u0430 \u043a\u043e\u0434\u0442\u0430\u0443\u0493\u0430 \u0442\u0430\u043b\u0430\u0431\u044b \u0431\u0430\u0440 \u04af\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u04af\u0448\u0456\u043d \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0443",
+ "HeaderPlayback": "\u0422\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u043e\u0439\u043d\u0430\u0442\u0443",
+ "OptionAllowAudioPlaybackTranscoding": "\u049a\u0430\u0439\u0442\u0430 \u043a\u043e\u0434\u0442\u0430\u0443\u0493\u0430 \u0442\u0430\u043b\u0430\u0431\u044b \u0431\u0430\u0440 \u0434\u044b\u0431\u044b\u0441 \u043e\u0439\u043d\u0430\u0442\u0443 \u04af\u0448\u0456\u043d \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0443",
+ "OptionAllowVideoPlaybackTranscoding": "\u049a\u0430\u0439\u0442\u0430 \u043a\u043e\u0434\u0442\u0430\u0443\u0493\u0430 \u0442\u0430\u043b\u0430\u0431\u044b \u0431\u0430\u0440 \u0431\u0435\u0439\u043d\u0435 \u043e\u0439\u043d\u0430\u0442\u0443 \u04af\u0448\u0456\u043d \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0443",
+ "OptionAllowMediaPlaybackTranscodingHelp": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043b\u0430\u0440 \u04e9\u0437\u0434\u0435\u0440\u0456\u043d\u0456\u04a3 \u0441\u0430\u044f\u0441\u0430\u0442\u0442\u0430\u0440\u044b\u043d\u0430 \u043d\u0435\u0433\u0456\u0437\u0434\u0435\u043b\u0433\u0435\u043d \u043e\u0439\u043d\u0430\u0442\u044b\u043b\u043c\u0430\u0439\u0442\u044b\u043d \u043c\u0430\u0437\u043c\u04b1\u043d \u0431\u043e\u043b\u0493\u0430\u043d\u0434\u0430\u0493\u044b \u049b\u0430\u0442\u0435 \u0442\u0443\u0440\u0430\u043b\u044b \u043e\u04a3\u0430\u0439 \u0445\u0430\u0431\u0430\u0440\u043b\u0430\u0440\u0434\u044b \u0430\u043b\u0430\u0434\u044b.",
+ "TabStreaming": "\u0410\u0493\u044b\u043d\u043c\u0435\u043d \u0442\u0430\u0441\u044b\u043c\u0430\u043b\u0434\u0430\u0443",
+ "LabelRemoteClientBitrateLimit": "\u0410\u043b\u044b\u0441\u0442\u0430\u0493\u044b \u043a\u043b\u0438\u0435\u043d\u0442\u0442\u0435\u0440 \u049b\u0430\u0440\u049b\u044b\u043d\u044b\u043d\u044b\u04a3 \u0448\u0435\u0433\u0456, \u041c\u0431\u0438\u0442\/\u0441",
+ "LabelRemoteClientBitrateLimitHelp": "\u041c\u0456\u043d\u0434\u0435\u0442\u0442\u0456 \u0435\u043c\u0435\u0441 \u0431\u0430\u0440\u043b\u044b\u049b \u0430\u043b\u044b\u0441\u0442\u0430\u0493\u044b \u043a\u043b\u0438\u0435\u043d\u0442\u0442\u0435\u0440 \u04af\u0448\u0456\u043d \u049b\u0430\u0440\u049b\u044b\u043d \u0448\u0435\u0433\u0456. \u0411\u04b1\u043b \u049b\u043e\u0441\u044b\u043b\u044b\u043c\u044b\u04a3\u044b\u0437\u0434\u044b\u04a3 \u04e9\u04a3\u0434\u0435\u0443 \u043c\u04af\u043c\u043a\u0456\u043d\u0434\u0456\u0433\u0456\u043d\u0435 \u049b\u0430\u0440\u0430\u0493\u0430\u043d\u0434\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0442\u0435\u0440\u0434\u0456\u04a3 \u0436\u043e\u0493\u0430\u0440\u044b\u043b\u0430\u0443 \u049b\u0430\u0440\u049b\u044b\u043d \u0441\u0430\u0443\u0430\u043b\u0434\u0430\u0440\u044b\u043d\u0430 \u0442\u044b\u0439\u044b\u043c \u0441\u0430\u043b\u0443 \u04af\u0448\u0456\u043d \u043f\u0430\u0439\u0434\u0430\u043b\u044b \u0431\u043e\u043b\u044b\u043f \u0442\u0430\u0431\u044b\u043b\u0430\u0434\u044b.",
+ "LabelConversionCpuCoreLimit": "\u041f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u043b\u044b\u049b \u04e9\u0437\u0435\u043a\u0442\u0435\u0440 \u0448\u0435\u0433\u0456:",
+ "LabelConversionCpuCoreLimitHelp": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443\u043b\u0456\u043a \u0442\u04af\u0440\u043b\u0435\u043d\u0434\u0456\u0440\u0443 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u049b\u043e\u043b\u0434\u0430\u043d\u044b\u043b\u0430\u0442\u044b\u043d \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u043b\u044b\u049b \u04e9\u0437\u0435\u043a\u0442\u0435\u0440\u0434\u0456\u04a3 \u0441\u0430\u043d\u044b\u043d \u0448\u0435\u043a\u0442\u0435\u0443.",
+ "OptionEnableFullSpeedConversion": "\u0422\u04af\u0440\u043b\u0435\u043d\u0434\u0456\u0440\u0443\u0434\u0456\u04a3 \u0442\u043e\u043b\u044b\u049b \u0436\u044b\u043b\u0434\u0430\u043c\u043b\u044b\u0493\u044b\u043d \u049b\u043e\u0441\u0443",
+ "OptionEnableFullSpeedConversionHelp": "\u0420\u0435\u0441\u0443\u0440\u0441\u0442\u0430\u0440 \u0442\u04b1\u0442\u044b\u043d\u0443\u0434\u044b \u0431\u0430\u0440\u044b\u043d\u0448\u0430 \u0430\u0437\u0430\u0439\u0442\u0443 \u04af\u0448\u0456\u043d \u04af\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443\u043b\u0456\u043a \u0442\u04af\u0440\u043b\u0435\u043d\u0434\u0456\u0440\u0443 \u04d9\u0434\u0435\u043f\u043a\u0456\u0434\u0435 \u0442\u04e9\u043c\u0435\u043d \u0436\u044b\u043b\u0434\u0430\u043c\u0434\u044b\u049b\u043f\u0435\u043d \u043e\u0440\u044b\u043d\u0434\u0430\u043b\u0430\u0434\u044b.",
+ "HeaderPlaylists": "\u041e\u0439\u043d\u0430\u0442\u0443 \u0442\u0456\u0437\u0456\u043c\u0434\u0435\u0440",
+ "HeaderSelectDate": "\u041a\u04af\u043d\u0434\u0456 \u0442\u0430\u04a3\u0434\u0430\u0443",
+ "HeaderWelcomeExclamation": "\u049a\u043e\u0448 \u043a\u0435\u043b\u0434\u0456\u04a3\u0456\u0437!",
+ "HeaderMyPreferences": "\u041c\u0435\u043d\u0456\u04a3 \u0442\u0435\u04a3\u0448\u0435\u043b\u0456\u043c\u0434\u0435\u0440\u0456\u043c",
+ "ButtonMyPreferencesWelcomeYes": "\u0418\u04d9, \u043c\u0435\u043d \u0435\u043d\u0434\u0456 \u043c\u0435\u043d\u0456\u04a3 \u0442\u0435\u04a3\u0448\u0435\u043b\u0456\u043c\u0434\u0435\u0440\u0456\u043c\u0434\u0456 \u043e\u0440\u043d\u0430\u0442\u0443\u044b\u043d \u049b\u0430\u043b\u0430\u0439\u043c\u044b\u043d.",
+ "ButtonMyPreferencesWelcomeNo": "\u0416\u043e\u049b, \u0440\u0430\u0445\u043c\u0435\u0442, \u043c\u0435\u043d \u043e\u043d\u044b \u043a\u0435\u0439\u0456\u043d\u0456\u0440\u0435\u043a \u0456\u0441\u0442\u0435\u0439\u043c\u0456\u043d.",
+ "MyPreferencesWelcomeMessage1": "\u0421\u0456\u0437 \u049b\u0430\u043b\u0430\u0439 \u0442\u0430\u043c\u0430\u0448\u0430\u043b\u0430\u0439\u0442\u044b\u043d\u044b\u043d \u043e\u0439\u043b\u0430\u0441\u0442\u044b\u0440\u044b\u043f \u0441\u0456\u0437\u0434\u0456\u04a3 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430\u04a3\u044b\u0437\u0434\u044b \u043a\u04e9\u0440\u0441\u0435\u0442\u0442\u0456\u043c\u0456\u0437. \u0422\u0435\u04a3\u0448\u0435\u043b\u0456\u043c\u0434\u0435\u0440\u0456\u04a3\u0456\u0437\u0434\u0456 \u0440\u0435\u0442\u0442\u0435\u0443 \u0430\u0440\u049b\u044b\u043b\u044b \u043c\u0430\u0437\u043c\u04b1\u043d \u0431\u0435\u0437\u0435\u043d\u0434\u0456\u0440\u0443\u0456 \u043c\u0435\u043d \u0442\u043e\u043f\u0442\u0430\u0441\u0442\u044b\u0440\u0443\u044b \u043a\u0435\u0437 \u043a\u0435\u043b\u0433\u0435\u043d \u0443\u0430\u049b\u044b\u0442\u0442\u0430 \u04e9\u0437\u0433\u0435\u0440\u0442\u0456\u043b\u0443\u0456 \u043c\u04af\u043c\u043a\u0456\u043d. \u0421\u0456\u0437\u0434\u0456\u04a3 \u0442\u0435\u04a3\u0448\u0435\u043b\u0456\u043c\u0434\u0435\u0440\u0456\u04a3\u0456\u0437 \u0431\u0430\u0440\u043b\u044b\u049b Emby \u049b\u043e\u043b\u0434\u0430\u043d\u0431\u0430\u043b\u0430\u0440\u044b\u043d\u0434\u0430 \u049b\u043e\u043b\u0434\u0430\u043d\u044b\u043b\u0430\u0434\u044b.",
+ "MyPreferencesWelcomeMessage2": "\u0421\u0456\u0437 \u0435\u043d\u0434\u0456 \u04e9\u0437 \u0442\u0435\u04a3\u0448\u0435\u043b\u0456\u043c\u0434\u0435\u0440\u0456\u043d\u0456\u0437\u0434\u0456 \u043e\u0440\u043d\u0430\u0442\u0443\u044b\u043d \u049b\u0430\u043b\u0430\u0439\u0441\u044b\u0437 \u0431\u0430?",
+ "ToAccessPreferencesHelp": "\u0422\u0435\u04a3\u0448\u0435\u043b\u0456\u043c\u0434\u0435\u0440\u0456\u04a3\u0456\u0437\u0433\u0435 \u043a\u0435\u0439\u0456\u043d\u0456\u0440\u0435\u043a \u049b\u0430\u0442\u044b\u043d\u0430\u0443 \u04af\u0448\u0456\u043d, \u04af\u0441\u0442\u0456\u04a3\u0433\u0456 \u0434\u0435\u0440\u0435\u043a\u0442\u0435\u043c\u0435\u0441\u0456 \u043e\u04a3 \u0436\u0430\u0493\u044b\u043d\u0434\u0430\u0493\u044b \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b \u0431\u0435\u043b\u0433\u0456\u0448\u0435\u0441\u0456\u043d \u0431\u0430\u0441\u044b\u04a3\u044b\u0437 \u0436\u04d9\u043d\u0435 \u041c\u0435\u043d\u0456\u04a3 \u0442\u0435\u04a3\u0448\u0435\u043b\u0456\u043c\u0434\u0435\u0440\u0456\u043c\u0434\u0456 \u0442\u0430\u04a3\u0434\u0430\u04a3\u044b\u0437.",
+ "HeaderViewStyles": "\u0410\u0441\u043f\u0435\u043a\u0442 \u043c\u04d9\u043d\u0435\u0440\u043b\u0435\u0440\u0456",
+ "LabelSelectViewStyles": "\u041c\u044b\u043d\u0430\u0443 \u04af\u0448\u0456\u043d \u043c\u0430\u0437\u043c\u04b1\u043d\u0434\u044b \u043a\u04e9\u0440\u043c\u0435\u043b\u0435\u0440\u0434\u0456 \u049b\u043e\u0441\u0443:",
+ "LabelSelectViewStylesHelp": "\u049a\u043e\u0441\u044b\u043b\u0441\u0430, \u043c\u04b1\u043d\u0434\u0430\u0439 \u04b0\u0441\u044b\u043d\u044b\u0441\u0442\u0430\u0440, \u0415\u04a3 \u043a\u0435\u0439\u0456\u043d\u0433\u0456, \u0416\u0430\u043d\u0440\u043b\u0430\u0440\u0434\u044b \u0436\u04d9\u043d\u0435 \u0431\u0430\u0441\u049b\u0430 \u0434\u0430 \u0441\u0430\u043d\u0430\u0442\u0442\u0430\u0440\u044b\u043d \u04b1\u0441\u044b\u043d\u0443 \u04af\u0448\u0456\u043d \u0430\u0441\u043f\u0435\u043a\u0442\u0442\u0435\u0440 \u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u0430\u0440\u049b\u044b\u043b\u044b \u049b\u04b1\u0440\u044b\u043b\u0430\u0434\u044b. \u0410\u0436\u044b\u0440\u0430\u0442\u044b\u043b\u0441\u0430, \u043e\u043b\u0430\u0440 \u049b\u0430\u0440\u0430\u043f\u0430\u0439\u044b\u043c \u049b\u0430\u043b\u0442\u0430\u043b\u0430\u0440 \u0430\u0440\u049b\u044b\u043b\u044b \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u0435\u0434\u0456."
} \ 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 36003bc3f..aecd7bb81 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/ko.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/ko.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Add User",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
"LabelPinCode": "Pin code:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "Ok",
"ButtonCancel": "Cancel",
"ButtonExit": "Exit",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Nothing here.",
"MessagePleaseEnsureInternetMetadata": "Please ensure downloading of internet metadata is enabled.",
"TabSuggested": "Suggested",
+ "TabSuggestions": "Suggestions",
"TabLatest": "Latest",
"TabUpcoming": "Upcoming",
"TabShows": "Shows",
@@ -401,9 +404,10 @@
"ButtonRefresh": "Refresh",
"ButtonAdvancedRefresh": "Advanced Refresh",
"OptionPriority": "Priority",
- "OptionRecordOnAllChannels": "Record program on all channels",
- "OptionRecordAnytime": "Record program at any time",
+ "OptionRecordOnAllChannels": "Record on all channels",
+ "OptionRecordAnytime": "Record at any time",
"OptionRecordOnlyNewEpisodes": "Record only new episodes",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "Days",
"HeaderActiveRecordings": "Active Recordings",
"HeaderLatestRecordings": "Latest Recordings",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "Web socket port number:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Home page section 2:",
"LabelHomePageSection3": "Home page section 3:",
"LabelHomePageSection4": "Home page section 4:",
- "OptionMyViewsButtons": "My views (buttons)",
- "OptionMyViews": "My views",
- "OptionMyViewsSmall": "My views (small)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Resume",
"OptionLatestMedia": "Latest media",
"OptionLatestChannelMedia": "Latest channel items",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Default",
"OptionCommunityMostWatchedSort": "Most Watched",
"TabNextUp": "Next Up",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
"MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favorites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Display Settings",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "More...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ 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 12081cc5a..c7dda67e6 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/ms.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/ms.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Add User",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
"LabelPinCode": "Pin code:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "Ok",
"ButtonCancel": "Cancel",
"ButtonExit": "Exit",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Nothing here.",
"MessagePleaseEnsureInternetMetadata": "Please ensure downloading of internet metadata is enabled.",
"TabSuggested": "Suggested",
+ "TabSuggestions": "Suggestions",
"TabLatest": "Latest",
"TabUpcoming": "Upcoming",
"TabShows": "Shows",
@@ -401,9 +404,10 @@
"ButtonRefresh": "Refresh",
"ButtonAdvancedRefresh": "Advanced Refresh",
"OptionPriority": "Priority",
- "OptionRecordOnAllChannels": "Record program on all channels",
- "OptionRecordAnytime": "Record program at any time",
+ "OptionRecordOnAllChannels": "Record on all channels",
+ "OptionRecordAnytime": "Record at any time",
"OptionRecordOnlyNewEpisodes": "Record only new episodes",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "Days",
"HeaderActiveRecordings": "Active Recordings",
"HeaderLatestRecordings": "Latest Recordings",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "Web socket port number:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Home page section 2:",
"LabelHomePageSection3": "Home page section 3:",
"LabelHomePageSection4": "Home page section 4:",
- "OptionMyViewsButtons": "My views (buttons)",
- "OptionMyViews": "My views",
- "OptionMyViewsSmall": "My views (small)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Resume",
"OptionLatestMedia": "Latest media",
"OptionLatestChannelMedia": "Latest channel items",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Default",
"OptionCommunityMostWatchedSort": "Most Watched",
"TabNextUp": "Next Up",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
"MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favorites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Display Settings",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "More...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ 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 cce3ec647..46a82b395 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/nb.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/nb.json
@@ -7,7 +7,7 @@
"LabelApiDocumentation": "API-dokumentasjon",
"LabelDeveloperResources": "Ressurser for Utviklere",
"LabelBrowseLibrary": "Browse biblioteket",
- "LabelConfigureServer": "Configure Emby",
+ "LabelConfigureServer": "Konfigurer Emby",
"LabelOpenLibraryViewer": "\u00c5pne Biblioteket",
"LabelRestartServer": "Restart serveren",
"LabelShowLogWindow": "Se logg-vinduet",
@@ -15,18 +15,18 @@
"LabelFinish": "Ferdig",
"LabelNext": "Neste",
"LabelYoureDone": "Ferdig!",
- "WelcomeToProject": "Welcome to Emby!",
+ "WelcomeToProject": "Velkommen til Emby",
"ThisWizardWillGuideYou": "Denne wizarden vil guide deg gjennom server-konfigurasjonen. For \u00e5 begynne, vennligst velg spr\u00e5k.",
"TellUsAboutYourself": "Fortell om deg selv",
"ButtonQuickStartGuide": "Hurtigstartveiledning",
"LabelYourFirstName": "Ditt fornavn",
"MoreUsersCanBeAddedLater": "Du kan legge til flere brukere senere via Dashbord",
- "UserProfilesIntro": "Emby includes built-in support for user profiles, enabling each user to have their own display settings, playstate and parental controls.",
+ "UserProfilesIntro": "Emby har innebygd st\u00f8tte for brukerprofiler, slik at hver bruker har sine egne skjerminnstillinger, playstation og foreldrekontroll.",
"LabelWindowsService": "Windows Service",
"AWindowsServiceHasBeenInstalled": "Windows Service har blitt installert",
- "WindowsServiceIntro1": "Emby Server normally runs as a desktop application with a tray icon, but if you prefer to run it as a background service, it can be started from the windows services control panel instead.",
+ "WindowsServiceIntro1": "Emby Server normalt kj\u00f8rer som en desktop applikasjon, men hvis du foretrekker \u00e5 kj\u00f8re det som en bakgrunnstjeneste, kan det i stedet startes fra Windows Services i kontrollpanelet.",
"WindowsServiceIntro2": "Hvis du bruker Windows, v\u00e6r oppmerksom p\u00e5 at det ikke kan kj\u00f8res samtidig som ikonet, slik at du trenger \u00e5 g\u00e5 ut av \"trayen\" for \u00e5 kj\u00f8re tjenesten. Tjenesten m\u00e5 ogs\u00e5 konfigureres med administratorrettigheter via kontrollpanelet. V\u00e6r oppmerksom p\u00e5 at p\u00e5 denne tiden tjenesten ikke er i stand til selv-oppdatering, s\u00e5 nye versjoner vil kreve manuell interaksjon.",
- "WizardCompleted": "That's all we need for now. Emby has begun collecting information about your media library. Check out some of our apps, and then click <b>Finish<\/b> to view the <b>Server Dashboard<\/b>.",
+ "WizardCompleted": "Det er alt vi trenger for n\u00e5. Emby har begynt \u00e5 samle informasjon om mediebiblioteket. Sjekk ut noen av v\u00e5re programmer, og klikk deretter <b> Fullf\u00f8r <\/b> for \u00e5 se <b> Server Dashboard<\/b>.",
"LabelConfigureSettings": "Konfigurer innstillinger",
"LabelEnableVideoImageExtraction": "Aktiv\u00e9r uthenting av stillbilder fra video",
"VideoImageExtractionHelp": "For videoer som ikke allerede har bilder, og som vi ikke klarer \u00e5 finne internettbilder for. Dette gj\u00f8r at det f\u00f8rste biblioteks\u00f8ket tar noe lenger tid, men vil resultere i en mer tiltalende presentasjon.",
@@ -34,7 +34,7 @@
"LabelChapterImageExtractionForMoviesHelp": "Uthenting av kapittelbilder gj\u00f8r klientene i stand til \u00e5 vise grafiske menyer for valg av scene. Prosessen kan v\u00e6re treg, CPU-intensiv og kan kreve sv\u00e6rt mange gigabytes lagringsplass. Dette kj\u00f8res som en nattlig oppgave, og kan konfigureres under Planlagte Aktiviteter. Det anbefales ikke \u00e5 kj\u00f8re denne jobben n\u00e5r serveren brukes til annet.",
"LabelEnableAutomaticPortMapping": "Sl\u00e5 p\u00e5 automatisk port-mapping",
"LabelEnableAutomaticPortMappingHelp": "UPnP tillater automatisert router-konfigurasjon for enkel ekstern tilgang. Denne funksjonen st\u00f8ttes ikke av alle routere.",
- "HeaderTermsOfService": "Emby Terms of Service",
+ "HeaderTermsOfService": "Emby vilk\u00e5r for bruk.",
"MessagePleaseAcceptTermsOfService": "Vennligst aksepter v\u00e5re servicevilk\u00e5r og personvernpolicy f\u00f8r du fortsetter.",
"OptionIAcceptTermsOfService": "Jeg aksepterer servicevilk\u00e5rene",
"ButtonPrivacyPolicy": "Personvernpolicy",
@@ -47,26 +47,28 @@
"LabelDashboardSourcePathHelp": "Hvis serveren kj\u00f8rer fra kildekode, angi sti til mappe for dashboard-ui. Alle filer for webklienten kommer fra denne mappen.",
"ButtonConvertMedia": "Konverter media",
"ButtonOrganize": "Organiser",
- "LinkedToEmbyConnect": "Linked to Emby Connect",
+ "LinkedToEmbyConnect": "Knyttet til Emby Connect.",
"HeaderSupporterBenefits": "Supporter Benefits",
- "HeaderAddUser": "Add User",
+ "HeaderAddUser": "Ny bruker",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
- "LabelPinCode": "Pin code:",
+ "LabelPinCode": "Pin kode:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Synk.",
"ButtonOk": "Ok",
"ButtonCancel": "Avbryt",
- "ButtonExit": "Exit",
+ "ButtonExit": "Avslutt",
"ButtonNew": "Ny",
"HeaderTV": "TV",
"HeaderAudio": "Lyd",
"HeaderVideo": "Video",
"HeaderPaths": "Stier",
"CategorySync": "Synk",
- "TabPlaylist": "Playlist",
+ "TabPlaylist": "Spilleliste",
"HeaderEasyPinCode": "Enkel PIN-kode",
"HeaderGrownupsOnly": "Grown-ups Only!",
- "DividerOr": "-- or --",
- "HeaderInstalledServices": "Installed Services",
- "HeaderAvailableServices": "Available Services",
+ "DividerOr": "-- eller --",
+ "HeaderInstalledServices": "Installerte programtillegg",
+ "HeaderAvailableServices": "Tilgjengelige tjenester",
"MessageNoServicesInstalled": "No services are currently installed.",
"HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
"KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
@@ -107,7 +109,7 @@
"ReferToMediaLibraryWiki": "Se i wik for media-biblioteket.",
"LabelCountry": "Land:",
"LabelLanguage": "Spr\u00e5k:",
- "LabelTimeLimitHours": "Time limit (hours):",
+ "LabelTimeLimitHours": "Tidsbegrensning (timer):",
"ButtonJoinTheDevelopmentTeam": "Bli med i utvikler-teamet",
"HeaderPreferredMetadataLanguage": "Foretrukket spr\u00e5k for metadata",
"LabelSaveLocalMetadata": "Lagre cover og metadata i medie-mappene",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Ingeting her.",
"MessagePleaseEnsureInternetMetadata": "P\u00e5se at nedlasting av internet-metadata er sl\u00e5tt p\u00e5.",
"TabSuggested": "Forslag",
+ "TabSuggestions": "Suggestions",
"TabLatest": "Siste",
"TabUpcoming": "Kommer",
"TabShows": "Show",
@@ -292,7 +295,7 @@
"CheckoutKnowledgeBase": "Check out our knowledge base to help you get the most out of Emby.",
"SearchKnowledgeBase": "S\u00f8k kunnskapsbasen",
"VisitTheCommunity": "Bes\u00f8k oss",
- "VisitProjectWebsite": "Visit the Emby Web Site",
+ "VisitProjectWebsite": "Bes\u00f8k Emby Media",
"VisitProjectWebsiteLong": "Visit the Emby Web site to catch the latest news and keep up with the developer blog.",
"OptionHideUser": "Skjul brukere fra logginn-skjermen",
"OptionHideUserFromLoginHelp": "Praktisk for private eller skjulte administratorer. Brukeren vil m\u00e5tte logge inn manuelt ved \u00e5 skrive inn brukernavn og passord.",
@@ -404,6 +407,7 @@
"OptionRecordOnAllChannels": "Ta opptak p\u00e5 alle kanaler",
"OptionRecordAnytime": "Ta opptak n\u00e5r som helst",
"OptionRecordOnlyNewEpisodes": "Ta opptak kun av nye episoder",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "Dager",
"HeaderActiveRecordings": "Aktive opptak",
"HeaderLatestRecordings": "Siste opptak",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Offentlig HTTPS port:",
"LabelPublicHttpsPortHelp": "Den offentlige porten som den lokale porten kobles til.",
"LabelEnableHttps": "Oppgi HTTPS som ekstern adresse",
- "LabelEnableHttpsHelp": "Hvis denne er aktivert vil serveren oppgi en HTTPS URL som sin eksterne adresse. Dette kan \u00f8delegge for klienter som enda ikke st\u00f8tter HTTPS.",
+ "LabelEnableHttpsHelp": "Hvis denne er aktivert vil serveren oppgi en HTTPS URL som sin eksterne adresse. Dette kan \u00f8delegge for klienter som enda ikke st\u00f8tter HTTPS",
"LabelHttpsPort": "Lokal HTTPS port:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "Web socket portnummer:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Hjemme side seksjon 2:",
"LabelHomePageSection3": "Hjemme side seksjon 3:",
"LabelHomePageSection4": "Hjemme side seksjon 4:",
- "OptionMyViewsButtons": "Mitt syn (knapper)",
- "OptionMyViews": "Mitt syn",
- "OptionMyViewsSmall": "Mitt Syn (liten)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Fortsette",
"OptionLatestMedia": "Siste media",
"OptionLatestChannelMedia": "Siste kanal elementer",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Standard",
"OptionCommunityMostWatchedSort": "Mest Sett",
"TabNextUp": "Neste",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"MessageNoMovieSuggestionsAvailable": "Ingen film forslag er forel\u00f8pig tilgjengelig. Start med \u00e5 se og ranger filmer. Kom deretter tilbake for \u00e5 f\u00e5 forslag p\u00e5 anbefalinger.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
"MessageNoPlaylistsAvailable": "Spillelister tillater deg \u00e5 lage lister over innhold til \u00e5 spille etter hverandre p\u00e5 en gang. For \u00e5 legge til elementer i spillelister, h\u00f8yreklikk eller trykk og hold, og velg Legg til i spilleliste.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favoritter",
"ViewTypeMovieGenres": "Sjangere",
"ViewTypeMusicLatest": "Siste",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albumer",
"ViewTypeMusicAlbumArtists": "Album artister",
"HeaderOtherDisplaySettings": "Visnings Innstillinger",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "Mer...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ 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 ded3ae100..36fe64f55 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/nl.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/nl.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Gebruiker Toevoegen",
"LabelAddConnectSupporterHelp": "Om een \u200b\u200bgebruiker toe te voegen die niet in de lijst voorkomt, moet je eerst hun account koppelen aan Emby Connect uit hun gebruikersprofiel pagina.",
"LabelPinCode": "Pincode:",
+ "OptionHideWatchedContentFromLatestMedia": "Verberg bekeken inhoud van recent toegevoegd",
+ "HeaderSync": "Sync",
"ButtonOk": "Ok",
"ButtonCancel": "Annuleren",
"ButtonExit": "Afsluiten",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Lijst is leeg.",
"MessagePleaseEnsureInternetMetadata": "Zorg ervoor dat het downloaden van metadata van het internet is ingeschakeld.",
"TabSuggested": "Aanbevolen",
+ "TabSuggestions": "Suggesties",
"TabLatest": "Nieuw",
"TabUpcoming": "Binnenkort op TV",
"TabShows": "Series",
@@ -404,6 +407,7 @@
"OptionRecordOnAllChannels": "Programma van alle kanalen opnemen",
"OptionRecordAnytime": "Programma elke keer opnemen",
"OptionRecordOnlyNewEpisodes": "Alleen nieuwe afleveringen opnemen",
+ "HeaderRepeatingOptions": "Herhaling opties",
"HeaderDays": "Dagen",
"HeaderActiveRecordings": "Actieve Opnames",
"HeaderLatestRecordings": "Nieuwe Opnames",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Startpagina sectie 2:",
"LabelHomePageSection3": "Startpagina sectie 3:",
"LabelHomePageSection4": "Startpagina sectie 4:",
- "OptionMyViewsButtons": "Mijn overzichten (knoppen)",
- "OptionMyViews": "Mijn overzichten",
- "OptionMyViewsSmall": "Mijn overzichten (klein)",
+ "OptionMyMediaButtons": "Mijn media (knoppen)",
+ "OptionMyMedia": "Mijn media",
+ "OptionMyMediaSmall": "Mijn media (klein)",
"OptionResumablemedia": "Hervatten",
"OptionLatestMedia": "Nieuwste media",
"OptionLatestChannelMedia": "Nieuwste kanaal items",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Standaard",
"OptionCommunityMostWatchedSort": "Meest bekeken",
"TabNextUp": "Volgend",
+ "PlaceholderUsername": "Gebruikersnaam",
"HeaderBecomeProjectSupporter": "Wordt Emby Supporter",
- "TextEnjoyBonusFeatures": "Geniet van Bonus Features",
"MessageNoMovieSuggestionsAvailable": "Er zijn momenteel geen film suggesties beschikbaar. Begin met het bekijken en waardeer uw films, kom daarna terug om uw aanbevelingen te bekijken.",
"MessageNoCollectionsAvailable": "Collecties maken het u mogelijk om Films, Series, Albums, Boeken en Games te groeperen. Klik op de + knop om Collecties aan te maken.",
"MessageNoPlaylistsAvailable": "Met afspeellijsten kunt u een lijst maken waarvan de items achter elkaar afgespeeld worden. Om een item toe te voegen klikt u met rechts of tik en houd het vast om het te selecteren, klik vervolgens op Toevoegen aan afspeellijst.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favorieten",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Nieuwste",
+ "ViewTypeMusicPlaylists": "Afspeellijsten",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album artiesten",
"HeaderOtherDisplaySettings": "Beeld instellingen",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata voor:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Aankomende Films",
+ "HeaderUpcomingSports": "Sport binnenkort",
"HeaderUpcomingPrograms": "Aankomende Programma's",
"ButtonMoreItems": "Meer...",
"LabelShowLibraryTileNames": "Toon bibliotheek tegel namen",
"LabelShowLibraryTileNamesHelp": "Bepaalt of labels onder de bibliotheek tegels zullen worden weergegeven op de startpagina",
- "OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottle": "Throtteling inschakelen",
+ "OptionEnableTranscodingThrottleHelp": "Throtteling zal automatisch de snelheid van het transcoderen aanpassen om de cpu belasting laag te houden tijdens het afspelen.",
+ "LabelUploadSpeedLimit": "Upload limiet (mbps):",
+ "OptionAllowSyncTranscoding": "Sta synchronisatie toe die transcodering vereist",
+ "HeaderPlayback": "Media afspelen",
+ "OptionAllowAudioPlaybackTranscoding": "Sta het afspelen van audio wat transcoding vereist toe",
+ "OptionAllowVideoPlaybackTranscoding": "Sta het afspelen van video wat transcoding vereist toe",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Gebruikers zullen een bericht ontvangen als afspelen niet is toegestaan op basis van het beleid",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Client bitrate limiet (mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "Een optionele streaming bitrate limiet voor alle clients. Dit wordt gebruikt om te voorkomen dat clients een hogere bitrate aanvragen dan de internet connectie kan leveren.",
+ "LabelConversionCpuCoreLimit": "CPU core limiet:",
+ "LabelConversionCpuCoreLimitHelp": "Limiteer het aantal CPU cores wat gebruikt mag worden bij een omzetteing om te synchroniseren.",
+ "OptionEnableFullSpeedConversion": "Schakel hoge converteren op hoge snelheid in",
+ "OptionEnableFullSpeedConversionHelp": "Standaard wordt het converteren voor synchronisatie opdrachten op lage snelheid uitgevoerd zodat er weinig impact is op de server.",
+ "HeaderPlaylists": "Afspeellijsten",
+ "HeaderSelectDate": "Selecteer Datum",
+ "HeaderWelcomeExclamation": "Welkom!",
+ "HeaderMyPreferences": "Mijn voorkeuren",
+ "ButtonMyPreferencesWelcomeYes": "Ja, ik wil mijn voorkeuren nu instellen.",
+ "ButtonMyPreferencesWelcomeNo": "Nee, bedankt, dat doe ik later.",
+ "MyPreferencesWelcomeMessage1": "We tonen je bibliotheek op een manier waarvan we denken dat je het fijn vindt. De weergave en groepering kan altijd aangepast worden aan jouw voorkeur. Je voorkeur wordt op al je Emby apps toegepast.",
+ "MyPreferencesWelcomeMessage2": "Wil je nu je voorkeuren instellen?",
+ "ToAccessPreferencesHelp": "Om je voorkeuren later te wijzigen, klik je op je gebruikersicoon rechtsboven en kies je Mijn voorkeuren.",
+ "HeaderViewStyles": "Bekijk stijlen",
+ "LabelSelectViewStyles": "Schakel uitgebreide weergave in voor:",
+ "LabelSelectViewStylesHelp": "Bij inschakelen zullen overzichten met met categori\u00ebn zolas suggesties, recente, genres en meer getoond worden. Bij uitschakelen worden simpele mappen getoond."
} \ 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 ef441fccd..8edc74215 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/pl.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/pl.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Add User",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
"LabelPinCode": "Pin code:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "Ok",
"ButtonCancel": "Anuluj",
"ButtonExit": "Exit",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Nic tutaj nie ma.",
"MessagePleaseEnsureInternetMetadata": "Upewnij si\u0119 \u017ce pobieranie metadanych z internetu jest w\u0142\u0105czone.",
"TabSuggested": "Sugerowane",
+ "TabSuggestions": "Suggestions",
"TabLatest": "Ostatnie",
"TabUpcoming": "Upcoming",
"TabShows": "Seriale",
@@ -401,9 +404,10 @@
"ButtonRefresh": "Refresh",
"ButtonAdvancedRefresh": "Advanced Refresh",
"OptionPriority": "Priority",
- "OptionRecordOnAllChannels": "Record program on all channels",
- "OptionRecordAnytime": "Record program at any time",
+ "OptionRecordOnAllChannels": "Record on all channels",
+ "OptionRecordAnytime": "Record at any time",
"OptionRecordOnlyNewEpisodes": "Record only new episodes",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "Days",
"HeaderActiveRecordings": "Active Recordings",
"HeaderLatestRecordings": "Latest Recordings",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "Web socket port number:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Home page section 2:",
"LabelHomePageSection3": "Home page section 3:",
"LabelHomePageSection4": "Home page section 4:",
- "OptionMyViewsButtons": "My views (buttons)",
- "OptionMyViews": "My views",
- "OptionMyViewsSmall": "My views (small)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Resume",
"OptionLatestMedia": "Latest media",
"OptionLatestChannelMedia": "Latest channel items",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Default",
"OptionCommunityMostWatchedSort": "Most Watched",
"TabNextUp": "Next Up",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
"MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favorites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Display Settings",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "More...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ 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 20d7e32fa..35144da5e 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Adicionar Usu\u00e1rio",
"LabelAddConnectSupporterHelp": "Para adicionar um usu\u00e1rio que n\u00e3o esteja listado, voc\u00ea precisar\u00e1 associar sua conta ao Emby Connect na sua p\u00e1gina de perfil.",
"LabelPinCode": "C\u00f3digo Pin:",
+ "OptionHideWatchedContentFromLatestMedia": "Ocultar conte\u00fado j\u00e1 assistido das m\u00eddias recentes",
+ "HeaderSync": "Sincroniza\u00e7\u00e3o",
"ButtonOk": "Ok",
"ButtonCancel": "Cancelar",
"ButtonExit": "Sair",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Nada aqui.",
"MessagePleaseEnsureInternetMetadata": "Por favor, certifique-se que o download de metadados da internet est\u00e1 habilitado.",
"TabSuggested": "Sugeridos",
+ "TabSuggestions": "Sugest\u00f5es",
"TabLatest": "Recentes",
"TabUpcoming": "Por Estrear",
"TabShows": "S\u00e9ries",
@@ -401,9 +404,10 @@
"ButtonRefresh": "Atualizar",
"ButtonAdvancedRefresh": "Atualiza\u00e7\u00e3o Avan\u00e7ada",
"OptionPriority": "Prioridade",
- "OptionRecordOnAllChannels": "Gravar programa em todos os canais",
- "OptionRecordAnytime": "Gravar programa a qualquer hora",
+ "OptionRecordOnAllChannels": "Gravar em todos os canais",
+ "OptionRecordAnytime": "Gravar a qualquer hora",
"OptionRecordOnlyNewEpisodes": "Gravar apenas novos epis\u00f3dios",
+ "HeaderRepeatingOptions": "Op\u00e7\u00f5es de Repeti\u00e7\u00e3o",
"HeaderDays": "Dias",
"HeaderActiveRecordings": "Grava\u00e7\u00f5es Ativas",
"HeaderLatestRecordings": "Grava\u00e7\u00f5es Recentes",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "N\u00famero da porta p\u00fablica de https:",
"LabelPublicHttpsPortHelp": "O n\u00famero da porta p\u00fablica que dever\u00e1 ser mapeada para a porta local de https.",
"LabelEnableHttps": "Reportar https como um endere\u00e7o externo",
- "LabelEnableHttpsHelp": "Se ativado, o servidor ir\u00e1 reportar uma url https para os clientes como um endere\u00e7o externo. Isto pode prejudicar o funcionamento de clientes que ainda n\u00e3o suportam https.",
+ "LabelEnableHttpsHelp": "Se ativado, o servidor ir\u00e1 reportar uma url https para os clientes como um endere\u00e7o externo.",
"LabelHttpsPort": "N\u00famero da porta local de https:",
"LabelHttpsPortHelp": "O n\u00famero da porta tcp que o servidor https do Emby deveria se conectar.",
"LabelWebSocketPortNumber": "N\u00famero da porta do web socket:",
@@ -572,7 +576,7 @@
"HeaderDestination": "Destino",
"HeaderProgram": "Programa",
"HeaderClients": "Clientes",
- "LabelCompleted": "Completa",
+ "LabelCompleted": "Conclu\u00eddo",
"LabelFailed": "Falhou",
"LabelSkipped": "Ignorada",
"HeaderEpisodeOrganization": "Organiza\u00e7\u00e3o do Epis\u00f3dio",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Tela de in\u00edcio se\u00e7\u00e3o 2:",
"LabelHomePageSection3": "Tela de in\u00edcio se\u00e7\u00e3o 3:",
"LabelHomePageSection4": "Tela de in\u00edcio se\u00e7\u00e3o 4:",
- "OptionMyViewsButtons": "Minhas visualiza\u00e7\u00f5es (bot\u00f5es)",
- "OptionMyViews": "Minhas visualiza\u00e7\u00f5es",
- "OptionMyViewsSmall": "Minhas visualiza\u00e7\u00f5es (pequeno)",
+ "OptionMyMediaButtons": "Minha m\u00eddia (bot\u00f5es)",
+ "OptionMyMedia": "Minha m\u00eddia",
+ "OptionMyMediaSmall": "Minha m\u00eddia (pequeno)",
"OptionResumablemedia": "Retomar",
"OptionLatestMedia": "M\u00eddias recentes",
"OptionLatestChannelMedia": "Itens recentes de canal",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Padr\u00e3o",
"OptionCommunityMostWatchedSort": "Mais Assistidos",
"TabNextUp": "Pr\u00f3ximos",
+ "PlaceholderUsername": "Nome do usu\u00e1rio",
"HeaderBecomeProjectSupporter": "Torne-se um Colaborador do Emby",
- "TextEnjoyBonusFeatures": "Aproveite Funcionalidades Extras",
"MessageNoMovieSuggestionsAvailable": "N\u00e3o existem sugest\u00f5es de filmes dispon\u00edveis atualmente. Comece por assistir e avaliar seus filmes e, ent\u00e3o, volte para verificar suas recomenda\u00e7\u00f5es.",
"MessageNoCollectionsAvailable": "Cole\u00e7\u00f5es permitem que voc\u00ea aproveite grupos personalizados de Filmes, S\u00e9ries, \u00c1lbuns, Livros e Jogos. Clique no bot\u00e3o + para come\u00e7ar a criar Cole\u00e7\u00f5es.",
"MessageNoPlaylistsAvailable": "Listas de reprodu\u00e7\u00e3o permitem criar listas com conte\u00fado para reproduzir consecutivamente, de uma s\u00f3 vez. Para adicionar itens \u00e0s listas de reprodu\u00e7\u00e3o, clique com o bot\u00e3o direito ou toque a tela por alguns segundos, depois selecione Adicionar \u00e0 Lista de Reprodu\u00e7\u00e3o.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favoritos",
"ViewTypeMovieGenres": "G\u00eaneros",
"ViewTypeMusicLatest": "Recentes",
+ "ViewTypeMusicPlaylists": "Listas de Reprodu\u00e7\u00e3o",
"ViewTypeMusicAlbums": "\u00c1lbuns",
"ViewTypeMusicAlbumArtists": "Artistas do \u00c1lbum",
"HeaderOtherDisplaySettings": "Ajustes de Exibi\u00e7\u00e3o",
@@ -1096,8 +1101,8 @@
"HeaderActivity": "Atividade",
"ScheduledTaskStartedWithName": "{0} iniciado",
"ScheduledTaskCancelledWithName": "{0} foi cancelado",
- "ScheduledTaskCompletedWithName": "{0} completa",
- "ScheduledTaskFailed": "Tarefa agendada completa",
+ "ScheduledTaskCompletedWithName": "{0} conclu\u00edda",
+ "ScheduledTaskFailed": "Tarefa agendada conclu\u00edda",
"PluginInstalledWithName": "{0} foi instalado",
"PluginUpdatedWithName": "{0} foi atualizado",
"PluginUninstalledWithName": "{0} foi desinstalado",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Fazer download dos metadados da internet para:",
"OptionTVMovies": "Filmes da TV",
"HeaderUpcomingMovies": "Filmes Por Estrear",
+ "HeaderUpcomingSports": "Esportes Por Estrear",
"HeaderUpcomingPrograms": "Programas Por Estrear",
"ButtonMoreItems": "Mais...",
"LabelShowLibraryTileNames": "Mostrar os nomes das tiles da biblioteca",
"LabelShowLibraryTileNamesHelp": "Determina se os t\u00edtulos ser\u00e3o exibidos embaixo das tiles da biblioteca na p\u00e1gina in\u00edcio",
"OptionEnableTranscodingThrottle": "Ativar controlador de fluxo",
- "OptionEnableTranscodingThrottleHelp": "O controlador de fluxo ajustar\u00e1 automaticamente a velocidade de transcodifica\u00e7\u00e3o para minimizar o uso da cpu no servidor durante a reprodu\u00e7\u00e3o"
+ "OptionEnableTranscodingThrottleHelp": "O controlador de fluxo ajustar\u00e1 automaticamente a velocidade de transcodifica\u00e7\u00e3o para minimizar o uso da cpu no servidor durante a reprodu\u00e7\u00e3o.",
+ "LabelUploadSpeedLimit": "Limite de velocidade de upload (Mbps):",
+ "OptionAllowSyncTranscoding": "Permitir sincroniza\u00e7\u00e3o que necessite de transcodifica\u00e7\u00e3o",
+ "HeaderPlayback": "Reprodu\u00e7\u00e3o de M\u00eddia",
+ "OptionAllowAudioPlaybackTranscoding": "Permitir reprodu\u00e7\u00e3o de \u00e1udio que necessite de transcodifica\u00e7\u00e3o",
+ "OptionAllowVideoPlaybackTranscoding": "Permitir reprodu\u00e7\u00e3o de v\u00eddeo que necessite de transcodifica\u00e7\u00e3o",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Os usu\u00e1rios receber\u00e3o mensagens de erro amig\u00e1veis quando o conte\u00fado n\u00e3o for reproduz\u00edvel, baseado nas pol\u00edticas.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Limite de taxa de bits para o cliente remoto (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "Um limite opcional da taxa de bits para todos os clientes remotos. Esta op\u00e7\u00e3o \u00e9 \u00fatil para evitar que os clientes demandem uma taxa de bits maior que a permitida pela sua conex\u00e3o.",
+ "LabelConversionCpuCoreLimit": "Limite de n\u00facleos da CPU:",
+ "LabelConversionCpuCoreLimitHelp": "Limite o n\u00famero de n\u00facleos da CPU que ser\u00e3o usados durante a convers\u00e3o na sincroniza\u00e7\u00e3o",
+ "OptionEnableFullSpeedConversion": "Ativar convers\u00e3o de alta velocidade",
+ "OptionEnableFullSpeedConversionHelp": "Por padr\u00e3o, a convers\u00e3o na sincroniza\u00e7\u00e3o \u00e9 executada em uma velocidade baixa para minimizar o consumo de recursos.",
+ "HeaderPlaylists": "Listas de reprodu\u00e7\u00e3o",
+ "HeaderSelectDate": "Selecionar Data",
+ "HeaderWelcomeExclamation": "Bem Vindo!",
+ "HeaderMyPreferences": "Minhas Prefer\u00eancias",
+ "ButtonMyPreferencesWelcomeYes": "Sim, gostaria de definir minhas prefer\u00eancias agora.",
+ "ButtonMyPreferencesWelcomeNo": "N\u00e3o, obrigado. Farei mais tarde.",
+ "MyPreferencesWelcomeMessage1": "N\u00f3s exibimos sua biblioteca de uma forma que pensamos que ir\u00e1 gostar. A apar\u00eancia e o agrupamento de conte\u00fado podem ser mudados a qualquer hora ajustando suas prefer\u00eancias. Suas prefer\u00eancias ser\u00e3o aplicadas a todas as apps do Emby.",
+ "MyPreferencesWelcomeMessage2": "Gostaria de definir suas prefer\u00eancias agora?",
+ "ToAccessPreferencesHelp": "Para acessar suas prefer\u00eancias mais tarde, clique no \u00edcone do usu\u00e1rio no canto superior direito e selecione Minhas Prefer\u00eancias.",
+ "HeaderViewStyles": "Visualizar Estilos",
+ "LabelSelectViewStyles": "Ativar apresenta\u00e7\u00f5es melhoradas para:",
+ "LabelSelectViewStylesHelp": "Se ativada, as visualiza\u00e7\u00f5es ser\u00e3o feitas com metadados para oferecer categorias como Sugest\u00f5es, Recentes, G\u00eaneros e mais. Se desativada, elas ser\u00e3o exibidas como pastas simples."
} \ 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 dec7d35d2..6c6f19c14 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json
@@ -4,8 +4,8 @@
"LabelGithub": "Github",
"LabelSwagger": "Swagger",
"LabelStandard": "Padr\u00e3o",
- "LabelApiDocumentation": "Api Documentation",
- "LabelDeveloperResources": "Developer Resources",
+ "LabelApiDocumentation": "Documenta\u00e7\u00e3o da API",
+ "LabelDeveloperResources": "Recursos do Programador",
"LabelBrowseLibrary": "Navegar pela Biblioteca",
"LabelConfigureServer": "Configurar o Emby",
"LabelOpenLibraryViewer": "Abrir Visualizador da Biblioteca",
@@ -18,7 +18,7 @@
"WelcomeToProject": "Bem-vindo ao Emby!",
"ThisWizardWillGuideYou": "Este assistente ir\u00e1 ajud\u00e1-lo durante o processo de configura\u00e7\u00e3o. Para come\u00e7ar, selecione o idioma.",
"TellUsAboutYourself": "Fale-nos sobre si",
- "ButtonQuickStartGuide": "Quick start guide",
+ "ButtonQuickStartGuide": "Guia r\u00e1pido",
"LabelYourFirstName": "O seu primeiro nome:",
"MoreUsersCanBeAddedLater": "\u00c9 poss\u00edvel adicionar utilizadores mais tarde no Painel Principal",
"UserProfilesIntro": "O Emby inclui suporte nativo de perfis de utilizadores, permitindo que cada utilizador tenha as suas configura\u00e7\u00f5es de visualiza\u00e7\u00e3o, estado da reprodu\u00e7\u00e3o e controlos parentais.",
@@ -46,12 +46,14 @@
"LabelDashboardSourcePath": "Caminho da fonte do cliente web:",
"LabelDashboardSourcePathHelp": "Se correr o servidor a partir do c\u00f3digo fonte, especifique o caminho da pasta dashboard-ui. Todos os ficheiros do cliente web ser\u00e3o usados a partir desta localiza\u00e7\u00e3o.",
"ButtonConvertMedia": "Convert media",
- "ButtonOrganize": "Organize",
- "LinkedToEmbyConnect": "Linked to Emby Connect",
- "HeaderSupporterBenefits": "Supporter Benefits",
+ "ButtonOrganize": "Organizar",
+ "LinkedToEmbyConnect": "Associado ao Emby Connect",
+ "HeaderSupporterBenefits": "Benef\u00edcios do Apoiante",
"HeaderAddUser": "Add User",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
"LabelPinCode": "Pin code:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "Ok",
"ButtonCancel": "Cancelar",
"ButtonExit": "Exit",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Nada aqui.",
"MessagePleaseEnsureInternetMetadata": "Certifique-se que a transfer\u00eancia de metadados da internet est\u00e1 activa.",
"TabSuggested": "Sugest\u00f5es",
+ "TabSuggestions": "Suggestions",
"TabLatest": "Mais recente",
"TabUpcoming": "Pr\u00f3ximos",
"TabShows": "S\u00e9ries",
@@ -404,6 +407,7 @@
"OptionRecordOnAllChannels": "Gravar programa em todos os canais",
"OptionRecordAnytime": "Gravar programa em qualquer altura",
"OptionRecordOnlyNewEpisodes": "Gravar apenas novos epis\u00f3dios",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "Dias",
"HeaderActiveRecordings": "Grava\u00e7\u00f5es ativas",
"HeaderLatestRecordings": "\u00daltimas Grava\u00e7\u00f5es",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "N\u00famero da porta da Web socket:",
@@ -632,7 +636,7 @@
"LabelDownMixAudioScaleHelp": "Aumentar o \u00e1udio ao fazer downmix. Defina como 1 para preservar o volume original.",
"ButtonLinkKeys": "Transferir Chave",
"LabelOldSupporterKey": "Chave de apoiante antiga",
- "LabelNewSupporterKey": "Chave de apoiante nova",
+ "LabelNewSupporterKey": "Nova chave de apoiante",
"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",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Home page section 2:",
"LabelHomePageSection3": "Home page section 3:",
"LabelHomePageSection4": "Home page section 4:",
- "OptionMyViewsButtons": "My views (buttons)",
- "OptionMyViews": "My views",
- "OptionMyViewsSmall": "My views (small)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Resume",
"OptionLatestMedia": "Latest media",
"OptionLatestChannelMedia": "Latest channel items",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Default",
"OptionCommunityMostWatchedSort": "Most Watched",
"TabNextUp": "Next Up",
- "HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
+ "PlaceholderUsername": "Username",
+ "HeaderBecomeProjectSupporter": "Torne-se um Apoiante do Emby",
"MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
"MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favorites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Display Settings",
@@ -963,7 +968,7 @@
"LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:",
"LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.",
"OptionDisplayAdultContent": "Display adult content",
- "OptionLibraryFolders": "Media folders",
+ "OptionLibraryFolders": "Pastas multim\u00e9dia",
"TitleRemoteControl": "Remote Control",
"OptionLatestTvRecordings": "Latest recordings",
"LabelProtocolInfo": "Protocol info:",
@@ -1102,8 +1107,8 @@
"PluginUpdatedWithName": "{0} was updated",
"PluginUninstalledWithName": "{0} was uninstalled",
"ScheduledTaskFailedWithName": "{0} failed",
- "ItemAddedWithName": "{0} was added to the library",
- "ItemRemovedWithName": "{0} was removed from the library",
+ "ItemAddedWithName": "{0} foi adicionado \u00e0 biblioteca",
+ "ItemRemovedWithName": "{0} foi removido da biblioteca",
"DeviceOnlineWithName": "{0} is connected",
"UserOnlineFromDevice": "{0} is online from {1}",
"DeviceOfflineWithName": "{0} has disconnected",
@@ -1268,12 +1273,12 @@
"OptionHlsSegmentedSubtitles": "Hls segmented subtitles",
"LabelSubtitleFormatHelp": "Example: srt",
"ButtonLearnMore": "Learn more",
- "TabPlayback": "Playback",
+ "TabPlayback": "Reprodu\u00e7\u00e3o",
"HeaderLanguagePreferences": "Language Preferences",
- "TabCinemaMode": "Cinema Mode",
- "TitlePlayback": "Playback",
- "LabelEnableCinemaModeFor": "Enable cinema mode for:",
- "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
+ "TabCinemaMode": "Modo Cinema",
+ "TitlePlayback": "Reprodu\u00e7\u00e3o",
+ "LabelEnableCinemaModeFor": "Ativar modo cinema para:",
+ "CinemaModeConfigurationHelp": "O modo cinema traz a experi\u00eancia do cinema para a sua sala, possibilitando reproduzir trailers e introdu\u00e7\u00f5es personalizadas antes da longa-metragem.",
"OptionTrailersFromMyMovies": "Include trailers from movies in my library",
"OptionUpcomingMoviesInTheaters": "Include trailers from new and upcoming movies",
"LabelLimitIntrosToUnwatchedContent": "Only use trailers from unwatched content",
@@ -1284,14 +1289,14 @@
"LabelCustomIntrosPath": "Custom intros path:",
"LabelCustomIntrosPathHelp": "A folder containing video files. A video will be randomly selected and played after trailers.",
"ValueSpecialEpisodeName": "Special - {0}",
- "LabelSelectInternetTrailersForCinemaMode": "Internet trailers:",
+ "LabelSelectInternetTrailersForCinemaMode": "Trailers da Internet:",
"OptionUpcomingDvdMovies": "Include trailers from new and upcoming movies on Dvd & Blu-ray",
"OptionUpcomingStreamingMovies": "Include trailers from new and upcoming movies on Netflix",
"LabelDisplayTrailersWithinMovieSuggestions": "Display trailers within movie suggestions",
"LabelDisplayTrailersWithinMovieSuggestionsHelp": "Requires installation of the Trailer channel.",
- "CinemaModeConfigurationHelp2": "Individual users will have the ability to disable cinema mode within their own preferences.",
- "LabelEnableCinemaMode": "Enable cinema mode",
- "HeaderCinemaMode": "Cinema Mode",
+ "CinemaModeConfigurationHelp2": "Os utilizadores poder\u00e3o desativar o modo cinema nas suas prefer\u00eancias.",
+ "LabelEnableCinemaMode": "Ativar modo cinema",
+ "HeaderCinemaMode": "Modo Cinema",
"LabelDateAddedBehavior": "Date added behavior for new content:",
"OptionDateAddedImportTime": "Use date scanned into the library",
"OptionDateAddedFileTime": "Use file creation date",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "More...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ 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 29c1b9d12..60618b5ca 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/ru.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/ru.json
@@ -16,7 +16,7 @@
"LabelNext": "\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435",
"LabelYoureDone": "\u0412\u044b \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043b\u0438!",
"WelcomeToProject": "Emby \u043f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432\u0430\u0441!",
- "ThisWizardWillGuideYou": "\u042d\u0442\u043e\u0442 \u043f\u043e\u043c\u043e\u0449\u043d\u0438\u043a \u043f\u0440\u043e\u0432\u0435\u0434\u0451\u0442 \u0432\u0430\u0441 \u0447\u0435\u0440\u0435\u0437 \u0432\u0441\u0435 \u0444\u0430\u0437\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438. \u0427\u0442\u043e\u0431\u044b \u043d\u0430\u0447\u0430\u0442\u044c, \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0441\u0432\u043e\u0439 \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u0435\u043c\u044b\u0439 \u044f\u0437\u044b\u043a.",
+ "ThisWizardWillGuideYou": "\u042d\u0442\u043e\u0442 \u043f\u043e\u043c\u043e\u0449\u043d\u0438\u043a \u043f\u0440\u043e\u0432\u0435\u0434\u0451\u0442 \u0432\u0430\u0441 \u0447\u0435\u0440\u0435\u0437 \u0432\u0441\u0435 \u0444\u0430\u0437\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0441\u0432\u043e\u0439 \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u0435\u043c\u044b\u0439 \u044f\u0437\u044b\u043a.",
"TellUsAboutYourself": "\u0420\u0430\u0441\u0441\u043a\u0430\u0436\u0438\u0442\u0435 \u043e \u0441\u0435\u0431\u0435",
"ButtonQuickStartGuide": "\u041a\u043e \u043a\u0440\u0430\u0442\u043a\u043e\u043c\u0443 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u0443 \u043f\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0443",
"LabelYourFirstName": "\u0412\u0430\u0448\u0435 \u0438\u043c\u044f:",
@@ -29,9 +29,9 @@
"WizardCompleted": "\u042d\u0442\u043e \u043f\u043e\u043a\u0430 \u0432\u0441\u0451 \u0447\u0442\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e. Emby \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043e \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0435. \u041e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043d\u0430\u0448\u0438\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438, \u0430 \u043f\u043e\u0442\u043e\u043c \u043d\u0430\u0436\u043c\u0438\u0442\u0435 <b>\u0413\u043e\u0442\u043e\u0432\u043e<\/b>, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c <b>\u0418\u043d\u0444\u043e\u043f\u0430\u043d\u0435\u043b\u044c \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/b>.",
"LabelConfigureSettings": "\u041d\u0430\u0437\u043d\u0430\u0447\u0438\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b",
"LabelEnableVideoImageExtraction": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0435 \u0440\u0438\u0441\u0443\u043d\u043a\u0430 \u0438\u0437 \u0432\u0438\u0434\u0435\u043e",
- "VideoImageExtractionHelp": "\u0414\u043b\u044f \u0432\u0438\u0434\u0435\u043e, \u0433\u0434\u0435 \u0435\u0449\u0451 \u200b\u200b\u043d\u0435 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0440\u0438\u0441\u0443\u043d\u043a\u043e\u0432, \u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u0439\u0442\u0438 \u0432 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0435\u0449\u0451 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043a \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u043c\u0443 \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438, \u043d\u043e \u044d\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u0442 \u043a \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.",
+ "VideoImageExtractionHelp": "\u0414\u043b\u044f \u0432\u0438\u0434\u0435\u043e, \u0433\u0434\u0435 \u0435\u0449\u0451 \u200b\u200b\u043d\u0435 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0440\u0438\u0441\u0443\u043d\u043a\u043e\u0432, \u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u0439\u0442\u0438 \u0432 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0435\u0449\u0451 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043a \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u043c\u0443 \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438, \u043d\u043e \u044d\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u0442 \u043a \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u0438\u0432\u043b\u0435\u043a\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u043c\u0443 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044e.",
"LabelEnableChapterImageExtractionForMovies": "\u0418\u0437\u0432\u043b\u0435\u043a\u0430\u0442\u044c \u0440\u0438\u0441\u0443\u043d\u043a\u0438 \u0441\u0446\u0435\u043d \u0434\u043b\u044f \u0444\u0438\u043b\u044c\u043c\u043e\u0432",
- "LabelChapterImageExtractionForMoviesHelp": "\u0418\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0435 \u0440\u0438\u0441\u0443\u043d\u043a\u043e\u0432 \u0441\u0446\u0435\u043d \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043c\u0435\u043d\u044e \u0432\u044b\u0431\u043e\u0440\u0430 \u0441\u0446\u0435\u043d\u044b. \u0414\u0430\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u044b\u043c, \u043d\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440 \u0438 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0433\u0438\u0433\u0430\u0431\u0430\u0439\u0442 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0430. \u041e\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043a\u0430\u043a \u0437\u0430\u0434\u0430\u0447\u0430, \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u0430\u044f \u043d\u0430 \u043d\u043e\u0447\u044c, \u043e\u0434\u043d\u0430\u043a\u043e, \u0435\u0451 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0432 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u041d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447. \u041d\u0435 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443 \u0432 \u0447\u0430\u0441\u044b \u043f\u0438\u043a.",
+ "LabelChapterImageExtractionForMoviesHelp": "\u0418\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0435 \u0440\u0438\u0441\u0443\u043d\u043a\u043e\u0432 \u0441\u0446\u0435\u043d \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043c\u0435\u043d\u044e \u0432\u044b\u0431\u043e\u0440\u0430 \u0441\u0446\u0435\u043d\u044b. \u0414\u0430\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u044b\u043c, \u043d\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440 \u0438 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0433\u0438\u0433\u0430\u0431\u0430\u0439\u0442 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0430. \u041e\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432 \u0432\u0438\u0434\u0435 \u0437\u0430\u0434\u0430\u0447\u0438, \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u0430\u044f \u043d\u0430 \u043d\u043e\u0447\u044c, \u043e\u0434\u043d\u0430\u043a\u043e, \u0435\u0451 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0432 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u041d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447. \u041d\u0435 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443 \u0432 \u0447\u0430\u0441\u044b \u043f\u0438\u043a.",
"LabelEnableAutomaticPortMapping": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0430\u0432\u0442\u043e\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u0440\u0442\u043e\u0432",
"LabelEnableAutomaticPortMappingHelp": "UPnP \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0442\u043e\u0440\u0430 \u0434\u043b\u044f \u0443\u043f\u0440\u043e\u0449\u0451\u043d\u0438\u044f \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430.\u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0442\u043e\u0440\u043e\u0432.",
"HeaderTermsOfService": "\u0423\u0441\u043b\u043e\u0432\u0438\u044f \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0443\u0441\u043b\u0443\u0433 Emby",
@@ -41,7 +41,7 @@
"ButtonTermsOfService": "\u041a \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u043c \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0443\u0441\u043b\u0443\u0433",
"HeaderDeveloperOptions": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432",
"OptionEnableWebClientResponseCache": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0442\u043a\u043b\u0438\u043a\u043e\u0432 \u0432\u0435\u0431-\u043a\u043b\u0438\u0435\u043d\u0442\u0430",
- "OptionDisableForDevelopmentHelp": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u0442\u0435 \u0434\u0430\u043d\u043d\u043e\u0435, \u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438, \u0432 \u0446\u0435\u043b\u044f\u0445 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u0435\u0431-\u043a\u043b\u0438\u0435\u043d\u0442\u0430.",
+ "OptionDisableForDevelopmentHelp": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u0442\u0435 \u0438\u0445, \u043f\u043e \u043c\u0435\u0440\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438, \u0432 \u0446\u0435\u043b\u044f\u0445 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u0435\u0431-\u043a\u043b\u0438\u0435\u043d\u0442\u0430.",
"OptionEnableWebClientResourceMinification": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044e \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0432\u0435\u0431-\u043a\u043b\u0438\u0435\u043d\u0442\u0430",
"LabelDashboardSourcePath": "\u041f\u0443\u0442\u044c \u043a \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0443 \u0432\u0435\u0431-\u043a\u043b\u0438\u0435\u043d\u0442\u0430:",
"LabelDashboardSourcePathHelp": "\u0415\u0441\u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043e\u0442 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0445 \u043a\u043e\u0434\u043e\u0432, \u0443\u043a\u0430\u0436\u0438\u0442\u0435 \u043f\u0443\u0442\u044c \u043a \u043f\u0430\u043f\u043a\u0435 dashboard-ui. \u0412\u0441\u0435 \u0444\u0430\u0439\u043b\u044b \u0432\u0435\u0431-\u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0441 \u044d\u0442\u043e\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u0438\u044f.",
@@ -52,6 +52,8 @@
"HeaderAddUser": "\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f",
"LabelAddConnectSupporterHelp": "\u0427\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043d\u0435\u0442 \u0432 \u0441\u043f\u0438\u0441\u043a\u0435, \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0432\u044f\u0437\u0430\u0442\u044c \u0435\u0433\u043e \u0443\u0447\u0451\u0442\u043d\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c \u0441 Emby Connect \u0441 \u0435\u0433\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043f\u0440\u043e\u0444\u0438\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.",
"LabelPinCode": "PIN-\u043a\u043e\u0434:",
+ "OptionHideWatchedContentFromLatestMedia": "\u0421\u043a\u0440\u044b\u0442\u044c \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u0438\u0437 \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0445 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445",
+ "HeaderSync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f",
"ButtonOk": "\u041e\u041a",
"ButtonCancel": "\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c",
"ButtonExit": "\u0412\u044b\u0439\u0442\u0438",
@@ -112,8 +114,8 @@
"HeaderPreferredMetadataLanguage": "\u041f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u0435\u043c\u044b\u0439 \u044f\u0437\u044b\u043a \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445:",
"LabelSaveLocalMetadata": "\u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0438 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0432\u043d\u0443\u0442\u0440\u044c \u043c\u0435\u0434\u0438\u0430\u043f\u0430\u043f\u043e\u043a",
"LabelSaveLocalMetadataHelp": "\u041f\u0440\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0438 \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0439 \u0438 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0432\u043d\u0443\u0442\u0440\u044c \u043c\u0435\u0434\u0438\u0430\u043f\u0430\u043f\u043e\u043a, \u043e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u0432 \u0442\u0430\u043a\u043e\u043c \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0438, \u0433\u0434\u0435 \u0438\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u043f\u0440\u0430\u0432\u0438\u0442\u044c.",
- "LabelDownloadInternetMetadata": "\u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0438 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430",
- "LabelDownloadInternetMetadataHelp": "\u0412 Emby Server \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0439.",
+ "LabelDownloadInternetMetadata": "\u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0438 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430",
+ "LabelDownloadInternetMetadataHelp": "\u0412 Emby Server \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445, \u0447\u0442\u043e\u0431\u044b \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043d\u0430\u0441\u044b\u0449\u0435\u043d\u043d\u044b\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f.",
"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",
@@ -165,8 +167,9 @@
"LabelDropImageHere": "\u041f\u0435\u0440\u0435\u0442\u0430\u0449\u0438\u0442\u0435 \u0440\u0438\u0441\u0443\u043d\u043e\u043a \u0441\u044e\u0434\u0430",
"ImageUploadAspectRatioHelp": "\u0420\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u043c\u043e\u0435 \u0441\u043e\u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u0435 \u0441\u0442\u043e\u0440\u043e\u043d - 1:1. \u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b \u0442\u043e\u043b\u044c\u043a\u043e JPG\/PNG.",
"MessageNothingHere": "\u0417\u0434\u0435\u0441\u044c \u043d\u0435\u0442 \u043d\u0438\u0447\u0435\u0433\u043e.",
- "MessagePleaseEnsureInternetMetadata": "\u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0430.",
- "TabSuggested": "\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c\u043e\u0435",
+ "MessagePleaseEnsureInternetMetadata": "\u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0430.",
+ "TabSuggested": "\u041f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0435",
+ "TabSuggestions": "\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c\u043e\u0435",
"TabLatest": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435",
"TabUpcoming": "\u041e\u0436\u0438\u0434\u0430\u0435\u043c\u043e\u0435",
"TabShows": "\u0422\u0412-\u0446\u0438\u043a\u043b\u044b",
@@ -185,8 +188,8 @@
"OptionDirectors": "\u0420\u0435\u0436\u0438\u0441\u0441\u0451\u0440\u044b",
"OptionWriters": "\u0421\u0446\u0435\u043d\u0430\u0440\u0438\u0441\u0442\u044b",
"OptionProducers": "\u041f\u0440\u043e\u0434\u044e\u0441\u0435\u0440\u044b",
- "HeaderResume": "\u0412\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u0438\u043c\u044b\u0435",
- "HeaderNextUp": "\u041e\u0447\u0435\u0440\u0435\u0434\u043d\u044b\u0435",
+ "HeaderResume": "\u0412\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u0438\u043c\u043e\u0435",
+ "HeaderNextUp": "\u041e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0435",
"NoNextUpItemsMessage": "\u041d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e. \u041d\u0430\u0447\u043d\u0438\u0442\u0435 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0441\u0432\u043e\u0438 \u0422\u0412-\u0446\u0438\u043a\u043b\u044b!",
"HeaderLatestEpisodes": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u044d\u043f\u0438\u0437\u043e\u0434\u044b",
"HeaderPersonTypes": "\u0422\u0438\u043f\u044b \u043f\u0435\u0440\u0441\u043e\u043d:",
@@ -225,7 +228,7 @@
"OptionBanner": "\u0411\u0430\u043d\u043d\u0435\u0440",
"OptionCriticRating": "\u041e\u0446\u0435\u043d\u043a\u0430 \u043a\u0440\u0438\u0442\u0438\u043a\u043e\u0432",
"OptionVideoBitrate": "\u041f\u043e\u0442\u043e\u043a. \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0432\u0438\u0434\u0435\u043e",
- "OptionResumable": "\u0412\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u0438\u043c\u044b\u0435",
+ "OptionResumable": "\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435",
"ScheduledTasksHelp": "\u0429\u0451\u043b\u043a\u043d\u0438\u0442\u0435 \u043f\u043e \u0437\u0430\u0434\u0430\u0447\u0435, \u0447\u0442\u043e\u0431\u044b \u0441\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0451 \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u0435.",
"ScheduledTasksTitle": "\u041f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0449\u0438\u043a",
"TabMyPlugins": "\u041c\u043e\u0438 \u043f\u043b\u0430\u0433\u0438\u043d\u044b",
@@ -295,12 +298,12 @@
"VisitProjectWebsite": "\u041f\u043e\u0441\u0435\u0442\u0438\u0442\u044c \u0441\u0430\u0439\u0442 Emby",
"VisitProjectWebsiteLong": "\u041f\u043e\u0441\u0435\u0449\u0430\u0439\u0442\u0435 \u0441\u0430\u0439\u0442 Emby, \u0447\u0442\u043e\u0431\u044b \u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c\u0438 \u043d\u043e\u0432\u043e\u0441\u0442\u044f\u043c\u0438 \u0438 \u0441\u043b\u0435\u0434\u0438\u0442\u044c \u0437\u0430 \u0431\u043b\u043e\u0433\u043e\u043c \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",
- "OptionHideUserFromLoginHelp": "\u041f\u043e\u043b\u0435\u0437\u043d\u043e \u043f\u0440\u0438 \u043b\u0438\u0447\u043d\u044b\u0445 \u0438\u043b\u0438 \u0441\u043a\u0440\u044b\u0442\u044b\u0445 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0441\u043a\u0438\u0445 \u0443\u0447\u0451\u0442\u043d\u044b\u0445 \u0437\u0430\u043f\u0438\u0441\u0435\u0439. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u043d\u0443\u0436\u043d\u043e \u0432\u043e\u0439\u0442\u0438 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0432\u0440\u0443\u0447\u043d\u0443\u044e, \u0432\u0432\u0435\u0434\u044f \u0441\u0432\u043e\u0451 \u0438\u043c\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u043f\u0430\u0440\u043e\u043b\u044c.",
+ "OptionHideUserFromLoginHelp": "\u0426\u0435\u043b\u0435\u0441\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u043e \u0434\u043b\u044f \u043b\u0438\u0447\u043d\u044b\u0445 \u0438\u043b\u0438 \u0441\u043a\u0440\u044b\u0442\u044b\u0445 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0441\u043a\u0438\u0445 \u0443\u0447\u0451\u0442\u043d\u044b\u0445 \u0437\u0430\u043f\u0438\u0441\u0435\u0439. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0431\u0443\u0434\u0435\u0442 \u043d\u0443\u0436\u043d\u043e \u0432\u0445\u043e\u0434\u0438\u0442\u044c \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0432\u0440\u0443\u0447\u043d\u0443\u044e, \u0432\u0432\u043e\u0434\u044f \u0441\u0432\u043e\u0451 \u0438\u043c\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u043f\u0430\u0440\u043e\u043b\u044c.",
"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 \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):",
- "ButtonHelp": "\u041a \u0441\u043f\u0440\u0430\u0432\u043a\u0435",
+ "ButtonHelp": "\u041a \u0441\u043f\u0440\u0430\u0432\u043a\u0435 \u0432 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435",
"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",
@@ -345,7 +348,7 @@
"LabelMetadataPath": "\u041f\u0443\u0442\u044c \u043a \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u043c:",
"LabelMetadataPathHelp": "\u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u043d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0435 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u044b\u0445 \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0439 \u0438 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445, \u043f\u0440\u0438 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0438 \u043d\u0435 \u0432 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u0445 \u043c\u0435\u0434\u0438\u0430\u043f\u0430\u043f\u043e\u043a.",
"LabelTranscodingTempPath": "\u041f\u0443\u0442\u044c \u043a\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c \u0444\u0430\u0439\u043b\u0430\u043c \u043f\u0435\u0440\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0438:",
- "LabelTranscodingTempPathHelp": "\u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u043f\u0430\u043f\u043a\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u0441\u044f \u0440\u0430\u0431\u043e\u0447\u0438\u0435 \u0444\u0430\u0439\u043b\u044b, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0435. \u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u043d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043f\u0443\u0442\u044c, \u0438\u043b\u0438 \u043e\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u043f\u043e\u043b\u0435 \u043d\u0435\u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u043c, \u0447\u0442\u043e\u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0432\u043d\u0443\u0442\u0440\u0438 \u043f\u0430\u043f\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u0435\u0440\u0432\u0435\u0440\u0430.",
+ "LabelTranscodingTempPathHelp": "\u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u043f\u0430\u043f\u043a\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u0441\u044f \u0440\u0430\u0431\u043e\u0447\u0438\u0435 \u0444\u0430\u0439\u043b\u044b, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0435. \u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u043d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043f\u0443\u0442\u044c, \u0438\u043b\u0438 \u043d\u0435 \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0439\u0442\u0435, \u0447\u0442\u043e\u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0432\u043d\u0443\u0442\u0440\u0438 \u043f\u0430\u043f\u043a\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 data.",
"TabBasics": "\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435",
"TabTV": "\u0422\u0412",
"TabGames": "\u0418\u0433\u0440\u044b",
@@ -368,7 +371,7 @@
"LabelMetadataDownloadLanguage": "\u041f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u0435\u043c\u044b\u0439 \u044f\u0437\u044b\u043a \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u043e\u0433\u043e:",
"ButtonAutoScroll": "\u041a \u0430\u0432\u0442\u043e\u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0435",
"LabelImageSavingConvention": "\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0440\u0438\u0441\u0443\u043d\u043a\u043e\u0432:",
- "LabelImageSavingConventionHelp": "\u0412 Emby \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u044e\u0442\u0441\u044f \u0440\u0438\u0441\u0443\u043d\u043a\u0438 \u0438\u0437 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0440\u0430\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0451\u043d\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043c\u0443\u043b\u044c\u0442\u0438\u043c\u0435\u0434\u0438\u0430. \u0412\u044b\u0431\u043e\u0440 \u0441\u0432\u043e\u0435\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043f\u043e\u043b\u0435\u0437\u0435\u043d, \u0435\u0441\u043b\u0438 \u0432\u044b \u0442\u0430\u043a\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u044b.",
+ "LabelImageSavingConventionHelp": "\u0412 Emby \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u044e\u0442\u0441\u044f \u0440\u0438\u0441\u0443\u043d\u043a\u0438 \u0438\u0437 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0434\u043b\u044f \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445. \u0412\u044b\u0431\u043e\u0440 \u0441\u0432\u043e\u0435\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0446\u0435\u043b\u0435\u0441\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u044b\u043c, \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0442\u0430\u043a\u0436\u0435 \u0438\u043d\u044b\u0445 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432.",
"OptionImageSavingCompatible": "\u0421\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0439 - Emby\/Kodi\/Plex",
"OptionImageSavingStandard": "\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 - MB2",
"ButtonSignIn": "\u0412\u043e\u0439\u0442\u0438",
@@ -401,9 +404,10 @@
"ButtonRefresh": "\u041f\u043e\u0434\u043d\u043e\u0432\u0438\u0442\u044c",
"ButtonAdvancedRefresh": "\u041f\u043e\u0434\u043d\u043e\u0432\u0438\u0442\u044c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u043e",
"OptionPriority": "\u041f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442",
- "OptionRecordOnAllChannels": "\u0417\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0443 \u0441\u043e \u0432\u0441\u0435\u0445 \u043a\u0430\u043d\u0430\u043b\u043e\u0432",
- "OptionRecordAnytime": "\u0417\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0443 \u0432 \u043b\u044e\u0431\u043e\u0435 \u0432\u0440\u0435\u043c\u044f",
+ "OptionRecordOnAllChannels": "\u0417\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0441\u043e \u0432\u0441\u0435\u0445 \u043a\u0430\u043d\u0430\u043b\u043e\u0432",
+ "OptionRecordAnytime": "\u0417\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0432 \u043b\u044e\u0431\u043e\u0435 \u0432\u0440\u0435\u043c\u044f",
"OptionRecordOnlyNewEpisodes": "\u0417\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u043e\u0432\u044b\u0435 \u044d\u043f\u0438\u0437\u043e\u0434\u044b",
+ "HeaderRepeatingOptions": "\u041f\u043e\u0432\u0442\u043e\u0440\u044f\u044e\u0449\u0438\u0435\u0441\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b",
"HeaderDays": "\u0414\u043d\u0438",
"HeaderActiveRecordings": "\u0410\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u0437\u0430\u043f\u0438\u0441\u0438",
"HeaderLatestRecordings": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0438",
@@ -414,7 +418,7 @@
"ButtonDelete": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c",
"ButtonRemove": "\u0418\u0437\u044a\u044f\u0442\u044c",
"OptionRecordSeries": "\u0417\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0435\u0440\u0438\u0430\u043b",
- "HeaderDetails": "\u0414\u0435\u0442\u0430\u043b\u0438",
+ "HeaderDetails": "\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u0435 \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u044f",
"TitleLiveTV": "\u0422\u0412-\u044d\u0444\u0438\u0440",
"LabelNumberOfGuideDays": "\u0427\u0438\u0441\u043b\u043e \u0434\u043d\u0435\u0439 \u0434\u043b\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0433\u0438\u0434\u0430:",
"LabelNumberOfGuideDaysHelp": "\u0427\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u044b\u0445 \u0434\u043d\u0435\u0439, \u0442\u0435\u043c \u0446\u0435\u043d\u043d\u0435\u0435 \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0433\u0438\u0434\u0430, \u0434\u0430\u0432\u0430\u044f \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c \u0434\u043b\u044f \u0440\u0430\u043d\u043d\u0435\u0433\u043e \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0433\u043e \u0438 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u0431\u043e\u043b\u044c\u0448\u0435\u0433\u043e \u043e\u0431\u044a\u0451\u043c\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0447, \u043d\u043e \u044d\u0442\u043e \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u043e\u0434\u043b\u044f\u0435\u0442 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443. \u041f\u0440\u0438 \u0440\u0435\u0436\u0438\u043c\u0435 \u00ab\u0410\u0432\u0442\u043e\u00bb \u0432\u044b\u0431\u043e\u0440 \u0431\u0443\u0434\u0435\u0442 \u043e\u0441\u043d\u043e\u0432\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435 \u043a\u0430\u043d\u0430\u043b\u043e\u0432.",
@@ -547,14 +551,14 @@
"LabelPublicHttpsPort": "\u041d\u043e\u043c\u0435\u0440 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u0433\u043e HTTPS-\u043f\u043e\u0440\u0442\u0430:",
"LabelPublicHttpsPortHelp": "\u041f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u043d\u043e\u043c\u0435\u0440 \u043f\u043e\u0440\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u043c HTTPS-\u043f\u043e\u0440\u0442\u043e\u043c.",
"LabelEnableHttps": "\u041e\u0442\u0434\u0430\u0432\u0430\u0442\u044c HTTPS \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u0430\u0434\u0440\u0435\u0441\u0430",
- "LabelEnableHttpsHelp": "\u041f\u0440\u0438 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438, \u0441\u0435\u0440\u0432\u0435\u0440 \u043e\u0442\u0434\u0430\u0451\u0442 HTTPS URL \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c, \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0435\u0433\u043e \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u0430\u0434\u0440\u0435\u0441\u0430. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0435\u0440\u0432\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0435\u0449\u0451 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442 HTTPS-\u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b.",
+ "LabelEnableHttpsHelp": "\u041f\u0440\u0438 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438, \u0441\u0435\u0440\u0432\u0435\u0440 \u043e\u0442\u0434\u0430\u0451\u0442 HTTPS URL \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c, \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0435\u0433\u043e \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u0430\u0434\u0440\u0435\u0441\u0430.",
"LabelHttpsPort": "\u041d\u043e\u043c\u0435\u0440 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e HTTPS-\u043f\u043e\u0440\u0442\u0430:",
"LabelHttpsPortHelp": "TCP-\u043f\u043e\u0440\u0442, \u043a\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0443 HTTPS-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 Emby.",
"LabelWebSocketPortNumber": "\u041d\u043e\u043c\u0435\u0440 \u043f\u043e\u0440\u0442\u0430 \u0432\u0435\u0431-\u0441\u043e\u043a\u0435\u0442\u0430:",
"LabelEnableAutomaticPortMap": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0430\u0432\u0442\u043e\u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u0440\u0442\u043e\u0432",
"LabelEnableAutomaticPortMapHelp": "\u041f\u043e\u043f\u044b\u0442\u0430\u0442\u044c\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u043f\u043e\u0440\u0442 \u0441 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u043c \u043f\u043e\u0440\u0442\u043e\u043c \u0447\u0435\u0440\u0435\u0437 UPnP. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0442\u043e\u0440\u043e\u0432.",
"LabelExternalDDNS": "\u0412\u043d\u0435\u0448\u043d\u0438\u0439 WAN-\u0430\u0434\u0440\u0435\u0441:",
- "LabelExternalDDNSHelp": "\u0415\u0441\u043b\u0438 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0439 DNS, \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u0435\u0433\u043e \u0437\u0434\u0435\u0441\u044c. \u042d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f Emby-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438 \u043f\u0440\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438. \u041e\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u043f\u0443\u0441\u0442\u044b\u043c \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u044f.",
+ "LabelExternalDDNSHelp": "\u0415\u0441\u043b\u0438 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0439 DNS, \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u0435\u0433\u043e \u0437\u0434\u0435\u0441\u044c. \u042d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f Emby-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438 \u043f\u0440\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438. \u041d\u0435 \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0439\u0442\u0435 \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u044f.",
"TabResume": "\u0412\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435",
"TabWeather": "\u041f\u043e\u0433\u043e\u0434\u0430",
"TitleAppSettings": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f",
@@ -711,7 +715,7 @@
"ButtonPageUp": "\u041d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0432\u0432\u0435\u0440\u0445",
"ButtonPageDown": "\u041d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0432\u043d\u0438\u0437",
"PageAbbreviation": "\u0421\u0422\u0420",
- "ButtonHome": "\u041a \u0433\u043b\u0430\u0432\u043d\u043e\u043c\u0443",
+ "ButtonHome": "\u041a\u043e \u0433\u043b\u0430\u0432\u043d\u043e\u043c\u0443",
"ButtonSearch": "\u0412\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043f\u043e\u0438\u0441\u043a",
"ButtonSettings": "\u041a \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c",
"ButtonTakeScreenshot": "\u0421\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043d\u0438\u043c\u043e\u043a \u044d\u043a\u0440\u0430\u043d\u0430",
@@ -762,7 +766,7 @@
"OptionProfileVideoAudio": "\u0412\u0438\u0434\u0435\u043e \u0410\u0443\u0434\u0438\u043e",
"OptionProfilePhoto": "\u0424\u043e\u0442\u043e",
"LabelUserLibrary": "\u041c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f:",
- "LabelUserLibraryHelp": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435, \u0447\u044c\u044e \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0443 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u043d\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435. \u041e\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u043f\u043e\u043b\u0435 \u043d\u0435\u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u043c, \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e.",
+ "LabelUserLibraryHelp": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435, \u0447\u044c\u044e \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0443 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u043d\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435. \u041d\u0435 \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0439\u0442\u0435, \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e.",
"OptionPlainStorageFolders": "\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0432\u0441\u0435 \u043f\u0430\u043f\u043a\u0438, \u043a\u0430\u043a \u043e\u0431\u044b\u0447\u043d\u044b\u0435 \u043f\u0430\u043f\u043a\u0438 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f",
"OptionPlainStorageFoldersHelp": "\u041f\u0440\u0438 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438, \u0432\u0441\u0435 \u043f\u0430\u043f\u043a\u0438 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432 DIDL \u043a\u0430\u043a \u00abobject.container.storageFolder\u00bb, \u0432\u043c\u0435\u0441\u0442\u043e \u0431\u043e\u043b\u0435\u0435 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u00abobject.container.person.musicArtist\u00bb.",
"OptionPlainVideoItems": "\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0432\u0441\u0435 \u0438\u043c\u0435\u044e\u0449\u0438\u0435\u0441\u044f \u0432\u0438\u0434\u0435\u043e, \u043a\u0430\u043a \u043e\u0431\u044b\u0447\u043d\u044b\u0435 \u0432\u0438\u0434\u0435\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b",
@@ -839,7 +843,7 @@
"HeaderDownloadChaptersFor": "\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0439 \u0441\u0446\u0435\u043d \u0434\u043b\u044f:",
"LabelOpenSubtitlesUsername": "\u0418\u043c\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f Open Subtitles:",
"LabelOpenSubtitlesPassword": "\u041f\u0430\u0440\u043e\u043b\u044c Open Subtitles:",
- "HeaderChapterDownloadingHelp": "\u041f\u0440\u0438 \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0432\u0438\u0434\u0435\u043e\u0444\u0430\u0439\u043b\u043e\u0432 \u0432 Emby, \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u0445 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0439 \u0441\u0446\u0435\u043d \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043f\u043b\u0430\u0433\u0438\u043d\u044b \u0441\u0446\u0435\u043d, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, ChapterDb.",
+ "HeaderChapterDownloadingHelp": "\u041f\u0440\u0438 \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0432\u0438\u0434\u0435\u043e\u0444\u0430\u0439\u043b\u043e\u0432 \u0432 Emby, \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u0445 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0439 \u0441\u0446\u0435\u043d \u0438\u0437 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043f\u043b\u0430\u0433\u0438\u043d\u044b \u0441\u0446\u0435\u043d, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, ChapterDb.",
"LabelPlayDefaultAudioTrack": "\u0412\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0443\u044e \u0430\u0443\u0434\u0438\u043e\u0434\u043e\u0440\u043e\u0436\u043a\u0443 \u0432\u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u044f\u0437\u044b\u043a\u0430",
"LabelSubtitlePlaybackMode": "\u0420\u0435\u0436\u0438\u043c \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432:",
"LabelDownloadLanguages": "\u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u044b\u0435 \u044f\u0437\u044b\u043a\u0438:",
@@ -884,10 +888,10 @@
"LabelHomePageSection2": "\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 - \u0440\u0430\u0437\u0434\u0435\u043b 2:",
"LabelHomePageSection3": "\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 - \u0440\u0430\u0437\u0434\u0435\u043b 3:",
"LabelHomePageSection4": "\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 - \u0440\u0430\u0437\u0434\u0435\u043b 4:",
- "OptionMyViewsButtons": "\u041c\u043e\u0438 \u0430\u0441\u043f\u0435\u043a\u0442\u044b (\u043a\u043d\u043e\u043f\u043a\u0438)",
- "OptionMyViews": "\u041c\u043e\u0438 \u0430\u0441\u043f\u0435\u043a\u0442\u044b",
- "OptionMyViewsSmall": "\u041c\u043e\u0438 \u0430\u0441\u043f\u0435\u043a\u0442\u044b (\u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u043e)",
- "OptionResumablemedia": "\u0412\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u0438\u043c\u044b\u0435",
+ "OptionMyMediaButtons": "\u041c\u043e\u0438 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435 (\u043a\u043d\u043e\u043f\u043a\u0438)",
+ "OptionMyMedia": "\u041c\u043e\u0438 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435",
+ "OptionMyMediaSmall": "\u041c\u043e\u0438 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435 (\u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u043e)",
+ "OptionResumablemedia": "\u0412\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u0438\u043c\u043e\u0435",
"OptionLatestMedia": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435",
"OptionLatestChannelMedia": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0438\u0437 \u043a\u0430\u043d\u0430\u043b\u043e\u0432",
"HeaderLatestChannelItems": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0438\u0437 \u043a\u0430\u043d\u0430\u043b\u043e\u0432",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "\u0423\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u0435",
"OptionCommunityMostWatchedSort": "\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0435 \u0431\u043e\u043b\u044c\u0448\u0435",
"TabNextUp": "\u041e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0435",
+ "PlaceholderUsername": "\u0418\u043c\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f",
"HeaderBecomeProjectSupporter": "\u0421\u0442\u0430\u043d\u044c\u0442\u0435 \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u043e\u043c Emby",
- "TextEnjoyBonusFeatures": "\u0412\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435\u0441\u044c \u0431\u043e\u043d\u0443\u0441\u043d\u044b\u043c\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438",
"MessageNoMovieSuggestionsAvailable": "\u0412 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0435 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c\u044b\u0445 \u0444\u0438\u043b\u044c\u043c\u043e\u0432. \u041d\u0430\u0447\u043d\u0438\u0442\u0435 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0438 \u043e\u0446\u0435\u043d\u0438\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u0444\u0438\u043b\u044c\u043c\u044b, \u0438 \u0442\u043e\u0433\u0434\u0430 \u0432\u0435\u0440\u043d\u0438\u0442\u0435\u0441\u044c \u043d\u0430\u0437\u0430\u0434, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438.",
"MessageNoCollectionsAvailable": "\u041a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0438\u043d\u0434\u0438\u0432\u0438\u0434\u0443\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c\u0438 \u0441\u043e\u0431\u0440\u0430\u043d\u0438\u044f\u043c\u0438 \u0444\u0438\u043b\u044c\u043c\u043e\u0432, \u0441\u0435\u0440\u0438\u0430\u043b\u043e\u0432, \u0430\u043b\u044c\u0431\u043e\u043c\u043e\u0432, \u043a\u043d\u0438\u0433 \u0438 \u0438\u0433\u0440. \u041d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 \"+\", \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0439.",
"MessageNoPlaylistsAvailable": "\u0421\u043f\u0438\u0441\u043a\u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u043e\u0432 \u0438\u0437 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u0440\u0430\u0437\u043e\u043c. \u0427\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0432\u043e \u0441\u043f\u0438\u0441\u043a\u0438, \u0449\u0435\u043b\u043a\u043d\u0438\u0442\u0435 \u043f\u0440\u0430\u0432\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u043e\u0439 \u043c\u044b\u0448\u0438 \u0438\u043b\u0438 \u043a\u043e\u0441\u043d\u0438\u0442\u0435\u0441\u044c \u0438 \u0443\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0439\u0442\u0435, \u0437\u0430\u0442\u0435\u043c \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u00ab\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432\u043e \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f\u00bb.",
@@ -916,7 +920,7 @@
"LabelEnableChannelContentDownloadingFor": "\u0412\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u043e\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f \u043a\u0430\u043d\u0430\u043b\u0430 \u0434\u043b\u044f:",
"LabelEnableChannelContentDownloadingForHelp": "\u041d\u0430 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043a\u0430\u043d\u0430\u043b\u0430\u0445 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435, \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u044f\u044e\u0449\u0435\u0435 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440. \u0412\u043a\u043b\u044e\u0447\u0430\u0439\u0442\u0435 \u043f\u0440\u0438 \u0441\u0440\u0435\u0434\u0430\u0445 \u0441 \u043d\u0438\u0437\u043a\u043e\u0439 \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u043d\u043e\u0439 \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c\u044e, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u043a\u0430\u043d\u0430\u043b\u0430 \u0432 \u043d\u0435\u0440\u0430\u0431\u043e\u0447\u0435\u0435 \u0432\u0440\u0435\u043c\u044f. \u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u0447\u0430\u0441\u0442\u044c \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u00ab\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043a\u0430\u043d\u0430\u043b\u043e\u0432\u00bb.",
"LabelChannelDownloadPath": "\u041f\u0443\u0442\u044c \u0434\u043b\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u044b\u0445 \u043a\u0430\u043d\u0430\u043b\u043e\u0432:",
- "LabelChannelDownloadPathHelp": "\u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u043d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043f\u0443\u0442\u044c \u0434\u043b\u044f \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u043e\u0433\u043e, \u043f\u043e \u0436\u0435\u043b\u0430\u043d\u0438\u044e. \u041e\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u043f\u043e\u043b\u0435 \u043d\u0435\u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u043c, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0432\u043e \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u044e\u044e \u043f\u0430\u043f\u043a\u0443 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445.",
+ "LabelChannelDownloadPathHelp": "\u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u043d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043f\u0443\u0442\u044c \u0434\u043b\u044f \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u043e\u0433\u043e, \u043f\u043e \u0436\u0435\u043b\u0430\u043d\u0438\u044e. \u041d\u0435 \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0439\u0442\u0435, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0432\u043e \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u044e\u044e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u0443\u044e \u043f\u0430\u043f\u043a\u0443 data.",
"LabelChannelDownloadAge": "\u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f \u0447\u0435\u0440\u0435\u0437, \u0434\u043d\u0438:",
"LabelChannelDownloadAgeHelp": "\u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u0441\u0442\u0430\u0440\u0448\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u0443\u0434\u0430\u043b\u0435\u043d\u043e. \u041e\u043d\u043e \u043e\u0441\u0442\u0430\u043d\u0435\u0442\u0441\u044f \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u043c\u044b\u043c \u043f\u043e \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0442\u0440\u0430\u043d\u0441\u043b\u044f\u0446\u0438\u0438.",
"ChannelSettingsFormHelp": "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 \u043a\u0430\u043d\u0430\u043b\u044b (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440: Trailers \u0438\u043b\u0438 Vimeo) \u0438\u0437 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432.",
@@ -937,20 +941,21 @@
"ViewTypeGameFavorites": "\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u043e\u0435",
"ViewTypeGameSystems": "\u0418\u0433\u0440\u043e\u0432\u044b\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b",
"ViewTypeGameGenres": "\u0416\u0430\u043d\u0440\u044b",
- "ViewTypeTvResume": "\u0412\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u0438\u043c\u044b\u0435",
- "ViewTypeTvNextUp": "\u041e\u0447\u0435\u0440\u0435\u0434\u043d\u044b\u0435",
+ "ViewTypeTvResume": "\u0412\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u0438\u043c\u043e\u0435",
+ "ViewTypeTvNextUp": "\u041e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0435",
"ViewTypeTvLatest": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435",
"ViewTypeTvShowSeries": "\u0421\u0435\u0440\u0438\u0430\u043b\u044b",
"ViewTypeTvGenres": "\u0416\u0430\u043d\u0440\u044b",
"ViewTypeTvFavoriteSeries": "\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0441\u0435\u0440\u0438\u0430\u043b\u044b",
"ViewTypeTvFavoriteEpisodes": "\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u044d\u043f\u0438\u0437\u043e\u0434\u044b",
- "ViewTypeMovieResume": "\u0412\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u0438\u043c\u044b\u0435",
+ "ViewTypeMovieResume": "\u0412\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u0438\u043c\u043e\u0435",
"ViewTypeMovieLatest": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435",
"ViewTypeMovieMovies": "\u0424\u0438\u043b\u044c\u043c\u044b",
"ViewTypeMovieCollections": "\u041a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438",
"ViewTypeMovieFavorites": "\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u043e\u0435",
"ViewTypeMovieGenres": "\u0416\u0430\u043d\u0440\u044b",
"ViewTypeMusicLatest": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435",
+ "ViewTypeMusicPlaylists": "\u0421\u043f\u0438\u0441\u043a\u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f",
"ViewTypeMusicAlbums": "\u0410\u043b\u044c\u0431\u043e\u043c\u044b",
"ViewTypeMusicAlbumArtists": "\u0410\u043b\u044c\u0431\u043e\u043c\u043d\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u0438",
"HeaderOtherDisplaySettings": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f",
@@ -970,7 +975,7 @@
"LabelProtocolInfoHelp": "\u0417\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u043e\u0442\u043a\u043b\u0438\u043a\u0435 \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u044b GetProtocolInfo \u043e\u0442 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430.",
"TabNfo": "NFO-\u0444\u0430\u0439\u043b\u044b",
"HeaderKodiMetadataHelp": "\u0412 Emby \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0434\u043b\u044f \u0444\u0430\u0439\u043b\u043e\u0432 NFO-\u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445. \u0427\u0442\u043e\u0431\u044b \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0438\u043b\u0438 \u043e\u0442\u043a\u043b\u044e\u0447\u0430\u0442\u044c NFO-\u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0432\u043a\u043b\u0430\u0434\u043a\u0443 \u00ab\u0421\u043b\u0443\u0436\u0431\u044b\u00bb, \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u043f\u043e \u0442\u0438\u043f\u0430\u043c \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445.",
- "LabelKodiMetadataUser": "\u0421\u0438\u043d\u0445\u0440-\u0438\u044f NFO \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f:",
+ "LabelKodiMetadataUser": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u0441 NFO \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f:",
"LabelKodiMetadataUserHelp": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u0435, \u0447\u0442\u043e\u0431\u044b \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u043e\u043c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u043b\u0438\u0441\u044c \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c\u0438 \u043c\u0435\u0436\u0434\u0443 Emby Server \u0438 NFO-\u0444\u0430\u0439\u043b\u0430\u043c\u0438.",
"LabelKodiMetadataDateFormat": "\u0424\u043e\u0440\u043c\u0430\u0442 \u0434\u0430\u0442\u044b \u0432\u044b\u043f\u0443\u0441\u043a\u0430:",
"LabelKodiMetadataDateFormatHelp": "\u0412\u0441\u0435 \u0434\u0430\u0442\u044b \u0432 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u0445 NFO-\u0444\u0430\u0439\u043b\u043e\u0432 \u0431\u0443\u0434\u0443\u0442 \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0430.",
@@ -1209,7 +1214,7 @@
"HeaderTags": "\u0422\u0435\u0433\u0438",
"HeaderMetadataSettings": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445",
"LabelLockItemToPreventChanges": "\u0417\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u043f\u0440\u0435\u0442\u0438\u0442\u044c \u0431\u0443\u0434\u0443\u0449\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f",
- "MessageLeaveEmptyToInherit": "\u041e\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u043f\u043e\u043b\u0435 \u043d\u0435\u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u043c, \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043e\u0442 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430, \u0438\u043b\u0438 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e.",
+ "MessageLeaveEmptyToInherit": "\u041d\u0435 \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0439\u0442\u0435, \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043e\u0442 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430, \u0438\u043b\u0438 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e.",
"TabDonate": "\u041f\u043e\u0436\u0435\u0440\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u044f",
"HeaderDonationType": "\u0422\u0438\u043f \u043f\u043e\u0436\u0435\u0440\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u044f:",
"OptionMakeOneTimeDonation": "\u0421\u0434\u0435\u043b\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u0436\u0435\u0440\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435",
@@ -1246,7 +1251,7 @@
"HeaderXmlDocumentAttributes": "\u0410\u0442\u0440\u0438\u0431\u0443\u0442\u044b XML-\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430",
"HeaderXmlDocumentAttribute": "\u0410\u0442\u0440\u0438\u0431\u0443\u0442 XML-\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430",
"XmlDocumentAttributeListHelp": "\u0414\u0430\u043d\u043d\u044b\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u043a\u043e \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u043c\u0443 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0443 \u043a\u0430\u0436\u0434\u043e\u0433\u043e XML-\u043e\u0442\u043a\u043b\u0438\u043a\u0430.",
- "OptionSaveMetadataAsHidden": "\u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u0440\u0438\u0441\u0443\u043d\u043a\u0438 \u043a\u0430\u043a \u0441\u043a\u0440\u044b\u0442\u044b\u0435 \u0444\u0430\u0439\u043b\u044b",
+ "OptionSaveMetadataAsHidden": "\u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u0440\u0438\u0441\u0443\u043d\u043a\u0438 \u0432 \u0432\u0438\u0434\u0435 \u0441\u043a\u0440\u044b\u0442\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432",
"LabelExtractChaptersDuringLibraryScan": "\u0418\u0437\u0432\u043b\u0435\u043a\u0430\u0442\u044c \u0440\u0438\u0441\u0443\u043d\u043a\u0438 \u0441\u0446\u0435\u043d \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438",
"LabelExtractChaptersDuringLibraryScanHelp": "\u041f\u0440\u0438 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438, \u0440\u0438\u0441\u0443\u043d\u043a\u0438 \u0441\u0446\u0435\u043d \u0431\u0443\u0434\u0443\u0442 \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u044b, \u043a\u043e\u0433\u0434\u0430 \u0432\u0438\u0434\u0435\u043e \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438. \u041f\u0440\u0438 \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438, \u043e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u044b \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u00ab\u0420\u0438\u0441\u0443\u043d\u043a\u0438 \u0441\u0446\u0435\u043d\u00bb, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044f \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e\u043c\u0443 \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0442\u044c\u0441\u044f \u0431\u044b\u0441\u0442\u0440\u0435\u0435.",
"LabelConnectGuestUserName": "\u0418\u043c\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f Emby \u0438\u043b\u0438 \u0430\u0434\u0440\u0435\u0441 \u044d-\u043f\u043e\u0447\u0442\u044b:",
@@ -1307,7 +1312,7 @@
"LabelCreateCameraUploadSubfolder": "\u0421\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u043f\u0430\u043f\u043a\u0443 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430",
"LabelCreateCameraUploadSubfolderHelp": "\u041d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u043f\u0430\u043f\u043a\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u044b \u0434\u043b\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043f\u0440\u0438 \u0449\u0435\u043b\u0447\u043a\u0435 \u043d\u0430 \u043d\u0451\u043c \u0441\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \"\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\".",
"LabelCustomDeviceDisplayName": "\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c\u043e\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435:",
- "LabelCustomDeviceDisplayNameHelp": "\u041f\u0440\u0438\u0432\u0435\u0434\u0438\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c\u043e\u0435 \u0438\u043c\u044f \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438\u043b\u0438 \u043e\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u043f\u043e\u043b\u0435 \u043d\u0435\u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u043c, \u0447\u0442\u043e\u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u043c\u044f, \u0432\u044b\u0434\u0430\u043d\u043d\u043e\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u043c.",
+ "LabelCustomDeviceDisplayNameHelp": "\u041f\u0440\u0438\u0432\u0435\u0434\u0438\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c\u043e\u0435 \u0438\u043c\u044f \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438\u043b\u0438 \u043d\u0435 \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0439\u0442\u0435, \u0447\u0442\u043e\u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u043c\u044f, \u0432\u044b\u0434\u0430\u043d\u043d\u043e\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u043c.",
"HeaderInviteUser": "\u041f\u0440\u0438\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f",
"LabelConnectGuestUserNameHelp": "\u0418\u043c\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u043b\u0438 \u044d-\u043f\u043e\u0447\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432\u0430\u0448 \u0434\u0440\u0443\u0433 \u0434\u043b\u044f \u0432\u0445\u043e\u0434\u0430 \u043d\u0430 \u0432\u0435\u0431-\u0441\u0430\u0439\u0442 Emby.",
"HeaderInviteUserHelp": "\u041f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432\u0430\u0448\u0438\u043c \u0434\u0440\u0443\u0437\u044c\u044f\u043c \u043e\u0431\u0449\u0435\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u043c \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 Emby Connect.",
@@ -1378,13 +1383,39 @@
"LabelTagFilterAllowModeHelp": "\u0415\u0441\u043b\u0438 \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u0435 \u0442\u0435\u0433\u0438 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0447\u0430\u0441\u0442\u044c\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0433\u043b\u0443\u0431\u043e\u043a\u043e \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0445 \u043f\u0430\u043f\u043e\u043a, \u0442\u043e \u0434\u043b\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f, \u043f\u043e\u043c\u0435\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u0433\u0430\u043c\u0438, \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u043f\u0430\u043f\u043a\u0438 \u0431\u044b\u043b\u0438 \u043f\u043e\u043c\u0435\u0447\u0435\u043d\u044b \u0442\u0430\u043a\u0436\u0435.",
"HeaderThisUserIsCurrentlyDisabled": "\u042d\u0442\u043e\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d",
"MessageReenableUser": "\u0421\u043c. \u043d\u0438\u0436\u0435 \u0434\u043b\u044f \u0440\u0430\u0437\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438",
- "LabelEnableInternetMetadataForTvPrograms": "\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u043b\u044f:",
+ "LabelEnableInternetMetadataForTvPrograms": "\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u043b\u044f:",
"OptionTVMovies": "\u0422\u0412 \u0444\u0438\u043b\u044c\u043c\u044b",
"HeaderUpcomingMovies": "\u041e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0435 \u0444\u0438\u043b\u044c\u043c\u044b",
+ "HeaderUpcomingSports": "\u041e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0435 \u0441\u043f\u043e\u0440\u0442\u0438\u0432\u043d\u044b\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438",
"HeaderUpcomingPrograms": "\u041e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438",
"ButtonMoreItems": "\u0415\u0449\u0451...",
"LabelShowLibraryTileNames": "\u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u043f\u043b\u0438\u0442\u043e\u043a \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438",
"LabelShowLibraryTileNamesHelp": "\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f, \u0431\u0443\u0434\u0443\u0442 \u043b\u0438 \u043d\u0430\u0434\u043f\u0438\u0441\u0438 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u044b \u043f\u043e\u0434 \u043f\u043b\u0438\u0442\u043a\u0430\u043c\u0438 \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438 \u043d\u0430 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435.",
"OptionEnableTranscodingThrottle": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0440\u0435\u0433\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435",
- "OptionEnableTranscodingThrottleHelp": "\u0420\u0435\u0433\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0438 \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0441\u0432\u0435\u0441\u0442\u0438 \u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c\u0443 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f."
+ "OptionEnableTranscodingThrottleHelp": "\u0420\u0435\u0433\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0438 \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u043d\u0430 \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f.",
+ "LabelUploadSpeedLimit": "\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0432\u044b\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u043d\u0438\u044f, \u041c\u0431\u0438\u0442\/\u0441",
+ "OptionAllowSyncTranscoding": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043f\u0435\u0440\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0443",
+ "HeaderPlayback": "\u0412\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",
+ "OptionAllowAudioPlaybackTranscoding": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0430\u0443\u0434\u0438\u043e, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043f\u0435\u0440\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0443",
+ "OptionAllowVideoPlaybackTranscoding": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0432\u0438\u0434\u0435\u043e, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043f\u0435\u0440\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0443",
+ "OptionAllowMediaPlaybackTranscodingHelp": "\u041f\u0440\u0438 \u043d\u0435\u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u0438\u0445 \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0430\u0445 \u0434\u0440\u0443\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445.",
+ "TabStreaming": "\u0422\u0440\u0430\u043d\u0441\u043b\u044f\u0446\u0438\u044f",
+ "LabelRemoteClientBitrateLimit": "\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u043e\u0439 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u044b\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432, \u041c\u0431\u0438\u0442\/\u0441",
+ "LabelRemoteClientBitrateLimitHelp": "\u041d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u043e\u0439 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u044b\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432. \u042d\u0442\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0446\u0435\u043b\u0435\u0441\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u044b\u043c, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u043d\u0438\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c\u0438 \u0431\u043e\u043b\u0435\u0435 \u0432\u044b\u0441\u043e\u043a\u043e\u0439 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438, \u0447\u0435\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435.",
+ "LabelConversionCpuCoreLimit": "\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u043d\u044b\u0445 \u044f\u0434\u0435\u0440:",
+ "LabelConversionCpuCoreLimitHelp": "\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0447\u0438\u0441\u043b\u043e \u044f\u0434\u0435\u0440 \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u044b \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438.",
+ "OptionEnableFullSpeedConversion": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0441\u043a\u043e\u0440\u043e\u0441\u0442\u043d\u043e\u0435 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435",
+ "OptionEnableFullSpeedConversionHelp": "\u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0435 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u043d\u0438\u0437\u043a\u043e\u0439 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438, \u0447\u0442\u043e\u0431\u044b \u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0435\u043d\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432.",
+ "HeaderPlaylists": "\u0421\u043f\u0438\u0441\u043a\u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f",
+ "HeaderSelectDate": "\u0412\u044b\u0431\u043e\u0440 \u0434\u0430\u0442\u044b",
+ "HeaderWelcomeExclamation": "\u041f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u043c!",
+ "HeaderMyPreferences": "\u041c\u043e\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438",
+ "ButtonMyPreferencesWelcomeYes": "\u0414\u0430, \u044f \u0445\u043e\u0447\u0443 \u0442\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u0434\u0430\u0442\u044c \u043c\u043e\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438.",
+ "ButtonMyPreferencesWelcomeNo": "\u041d\u0435\u0442, \u0441\u043f\u0430\u0441\u0438\u0431\u043e, \u044f \u0441\u0434\u0435\u043b\u0430\u044e \u044d\u0442\u043e \u043f\u043e\u0442\u043e\u043c.",
+ "MyPreferencesWelcomeMessage1": "\u0412\u0430\u0448\u0430 \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u043d\u0430\u043c\u0438 \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043a\u0430\u043a \u043c\u044b \u0434\u0443\u043c\u0430\u0435\u043c, \u0447\u0442\u043e \u0432\u0430\u043c \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u044f\u0442\u043d\u043e. \u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u0432\u0438\u0434 \u0438 \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u044b \u0432 \u043b\u044e\u0431\u043e\u0435 \u0432\u0440\u0435\u043c\u044f, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u0430\u0448\u0438\u0445 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a. \u0412\u0430\u0448\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u043a\u043e \u0432\u0441\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c Emby.",
+ "MyPreferencesWelcomeMessage2": "\u0425\u043e\u0442\u0435\u043b\u0438 \u0431\u044b \u0432\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0441\u0432\u043e\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0441\u0435\u0439\u0447\u0430\u0441?",
+ "ToAccessPreferencesHelp": "\u0427\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u043e\u0437\u0436\u0435 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0432\u0430\u0448\u0438\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c, \u0449\u0435\u043b\u043a\u043d\u0438\u0442\u0435 \u0437\u043d\u0430\u0447\u043e\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0441\u043f\u0440\u0430\u0432\u0430 \u043d\u0430 \u0432\u0435\u0440\u0445\u043d\u0435\u0439 \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 \u0438 \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u041c\u043e\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438.",
+ "HeaderViewStyles": "\u0421\u0442\u0438\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043c\u0435\u0434\u0438\u0430\u043f\u0430\u043f\u043e\u043a",
+ "LabelSelectViewStyles": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043d\u0430\u0441\u044b\u0449\u0435\u043d\u043d\u044b\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u043b\u044f:",
+ "LabelSelectViewStylesHelp": "\u041f\u0440\u0438 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438, \u043c\u0435\u0434\u0438\u0430\u043f\u0430\u043f\u043a\u0438 \u0431\u0443\u0434\u0443\u0442 \u0441\u0442\u0438\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u044b \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u043c\u0438, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u043c\u0438 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c\u043e\u0435, \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435, \u0416\u0430\u043d\u0440\u044b \u0438 \u0442.\u0434. \u041f\u0440\u0438 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438, \u043e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u044b \u043f\u0440\u043e\u0441\u0442\u044b\u043c\u0438 \u043f\u0430\u043f\u043a\u0430\u043c\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 835e9b3be..f464dad4b 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/server.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json
@@ -53,6 +53,7 @@
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
"LabelPinCode": "Pin code:",
"OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "Ok",
"ButtonCancel": "Cancel",
"ButtonExit": "Exit",
@@ -403,9 +404,10 @@
"ButtonRefresh": "Refresh",
"ButtonAdvancedRefresh": "Advanced Refresh",
"OptionPriority": "Priority",
- "OptionRecordOnAllChannels": "Record program on all channels",
- "OptionRecordAnytime": "Record program at any time",
+ "OptionRecordOnAllChannels": "Record on all channels",
+ "OptionRecordAnytime": "Record at any time",
"OptionRecordOnlyNewEpisodes": "Record only new episodes",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "Days",
"HeaderActiveRecordings": "Active Recordings",
"HeaderLatestRecordings": "Latest Recordings",
@@ -551,7 +553,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "Web socket port number:",
@@ -895,9 +897,9 @@
"LabelHomePageSection2": "Home page section 2:",
"LabelHomePageSection3": "Home page section 3:",
"LabelHomePageSection4": "Home page section 4:",
- "OptionMyViewsButtons": "My views (buttons)",
- "OptionMyViews": "My views",
- "OptionMyViewsSmall": "My views (small)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Resume",
"OptionLatestMedia": "Latest media",
"OptionLatestChannelMedia": "Latest channel items",
@@ -962,6 +964,7 @@
"ViewTypeMovieFavorites": "Favorites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Display Settings",
@@ -1405,5 +1408,32 @@
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders.",
+ "TabPhotos": "Photos",
+ "TabVideos": "Videos"
}
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/sl_SI.json b/MediaBrowser.Server.Implementations/Localization/Server/sl_SI.json
index 86cb406b5..038b9b8e1 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/sl_SI.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/sl_SI.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Add User",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
"LabelPinCode": "Pin code:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "Ok",
"ButtonCancel": "Cancel",
"ButtonExit": "Exit",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Nothing here.",
"MessagePleaseEnsureInternetMetadata": "Please ensure downloading of internet metadata is enabled.",
"TabSuggested": "Suggested",
+ "TabSuggestions": "Suggestions",
"TabLatest": "Latest",
"TabUpcoming": "Upcoming",
"TabShows": "Shows",
@@ -401,9 +404,10 @@
"ButtonRefresh": "Refresh",
"ButtonAdvancedRefresh": "Advanced Refresh",
"OptionPriority": "Priority",
- "OptionRecordOnAllChannels": "Record program on all channels",
- "OptionRecordAnytime": "Record program at any time",
+ "OptionRecordOnAllChannels": "Record on all channels",
+ "OptionRecordAnytime": "Record at any time",
"OptionRecordOnlyNewEpisodes": "Record only new episodes",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "Days",
"HeaderActiveRecordings": "Active Recordings",
"HeaderLatestRecordings": "Latest Recordings",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "Web socket port number:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Home page section 2:",
"LabelHomePageSection3": "Home page section 3:",
"LabelHomePageSection4": "Home page section 4:",
- "OptionMyViewsButtons": "My views (buttons)",
- "OptionMyViews": "My views",
- "OptionMyViewsSmall": "My views (small)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Resume",
"OptionLatestMedia": "Latest media",
"OptionLatestChannelMedia": "Latest channel items",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Default",
"OptionCommunityMostWatchedSort": "Most Watched",
"TabNextUp": "Next Up",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
"MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favorites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Display Settings",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "More...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/sv.json b/MediaBrowser.Server.Implementations/Localization/Server/sv.json
index 390ecb170..6be67957a 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/sv.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/sv.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Add User",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
"LabelPinCode": "Pin code:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "OK",
"ButtonCancel": "Avbryt",
"ButtonExit": "Exit",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Ingenting h\u00e4r.",
"MessagePleaseEnsureInternetMetadata": "Var god se till att h\u00e4mtning av metadata via Internet \u00e4r aktiverad.",
"TabSuggested": "Rekommenderas",
+ "TabSuggestions": "Suggestions",
"TabLatest": "Nytillkommet",
"TabUpcoming": "Kommande",
"TabShows": "Serier",
@@ -404,6 +407,7 @@
"OptionRecordOnAllChannels": "Spela in fr\u00e5n alla kanaler",
"OptionRecordAnytime": "Spela in vid alla tidpunkter",
"OptionRecordOnlyNewEpisodes": "Spela bara in nya avsnitt",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "Dagar",
"HeaderActiveRecordings": "P\u00e5g\u00e5ende inspelningar",
"HeaderLatestRecordings": "Senaste inspelningarna",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "Webanslutningens portnummer:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Startsidans sektion 2:",
"LabelHomePageSection3": "Startsidans sektion 3:",
"LabelHomePageSection4": "Startsidans sektion 4:",
- "OptionMyViewsButtons": "Mina vyer (knappar)",
- "OptionMyViews": "Mina vyer",
- "OptionMyViewsSmall": "Mina vyer (liten)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "\u00c5teruppta",
"OptionLatestMedia": "Nytillkommet",
"OptionLatestChannelMedia": "Senaste objekten i Kanaler",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "F\u00f6rval",
"OptionCommunityMostWatchedSort": "Oftast visade",
"TabNextUp": "N\u00e4stkommande",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"MessageNoMovieSuggestionsAvailable": "Det finns inga filmf\u00f6rslag f\u00f6r tillf\u00e4llet. Efter att ha sett ett antal filmer kan du \u00e5terkomma hit f\u00f6r att se dina f\u00f6rslag.",
"MessageNoCollectionsAvailable": "Samlingar g\u00f6r det m\u00f6jligt att avnjuta personliga grupperingar av filmer, serier, Album, b\u00f6cker och spel. Klicka p\u00e5 knappen + f\u00f6r att b\u00f6rja skapa samlingar.",
"MessageNoPlaylistsAvailable": "Spellistor l\u00e5ter dig skapa listor med inneh\u00e5ll att spela upp i ordning. F\u00f6r att l\u00e4gga till objekt i spellistor, h\u00f6gerklicka eller tryck-och-h\u00e5ll och v\u00e4lj \"l\u00e4gg till i spellista\".",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favoriter",
"ViewTypeMovieGenres": "Genrer",
"ViewTypeMusicLatest": "Nytillkommet",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Album",
"ViewTypeMusicAlbumArtists": "Albumartister",
"HeaderOtherDisplaySettings": "Visningsinst\u00e4llningar",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "Mer...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ 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 96b8db8fc..bf994bc21 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/tr.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/tr.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Add User",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
"LabelPinCode": "Pin code:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "Tamam",
"ButtonCancel": "\u0130ptal",
"ButtonExit": "Exit",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Nothing here.",
"MessagePleaseEnsureInternetMetadata": "Please ensure downloading of internet metadata is enabled.",
"TabSuggested": "\u00d6nerilen",
+ "TabSuggestions": "Suggestions",
"TabLatest": "Son",
"TabUpcoming": "Gelecek",
"TabShows": "G\u00f6steriler",
@@ -404,6 +407,7 @@
"OptionRecordOnAllChannels": "T\u00fcm kanallardaki program\u0131 kaydet",
"OptionRecordAnytime": "Program\u0131 herhangi bir zamanda kaydet",
"OptionRecordOnlyNewEpisodes": "Sadece yeni b\u00f6l\u00fcmleri kaydet",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "G\u00fcnler",
"HeaderActiveRecordings": "Aktif Kay\u0131tlar",
"HeaderLatestRecordings": "Ge\u00e7mi\u015f Kay\u0131tlar",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "Web socket port number:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Anasayfa Secenek 2:",
"LabelHomePageSection3": "Anasayfa Secenek 3:",
"LabelHomePageSection4": "Anasayfa Secenek 4:",
- "OptionMyViewsButtons": "My views (buttons)",
- "OptionMyViews": "My views",
- "OptionMyViewsSmall": "My views (small)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Resume",
"OptionLatestMedia": "En Son G\u00f6r\u00fcnt\u00fclemeler",
"OptionLatestChannelMedia": "Latest channel items",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Default",
"OptionCommunityMostWatchedSort": "Most Watched",
"TabNextUp": "Sonraki hafta",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
"MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favorites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Display Settings",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "More...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/uk.json b/MediaBrowser.Server.Implementations/Localization/Server/uk.json
index 1f6da0700..faddf0d4a 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/uk.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/uk.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Add User",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
"LabelPinCode": "Pin code:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "Ok",
"ButtonCancel": "\u0421\u043a\u0430\u0441\u0443\u0432\u0430\u0442\u0438",
"ButtonExit": "Exit",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Nothing here.",
"MessagePleaseEnsureInternetMetadata": "Please ensure downloading of internet metadata is enabled.",
"TabSuggested": "Suggested",
+ "TabSuggestions": "Suggestions",
"TabLatest": "Latest",
"TabUpcoming": "Upcoming",
"TabShows": "Shows",
@@ -401,9 +404,10 @@
"ButtonRefresh": "Refresh",
"ButtonAdvancedRefresh": "Advanced Refresh",
"OptionPriority": "Priority",
- "OptionRecordOnAllChannels": "Record program on all channels",
- "OptionRecordAnytime": "Record program at any time",
+ "OptionRecordOnAllChannels": "Record on all channels",
+ "OptionRecordAnytime": "Record at any time",
"OptionRecordOnlyNewEpisodes": "Record only new episodes",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "Days",
"HeaderActiveRecordings": "Active Recordings",
"HeaderLatestRecordings": "Latest Recordings",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "Web socket port number:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Home page section 2:",
"LabelHomePageSection3": "Home page section 3:",
"LabelHomePageSection4": "Home page section 4:",
- "OptionMyViewsButtons": "My views (buttons)",
- "OptionMyViews": "My views",
- "OptionMyViewsSmall": "My views (small)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Resume",
"OptionLatestMedia": "\u041e\u0441\u0442\u0430\u043d\u043d\u0456 \u043c\u0435\u0434\u0456\u0430",
"OptionLatestChannelMedia": "Latest channel items",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Default",
"OptionCommunityMostWatchedSort": "Most Watched",
"TabNextUp": "Next Up",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
"MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favorites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "\u041e\u0441\u0442\u0430\u043d\u043d\u0456",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Display Settings",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "More...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ 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 8183e4601..0a19bfc1b 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/vi.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/vi.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Add User",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
"LabelPinCode": "Pin code:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "Ok",
"ButtonCancel": "Tho\u00e1t",
"ButtonExit": "Exit",
@@ -167,6 +169,7 @@
"MessageNothingHere": "Kh\u00f4ng c\u00f3 g\u00ec \u1edf \u0111\u00e2y.",
"MessagePleaseEnsureInternetMetadata": "Please ensure downloading of internet metadata is enabled.",
"TabSuggested": "Suggested",
+ "TabSuggestions": "Suggestions",
"TabLatest": "M\u1edbi nh\u1ea5t",
"TabUpcoming": "S\u1eafp di\u1ec5n ra",
"TabShows": "Shows",
@@ -401,9 +404,10 @@
"ButtonRefresh": "Refresh",
"ButtonAdvancedRefresh": "Advanced Refresh",
"OptionPriority": "Priority",
- "OptionRecordOnAllChannels": "Record program on all channels",
- "OptionRecordAnytime": "Record program at any time",
+ "OptionRecordOnAllChannels": "Record on all channels",
+ "OptionRecordAnytime": "Record at any time",
"OptionRecordOnlyNewEpisodes": "Record only new episodes",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "Days",
"HeaderActiveRecordings": "Active Recordings",
"HeaderLatestRecordings": "Latest Recordings",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "Web socket port number:",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Home page section 2:",
"LabelHomePageSection3": "Home page section 3:",
"LabelHomePageSection4": "Home page section 4:",
- "OptionMyViewsButtons": "My views (buttons)",
- "OptionMyViews": "My views",
- "OptionMyViewsSmall": "My views (small)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Resume",
"OptionLatestMedia": "Latest media",
"OptionLatestChannelMedia": "Latest channel items",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Default",
"OptionCommunityMostWatchedSort": "Most Watched",
"TabNextUp": "Next Up",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
"MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favorites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Display Settings",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "More...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ 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 b2c216960..2eb70ae66 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/zh_CN.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/zh_CN.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Add User",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
"LabelPinCode": "Pin code:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "\u786e\u5b9a",
"ButtonCancel": "\u53d6\u6d88",
"ButtonExit": "Exit",
@@ -167,6 +169,7 @@
"MessageNothingHere": "\u8fd9\u513f\u4ec0\u4e48\u90fd\u6ca1\u6709\u3002",
"MessagePleaseEnsureInternetMetadata": "\u8bf7\u786e\u4fdd\u5df2\u542f\u7528\u4ece\u4e92\u8054\u7f51\u4e0b\u8f7d\u5a92\u4f53\u8d44\u6599\u3002",
"TabSuggested": "\u5efa\u8bae",
+ "TabSuggestions": "Suggestions",
"TabLatest": "\u6700\u65b0",
"TabUpcoming": "\u5373\u5c06\u53d1\u5e03",
"TabShows": "\u8282\u76ee",
@@ -404,6 +407,7 @@
"OptionRecordOnAllChannels": "\u5f55\u5236\u6240\u6709\u9891\u9053",
"OptionRecordAnytime": "\u5f55\u5236\u6240\u6709\u65f6\u6bb5",
"OptionRecordOnlyNewEpisodes": "\u53ea\u5f55\u5236\u65b0\u5267\u96c6",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "\u5929",
"HeaderActiveRecordings": "\u6b63\u5728\u5f55\u5236\u7684\u8282\u76ee",
"HeaderLatestRecordings": "\u6700\u65b0\u5f55\u5236\u7684\u8282\u76ee",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "Web Socket\u7aef\u53e3\u53f7\uff1a",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "\u9996\u9875\u7b2c2\u533a\uff1a",
"LabelHomePageSection3": "\u9996\u9875\u7b2c3\u533a\uff1a",
"LabelHomePageSection4": "\u9996\u9875\u7b2c4\u533a\uff1a",
- "OptionMyViewsButtons": "\u6211\u7684\u754c\u9762(\u6309\u94ae)",
- "OptionMyViews": "\u6211\u7684\u754c\u9762",
- "OptionMyViewsSmall": "\u6211\u7684\u754c\u9762 (\u5c0f)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "\u6062\u590d\u64ad\u653e",
"OptionLatestMedia": "\u6700\u65b0\u5a92\u4f53",
"OptionLatestChannelMedia": "\u6700\u65b0\u9891\u9053\u9879\u76ee",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "\u9ed8\u8ba4",
"OptionCommunityMostWatchedSort": "\u6700\u53d7\u77a9\u76ee",
"TabNextUp": "\u4e0b\u4e00\u4e2a",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "\u4eab\u53d7\u5956\u52b1\u529f\u80fd",
"MessageNoMovieSuggestionsAvailable": "\u6ca1\u6709\u53ef\u7528\u7684\u7535\u5f71\u5efa\u8bae\u3002\u5f00\u59cb\u89c2\u770b\u4f60\u7684\u7535\u5f71\u5e76\u8fdb\u884c\u8bc4\u5206\uff0c\u518d\u56de\u8fc7\u5934\u6765\u67e5\u770b\u4f60\u7684\u5efa\u8bae\u3002",
"MessageNoCollectionsAvailable": "\u5408\u96c6\u8ba9\u4f60\u4eab\u53d7\u7535\u5f71\uff0c\u7cfb\u5217\uff0c\u76f8\u518c\uff0c\u4e66\u7c4d\u548c\u6e38\u620f\u4e2a\u6027\u5316\u7684\u5206\u7ec4\u3002\u5355\u51fb\u201c+\u201d\u6309\u94ae\u5f00\u59cb\u521b\u5efa\u5408\u96c6\u3002",
"MessageNoPlaylistsAvailable": "\u64ad\u653e\u5217\u8868\u5141\u8bb8\u60a8\u521b\u5efa\u4e00\u4e2a\u5185\u5bb9\u5217\u8868\u6765\u8fde\u7eed\u64ad\u653e\u3002\u5c06\u9879\u76ee\u6dfb\u52a0\u5230\u64ad\u653e\u5217\u8868\uff0c\u53f3\u952e\u5355\u51fb\u6216\u70b9\u51fb\u5e76\u6309\u4f4f\uff0c\u7136\u540e\u9009\u62e9\u201c\u6dfb\u52a0\u5230\u64ad\u653e\u5217\u8868\u201d\u3002",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "\u6536\u85cf\u5939",
"ViewTypeMovieGenres": "\u98ce\u683c",
"ViewTypeMusicLatest": "\u6700\u65b0",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "\u4e13\u8f91",
"ViewTypeMusicAlbumArtists": "\u4e13\u8f91\u827a\u672f\u5bb6",
"HeaderOtherDisplaySettings": "\u663e\u793a\u8bbe\u7f6e",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "\u66f4\u591a...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ 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 d957eb2cd..65d9b92a5 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json
@@ -52,6 +52,8 @@
"HeaderAddUser": "Add User",
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
"LabelPinCode": "Pin code:",
+ "OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
+ "HeaderSync": "Sync",
"ButtonOk": "OK",
"ButtonCancel": "\u53d6\u6d88",
"ButtonExit": "Exit",
@@ -167,6 +169,7 @@
"MessageNothingHere": "\u9019\u88e1\u6c92\u6709\u4ec0\u9ebc\u3002",
"MessagePleaseEnsureInternetMetadata": "\u8acb\u78ba\u4fdd\u5df2\u555f\u7528\u5f9e\u4e92\u806f\u7db2\u4e0b\u8f09\u5a92\u9ad4\u8cc7\u6599\u3002",
"TabSuggested": "\u5efa\u8b70",
+ "TabSuggestions": "Suggestions",
"TabLatest": "\u6700\u65b0",
"TabUpcoming": "\u5373\u5c07\u767c\u5e03",
"TabShows": "\u7bc0\u76ee",
@@ -404,6 +407,7 @@
"OptionRecordOnAllChannels": "\u9304\u5f71\u6240\u4ee5\u983b\u5ea6\u7684\u7bc0\u76ee",
"OptionRecordAnytime": "\u9304\u5f71\u6240\u6709\u6642\u6bb5\u7684\u7bc0\u76ee",
"OptionRecordOnlyNewEpisodes": "\u53ea\u9304\u5f71\u6700\u65b0\u7684\u55ae\u5143",
+ "HeaderRepeatingOptions": "Repeating Options",
"HeaderDays": "\u9304\u5f71\u65e5",
"HeaderActiveRecordings": "\u6b63\u5728\u9304\u5f71\u7684\u7bc0\u76ee",
"HeaderLatestRecordings": "\u6700\u65b0\u9304\u5f71\u7684\u7bc0\u76ee",
@@ -547,7 +551,7 @@
"LabelPublicHttpsPort": "Public https port number:",
"LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
"LabelEnableHttps": "Report https as external address",
- "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
+ "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address.",
"LabelHttpsPort": "Local https port number:",
"LabelHttpsPortHelp": "The tcp port number that Emby's https server should bind to.",
"LabelWebSocketPortNumber": "\u7db2\u7d61\u5957\u63a5\u7aef\u53e3\uff1a",
@@ -884,9 +888,9 @@
"LabelHomePageSection2": "Home page section 2:",
"LabelHomePageSection3": "Home page section 3:",
"LabelHomePageSection4": "Home page section 4:",
- "OptionMyViewsButtons": "My views (buttons)",
- "OptionMyViews": "My views",
- "OptionMyViewsSmall": "My views (small)",
+ "OptionMyMediaButtons": "My media (buttons)",
+ "OptionMyMedia": "My media",
+ "OptionMyMediaSmall": "My media (small)",
"OptionResumablemedia": "Resume",
"OptionLatestMedia": "Latest media",
"OptionLatestChannelMedia": "Latest channel items",
@@ -902,8 +906,8 @@
"OptionDefaultSort": "Default",
"OptionCommunityMostWatchedSort": "Most Watched",
"TabNextUp": "Next Up",
+ "PlaceholderUsername": "Username",
"HeaderBecomeProjectSupporter": "Become an Emby Supporter",
- "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
"MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
"MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
@@ -951,6 +955,7 @@
"ViewTypeMovieFavorites": "Favorites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Display Settings",
@@ -1381,10 +1386,36 @@
"LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
"OptionTVMovies": "TV Movies",
"HeaderUpcomingMovies": "Upcoming Movies",
+ "HeaderUpcomingSports": "Upcoming Sports",
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "More...",
"LabelShowLibraryTileNames": "Show library tile names",
"LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
"OptionEnableTranscodingThrottle": "Enable throttling",
- "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback.",
+ "LabelUploadSpeedLimit": "Upload speed limit (Mbps):",
+ "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
+ "HeaderPlayback": "Media Playback",
+ "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+ "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+ "TabStreaming": "Streaming",
+ "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (Mbps):",
+ "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.",
+ "LabelConversionCpuCoreLimit": "CPU core limit:",
+ "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.",
+ "OptionEnableFullSpeedConversion": "Enable full speed conversion",
+ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.",
+ "HeaderPlaylists": "Playlists",
+ "HeaderSelectDate": "Select Date",
+ "HeaderWelcomeExclamation": "Welcome!",
+ "HeaderMyPreferences": "My Preferences",
+ "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.",
+ "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
+ "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
+ "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
+ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
+ "HeaderViewStyles": "View Styles",
+ "LabelSelectViewStyles": "Enable rich presentations for:",
+ "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/cultures.json b/MediaBrowser.Server.Implementations/Localization/cultures.json
deleted file mode 100644
index e9732fda8..000000000
--- a/MediaBrowser.Server.Implementations/Localization/cultures.json
+++ /dev/null
@@ -1 +0,0 @@
-[{"Name":"af","DisplayName":"Afrikaans","TwoLetterISOLanguageName":"af","ThreeLetterISOLanguageName":"afr"},{"Name":"sq","DisplayName":"Albanian","TwoLetterISOLanguageName":"sq","ThreeLetterISOLanguageName":"sqi"},{"Name":"gsw","DisplayName":"Alsatian","TwoLetterISOLanguageName":"gsw","ThreeLetterISOLanguageName":"gsw"},{"Name":"am","DisplayName":"Amharic","TwoLetterISOLanguageName":"am","ThreeLetterISOLanguageName":"amh"},{"Name":"ar","DisplayName":"Arabic","TwoLetterISOLanguageName":"ar","ThreeLetterISOLanguageName":"ara"},{"Name":"hy","DisplayName":"Armenian","TwoLetterISOLanguageName":"hy","ThreeLetterISOLanguageName":"hye"},{"Name":"as","DisplayName":"Assamese","TwoLetterISOLanguageName":"as","ThreeLetterISOLanguageName":"asm"},{"Name":"az","DisplayName":"Azeri","TwoLetterISOLanguageName":"az","ThreeLetterISOLanguageName":"aze"},{"Name":"jv","DisplayName":"Basa Jawa","TwoLetterISOLanguageName":"jv","ThreeLetterISOLanguageName":"jav"},{"Name":"ba","DisplayName":"Bashkir","TwoLetterISOLanguageName":"ba","ThreeLetterISOLanguageName":"bak"},{"Name":"eu","DisplayName":"Basque","TwoLetterISOLanguageName":"eu","ThreeLetterISOLanguageName":"eus"},{"Name":"be","DisplayName":"Belarusian","TwoLetterISOLanguageName":"be","ThreeLetterISOLanguageName":"bel"},{"Name":"bn","DisplayName":"Bengali","TwoLetterISOLanguageName":"bn","ThreeLetterISOLanguageName":"bng"},{"Name":"bs","DisplayName":"Bosnian","TwoLetterISOLanguageName":"bs","ThreeLetterISOLanguageName":"bsb"},{"Name":"bs-Cyrl","DisplayName":"Bosnian (Cyrillic)","TwoLetterISOLanguageName":"bs","ThreeLetterISOLanguageName":"bsc"},{"Name":"br","DisplayName":"Breton","TwoLetterISOLanguageName":"br","ThreeLetterISOLanguageName":"bre"},{"Name":"bg","DisplayName":"Bulgarian","TwoLetterISOLanguageName":"bg","ThreeLetterISOLanguageName":"bul"},{"Name":"my","DisplayName":"Burmese","TwoLetterISOLanguageName":"my","ThreeLetterISOLanguageName":"mya"},{"Name":"ca","DisplayName":"Catalan","TwoLetterISOLanguageName":"ca","ThreeLetterISOLanguageName":"cat"},{"Name":"tzm-Tfng-MA","DisplayName":"Central Atlas Tamazight (Tifinagh, Morocco)","TwoLetterISOLanguageName":"tzm","ThreeLetterISOLanguageName":"tzm"},{"Name":"ku","DisplayName":"Central Kurdish","TwoLetterISOLanguageName":"ku","ThreeLetterISOLanguageName":"kur"},{"Name":"chr","DisplayName":"Cherokee","TwoLetterISOLanguageName":"chr","ThreeLetterISOLanguageName":"chr"},{"Name":"zh","DisplayName":"Chinese","TwoLetterISOLanguageName":"zh","ThreeLetterISOLanguageName":"zho"},{"Name":"sn","DisplayName":"chiShona","TwoLetterISOLanguageName":"sn","ThreeLetterISOLanguageName":"sna"},{"Name":"co","DisplayName":"Corsican","TwoLetterISOLanguageName":"co","ThreeLetterISOLanguageName":"cos"},{"Name":"hr","DisplayName":"Croatian","TwoLetterISOLanguageName":"hr","ThreeLetterISOLanguageName":"hrv"},{"Name":"hr-BA","DisplayName":"Croatian (Latin, Bosnia and Herzegovina)","TwoLetterISOLanguageName":"hr","ThreeLetterISOLanguageName":"hrb"},{"Name":"cs","DisplayName":"Czech","TwoLetterISOLanguageName":"cs","ThreeLetterISOLanguageName":"ces"},{"Name":"da","DisplayName":"Danish","TwoLetterISOLanguageName":"da","ThreeLetterISOLanguageName":"dan"},{"Name":"prs","DisplayName":"Dari","TwoLetterISOLanguageName":"prs","ThreeLetterISOLanguageName":"prs"},{"Name":"dv","DisplayName":"Divehi","TwoLetterISOLanguageName":"dv","ThreeLetterISOLanguageName":"div"},{"Name":"nl","DisplayName":"Dutch","TwoLetterISOLanguageName":"nl","ThreeLetterISOLanguageName":"nld"},{"Name":"en","DisplayName":"English","TwoLetterISOLanguageName":"en","ThreeLetterISOLanguageName":"eng"},{"Name":"et","DisplayName":"Estonian","TwoLetterISOLanguageName":"et","ThreeLetterISOLanguageName":"est"},{"Name":"fo","DisplayName":"Faroese","TwoLetterISOLanguageName":"fo","ThreeLetterISOLanguageName":"fao"},{"Name":"fil","DisplayName":"Filipino","TwoLetterISOLanguageName":"fil","ThreeLetterISOLanguageName":"fil"},{"Name":"fi","DisplayName":"Finnish","TwoLetterISOLanguageName":"fi","ThreeLetterISOLanguageName":"fin"},{"Name":"fr","DisplayName":"French","TwoLetterISOLanguageName":"fr","ThreeLetterISOLanguageName":"fra"},{"Name":"fy","DisplayName":"Frisian","TwoLetterISOLanguageName":"fy","ThreeLetterISOLanguageName":"fry"},{"Name":"ff","DisplayName":"Fulah","TwoLetterISOLanguageName":"ff","ThreeLetterISOLanguageName":"ful"},{"Name":"gl","DisplayName":"Galician","TwoLetterISOLanguageName":"gl","ThreeLetterISOLanguageName":"glg"},{"Name":"ka","DisplayName":"Georgian","TwoLetterISOLanguageName":"ka","ThreeLetterISOLanguageName":"kat"},{"Name":"de","DisplayName":"German","TwoLetterISOLanguageName":"de","ThreeLetterISOLanguageName":"deu"},{"Name":"el","DisplayName":"Greek","TwoLetterISOLanguageName":"el","ThreeLetterISOLanguageName":"ell"},{"Name":"kl","DisplayName":"Greenlandic","TwoLetterISOLanguageName":"kl","ThreeLetterISOLanguageName":"kal"},{"Name":"gn","DisplayName":"Guarani","TwoLetterISOLanguageName":"gn","ThreeLetterISOLanguageName":"grn"},{"Name":"gu","DisplayName":"Gujarati","TwoLetterISOLanguageName":"gu","ThreeLetterISOLanguageName":"guj"},{"Name":"ha","DisplayName":"Hausa","TwoLetterISOLanguageName":"ha","ThreeLetterISOLanguageName":"hau"},{"Name":"haw","DisplayName":"Hawaiian","TwoLetterISOLanguageName":"haw","ThreeLetterISOLanguageName":"haw"},{"Name":"he","DisplayName":"Hebrew","TwoLetterISOLanguageName":"he","ThreeLetterISOLanguageName":"heb"},{"Name":"hi","DisplayName":"Hindi","TwoLetterISOLanguageName":"hi","ThreeLetterISOLanguageName":"hin"},{"Name":"hu","DisplayName":"Hungarian","TwoLetterISOLanguageName":"hu","ThreeLetterISOLanguageName":"hun"},{"Name":"is","DisplayName":"Icelandic","TwoLetterISOLanguageName":"is","ThreeLetterISOLanguageName":"isl"},{"Name":"ig","DisplayName":"Igbo","TwoLetterISOLanguageName":"ig","ThreeLetterISOLanguageName":"ibo"},{"Name":"id","DisplayName":"Indonesian","TwoLetterISOLanguageName":"id","ThreeLetterISOLanguageName":"ind"},{"Name":"iu","DisplayName":"Inuktitut","TwoLetterISOLanguageName":"iu","ThreeLetterISOLanguageName":"iku"},{"Name":"ga","DisplayName":"Irish","TwoLetterISOLanguageName":"ga","ThreeLetterISOLanguageName":"gle"},{"Name":"xh","DisplayName":"isiXhosa","TwoLetterISOLanguageName":"xh","ThreeLetterISOLanguageName":"xho"},{"Name":"zu","DisplayName":"isiZulu","TwoLetterISOLanguageName":"zu","ThreeLetterISOLanguageName":"zul"},{"Name":"it","DisplayName":"Italian","TwoLetterISOLanguageName":"it","ThreeLetterISOLanguageName":"ita"},{"Name":"ja","DisplayName":"Japanese","TwoLetterISOLanguageName":"ja","ThreeLetterISOLanguageName":"jpn"},{"Name":"kn","DisplayName":"Kannada","TwoLetterISOLanguageName":"kn","ThreeLetterISOLanguageName":"kan"},{"Name":"kk","DisplayName":"Kazakh","TwoLetterISOLanguageName":"kk","ThreeLetterISOLanguageName":"kaz"},{"Name":"km","DisplayName":"Khmer","TwoLetterISOLanguageName":"km","ThreeLetterISOLanguageName":"khm"},{"Name":"qut","DisplayName":"K'iche","TwoLetterISOLanguageName":"qut","ThreeLetterISOLanguageName":"qut"},{"Name":"rw","DisplayName":"Kinyarwanda","TwoLetterISOLanguageName":"rw","ThreeLetterISOLanguageName":"kin"},{"Name":"sw","DisplayName":"Kiswahili","TwoLetterISOLanguageName":"sw","ThreeLetterISOLanguageName":"swa"},{"Name":"kok","DisplayName":"Konkani","TwoLetterISOLanguageName":"kok","ThreeLetterISOLanguageName":"kok"},{"Name":"ko","DisplayName":"Korean","TwoLetterISOLanguageName":"ko","ThreeLetterISOLanguageName":"kor"},{"Name":"ky","DisplayName":"Kyrgyz","TwoLetterISOLanguageName":"ky","ThreeLetterISOLanguageName":"kir"},{"Name":"lo","DisplayName":"Lao","TwoLetterISOLanguageName":"lo","ThreeLetterISOLanguageName":"lao"},{"Name":"lv","DisplayName":"Latvian","TwoLetterISOLanguageName":"lv","ThreeLetterISOLanguageName":"lav"},{"Name":"lt","DisplayName":"Lithuanian","TwoLetterISOLanguageName":"lt","ThreeLetterISOLanguageName":"lit"},{"Name":"dsb","DisplayName":"Lower Sorbian","TwoLetterISOLanguageName":"dsb","ThreeLetterISOLanguageName":"dsb"},{"Name":"lb","DisplayName":"Luxembourgish","TwoLetterISOLanguageName":"lb","ThreeLetterISOLanguageName":"ltz"},{"Name":"mk-MK","DisplayName":"Macedonian (Former Yugoslav Republic of Macedonia)","TwoLetterISOLanguageName":"mk","ThreeLetterISOLanguageName":"mkd"},{"Name":"mg","DisplayName":"Malagasy","TwoLetterISOLanguageName":"mg","ThreeLetterISOLanguageName":"mlg"},{"Name":"ms","DisplayName":"Malay","TwoLetterISOLanguageName":"ms","ThreeLetterISOLanguageName":"msa"},{"Name":"ml","DisplayName":"Malayalam","TwoLetterISOLanguageName":"ml","ThreeLetterISOLanguageName":"mym"},{"Name":"mt","DisplayName":"Maltese","TwoLetterISOLanguageName":"mt","ThreeLetterISOLanguageName":"mlt"},{"Name":"mi","DisplayName":"Maori","TwoLetterISOLanguageName":"mi","ThreeLetterISOLanguageName":"mri"},{"Name":"arn","DisplayName":"Mapudungun","TwoLetterISOLanguageName":"arn","ThreeLetterISOLanguageName":"arn"},{"Name":"mr","DisplayName":"Marathi","TwoLetterISOLanguageName":"mr","ThreeLetterISOLanguageName":"mar"},{"Name":"moh","DisplayName":"Mohawk","TwoLetterISOLanguageName":"moh","ThreeLetterISOLanguageName":"moh"},{"Name":"mn","DisplayName":"Mongolian","TwoLetterISOLanguageName":"mn","ThreeLetterISOLanguageName":"mon"},{"Name":"ne","DisplayName":"Nepali","TwoLetterISOLanguageName":"ne","ThreeLetterISOLanguageName":"nep"},{"Name":"no","DisplayName":"Norwegian","TwoLetterISOLanguageName":"nb","ThreeLetterISOLanguageName":"nob"},{"Name":"nn","DisplayName":"Norwegian (Nynorsk)","TwoLetterISOLanguageName":"nn","ThreeLetterISOLanguageName":"nno"},{"Name":"oc","DisplayName":"Occitan","TwoLetterISOLanguageName":"oc","ThreeLetterISOLanguageName":"oci"},{"Name":"or","DisplayName":"Oriya","TwoLetterISOLanguageName":"or","ThreeLetterISOLanguageName":"ori"},{"Name":"om","DisplayName":"Oromo","TwoLetterISOLanguageName":"om","ThreeLetterISOLanguageName":"orm"},{"Name":"ps","DisplayName":"Pashto","TwoLetterISOLanguageName":"ps","ThreeLetterISOLanguageName":"pus"},{"Name":"fa","DisplayName":"Persian","TwoLetterISOLanguageName":"fa","ThreeLetterISOLanguageName":"fas"},{"Name":"pl","DisplayName":"Polish","TwoLetterISOLanguageName":"pl","ThreeLetterISOLanguageName":"pol"},{"Name":"pt-AO","DisplayName":"português (Angola)","TwoLetterISOLanguageName":"pt","ThreeLetterISOLanguageName":"por"},{"Name":"pa","DisplayName":"Punjabi","TwoLetterISOLanguageName":"pa","ThreeLetterISOLanguageName":"pan"},{"Name":"quz","DisplayName":"Quechua","TwoLetterISOLanguageName":"quz","ThreeLetterISOLanguageName":"qub"},{"Name":"quz-EC","DisplayName":"Quechua (Ecuador)","TwoLetterISOLanguageName":"quz","ThreeLetterISOLanguageName":"que"},{"Name":"quz-PE","DisplayName":"Quechua (Peru)","TwoLetterISOLanguageName":"quz","ThreeLetterISOLanguageName":"qup"},{"Name":"ro","DisplayName":"Romanian","TwoLetterISOLanguageName":"ro","ThreeLetterISOLanguageName":"ron"},{"Name":"rm","DisplayName":"Romansh","TwoLetterISOLanguageName":"rm","ThreeLetterISOLanguageName":"roh"},{"Name":"ru","DisplayName":"Russian","TwoLetterISOLanguageName":"ru","ThreeLetterISOLanguageName":"rus"},{"Name":"sah","DisplayName":"Sakha","TwoLetterISOLanguageName":"sah","ThreeLetterISOLanguageName":"sah"},{"Name":"smn","DisplayName":"Sami (Inari)","TwoLetterISOLanguageName":"smn","ThreeLetterISOLanguageName":"smn"},{"Name":"smj","DisplayName":"Sami (Lule)","TwoLetterISOLanguageName":"smj","ThreeLetterISOLanguageName":"smj"},{"Name":"se","DisplayName":"Sami (Northern)","TwoLetterISOLanguageName":"se","ThreeLetterISOLanguageName":"sme"},{"Name":"sms","DisplayName":"Sami (Skolt)","TwoLetterISOLanguageName":"sms","ThreeLetterISOLanguageName":"sms"},{"Name":"sma","DisplayName":"Sami (Southern)","TwoLetterISOLanguageName":"sma","ThreeLetterISOLanguageName":"sma"},{"Name":"sa","DisplayName":"Sanskrit","TwoLetterISOLanguageName":"sa","ThreeLetterISOLanguageName":"san"},{"Name":"gd","DisplayName":"Scottish Gaelic","TwoLetterISOLanguageName":"gd","ThreeLetterISOLanguageName":"gla"},{"Name":"sr","DisplayName":"Serbian","TwoLetterISOLanguageName":"sr","ThreeLetterISOLanguageName":"srp"},{"Name":"sr-Cyrl-BA","DisplayName":"Serbian (Cyrillic, Bosnia and Herzegovina)","TwoLetterISOLanguageName":"sr","ThreeLetterISOLanguageName":"srn"},{"Name":"sr-Latn-BA","DisplayName":"Serbian (Latin, Bosnia and Herzegovina)","TwoLetterISOLanguageName":"sr","ThreeLetterISOLanguageName":"srs"},{"Name":"nso","DisplayName":"Sesotho sa Leboa","TwoLetterISOLanguageName":"nso","ThreeLetterISOLanguageName":"nso"},{"Name":"tn","DisplayName":"Setswana","TwoLetterISOLanguageName":"tn","ThreeLetterISOLanguageName":"tsn"},{"Name":"sd","DisplayName":"Sindhi","TwoLetterISOLanguageName":"sd","ThreeLetterISOLanguageName":"sin"},{"Name":"si","DisplayName":"Sinhala","TwoLetterISOLanguageName":"si","ThreeLetterISOLanguageName":"sin"},{"Name":"sk","DisplayName":"Slovak","TwoLetterISOLanguageName":"sk","ThreeLetterISOLanguageName":"slk"},{"Name":"sl","DisplayName":"Slovenian","TwoLetterISOLanguageName":"sl","ThreeLetterISOLanguageName":"slv"},{"Name":"so","DisplayName":"Somali","TwoLetterISOLanguageName":"so","ThreeLetterISOLanguageName":"som"},{"Name":"st","DisplayName":"Southern Sotho","TwoLetterISOLanguageName":"st","ThreeLetterISOLanguageName":"sot"},{"Name":"es","DisplayName":"Spanish","TwoLetterISOLanguageName":"es","ThreeLetterISOLanguageName":"spa"},{"Name":"zgh","DisplayName":"Standard Morrocan Tamazight","TwoLetterISOLanguageName":"zgh","ThreeLetterISOLanguageName":"zgh"},{"Name":"sv","DisplayName":"Swedish","TwoLetterISOLanguageName":"sv","ThreeLetterISOLanguageName":"swe"},{"Name":"syr","DisplayName":"Syriac","TwoLetterISOLanguageName":"syr","ThreeLetterISOLanguageName":"syr"},{"Name":"tg","DisplayName":"Tajik","TwoLetterISOLanguageName":"tg","ThreeLetterISOLanguageName":"tgk"},{"Name":"ta","DisplayName":"Tamil","TwoLetterISOLanguageName":"ta","ThreeLetterISOLanguageName":"tam"},{"Name":"tt","DisplayName":"Tatar","TwoLetterISOLanguageName":"tt","ThreeLetterISOLanguageName":"tat"},{"Name":"te","DisplayName":"Telugu","TwoLetterISOLanguageName":"te","ThreeLetterISOLanguageName":"tel"},{"Name":"th","DisplayName":"Thai","TwoLetterISOLanguageName":"th","ThreeLetterISOLanguageName":"tha"},{"Name":"bo","DisplayName":"Tibetan","TwoLetterISOLanguageName":"bo","ThreeLetterISOLanguageName":"bod"},{"Name":"ti","DisplayName":"Tigrinya","TwoLetterISOLanguageName":"ti","ThreeLetterISOLanguageName":"tir"},{"Name":"ts","DisplayName":"Tsonga","TwoLetterISOLanguageName":"ts","ThreeLetterISOLanguageName":"tso"},{"Name":"tr","DisplayName":"Turkish","TwoLetterISOLanguageName":"tr","ThreeLetterISOLanguageName":"tur"},{"Name":"tk","DisplayName":"Turkmen","TwoLetterISOLanguageName":"tk","ThreeLetterISOLanguageName":"tuk"},{"Name":"uk","DisplayName":"Ukrainian","TwoLetterISOLanguageName":"uk","ThreeLetterISOLanguageName":"ukr"},{"Name":"hsb","DisplayName":"Upper Sorbian","TwoLetterISOLanguageName":"hsb","ThreeLetterISOLanguageName":"hsb"},{"Name":"ur","DisplayName":"Urdu","TwoLetterISOLanguageName":"ur","ThreeLetterISOLanguageName":"urd"},{"Name":"ug","DisplayName":"Uyghur","TwoLetterISOLanguageName":"ug","ThreeLetterISOLanguageName":"uig"},{"Name":"uz","DisplayName":"Uzbek","TwoLetterISOLanguageName":"uz","ThreeLetterISOLanguageName":"uzb"},{"Name":"vi","DisplayName":"Vietnamese","TwoLetterISOLanguageName":"vi","ThreeLetterISOLanguageName":"vie"},{"Name":"cy","DisplayName":"Welsh","TwoLetterISOLanguageName":"cy","ThreeLetterISOLanguageName":"cym"},{"Name":"wo","DisplayName":"Wolof","TwoLetterISOLanguageName":"wo","ThreeLetterISOLanguageName":"wol"},{"Name":"ii","DisplayName":"Yi","TwoLetterISOLanguageName":"ii","ThreeLetterISOLanguageName":"iii"},{"Name":"yo","DisplayName":"Yoruba","TwoLetterISOLanguageName":"yo","ThreeLetterISOLanguageName":"yor"}] \ 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 dd770b0c8..c47759e96 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -45,17 +45,16 @@
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<ItemGroup>
- <Reference Include="ImageMagickSharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\ImageMagickSharp.1.0.0.11\lib\net45\ImageMagickSharp.dll</HintPath>
+ <Reference Include="Interfaces.IO">
+ <HintPath>..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll</HintPath>
</Reference>
<Reference Include="MediaBrowser.Naming, Version=1.0.5509.27636, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\MediaBrowser.Naming.1.0.0.32\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">
+ <Reference Include="Mono.Nat, Version=1.2.23.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Mono.Nat.1.2.21.0\lib\net40\Mono.Nat.dll</HintPath>
+ <HintPath>..\packages\Mono.Nat.1.2.23.0\lib\net40\Mono.Nat.dll</HintPath>
</Reference>
<Reference Include="MoreLinq, Version=1.1.17511.0, Culture=neutral, PublicKeyToken=384d532d7e88985d, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
@@ -68,9 +67,9 @@
<Reference Include="ServiceStack.Api.Swagger">
<HintPath>..\ThirdParty\ServiceStack\ServiceStack.Api.Swagger.dll</HintPath>
</Reference>
- <Reference Include="SocketHttpListener, Version=1.0.5554.26260, Culture=neutral, processorArchitecture=MSIL">
+ <Reference Include="SocketHttpListener, Version=1.0.5589.21083, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\SocketHttpListener.1.0.0.3\lib\net45\SocketHttpListener.dll</HintPath>
+ <HintPath>..\packages\SocketHttpListener.1.0.0.6\lib\net45\SocketHttpListener.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@@ -129,10 +128,6 @@
<Compile Include="Devices\DeviceManager.cs" />
<Compile Include="Devices\DeviceRepository.cs" />
<Compile Include="Devices\CameraUploadsFolder.cs" />
- <Compile Include="Drawing\ImageHeader.cs" />
- <Compile Include="Drawing\PercentPlayedDrawer.cs" />
- <Compile Include="Drawing\PlayedIndicatorDrawer.cs" />
- <Compile Include="Drawing\UnplayedCountIndicator.cs" />
<Compile Include="Dto\DtoService.cs" />
<Compile Include="EntryPoints\ActivityLogEntryPoint.cs" />
<Compile Include="EntryPoints\AutomaticRestartEntryPoint.cs" />
@@ -174,13 +169,11 @@
<Compile Include="HttpServer\SocketSharp\SharpWebSocket.cs" />
<Compile Include="HttpServer\StreamWriter.cs" />
<Compile Include="HttpServer\SwaggerService.cs" />
- <Compile Include="Drawing\ImageProcessor.cs" />
<Compile Include="HttpServer\SocketSharp\Extensions.cs" />
<Compile Include="HttpServer\SocketSharp\RequestMono.cs" />
<Compile Include="HttpServer\SocketSharp\WebSocketSharpListener.cs" />
<Compile Include="HttpServer\SocketSharp\WebSocketSharpRequest.cs" />
<Compile Include="HttpServer\SocketSharp\WebSocketSharpResponse.cs" />
- <Compile Include="HttpServer\ThrottledStream.cs" />
<Compile Include="Intros\DefaultIntroProvider.cs" />
<Compile Include="IO\LibraryMonitor.cs" />
<Compile Include="Library\CoreResolutionIgnoreRule.cs" />
@@ -252,8 +245,6 @@
<Compile Include="Persistence\SqliteShrinkMemoryTimer.cs" />
<Compile Include="Persistence\TypeMapper.cs" />
<Compile Include="Photos\BaseDynamicImageProvider.cs" />
- <Compile Include="Photos\DynamicImageHelpers.cs" />
- <Compile Include="UserViews\StripCollageBuilder.cs" />
<Compile Include="Playlists\ManualPlaylistsFolder.cs" />
<Compile Include="Photos\PhotoAlbumImageProvider.cs" />
<Compile Include="Playlists\PlaylistImageProvider.cs" />
@@ -410,7 +401,6 @@
<EmbeddedResource Include="Localization\JavaScript\kk.json" />
<EmbeddedResource Include="Localization\Server\kk.json" />
<EmbeddedResource Include="Localization\countries.json" />
- <EmbeddedResource Include="Localization\cultures.json" />
<EmbeddedResource Include="Localization\JavaScript\da.json" />
<EmbeddedResource Include="Localization\JavaScript\vi.json" />
<EmbeddedResource Include="Localization\Server\da.json" />
@@ -432,9 +422,6 @@
<EmbeddedResource Include="Localization\JavaScript\uk.json" />
<EmbeddedResource Include="Localization\Server\bg_BG.json" />
<EmbeddedResource Include="Localization\Server\uk.json" />
- <EmbeddedResource Include="Drawing\fonts\webdings.ttf" />
- <EmbeddedResource Include="Drawing\fonts\robotoregular.ttf" />
- <EmbeddedResource Include="Drawing\fonts\MontserratLight.otf" />
<None Include="Localization\JavaScript\sl_SI.json" />
<EmbeddedResource Include="Localization\Server\sl_SI.json" />
<None Include="packages.config" />
diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs b/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs
index 56557d6e1..6b99883a5 100644
--- a/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs
+++ b/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs
@@ -151,8 +151,9 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
chapter.ImagePath = path;
changesMade = true;
}
- catch
+ catch (Exception ex)
{
+ _logger.ErrorException("Error extraching chapter images for {0}", ex, string.Join(",", inputPath));
success = false;
break;
}
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
index 12ce60d45..61432d00f 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
@@ -522,7 +522,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
- public IEnumerable<Guid> GetItemsOfType(Type type)
+ public IEnumerable<BaseItem> GetItemsOfType(Type type)
{
if (type == null)
{
@@ -530,7 +530,37 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
CheckDisposed();
-
+
+ using (var cmd = _connection.CreateCommand())
+ {
+ cmd.CommandText = "select type,data from TypedBaseItems where type = @type";
+
+ cmd.Parameters.Add(cmd, "@type", DbType.String).Value = type.FullName;
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
+ {
+ while (reader.Read())
+ {
+ var item = GetItem(reader);
+
+ if (item != null)
+ {
+ yield return item;
+ }
+ }
+ }
+ }
+ }
+
+ public IEnumerable<Guid> GetItemIdsOfType(Type type)
+ {
+ if (type == null)
+ {
+ throw new ArgumentNullException("type");
+ }
+
+ CheckDisposed();
+
using (var cmd = _connection.CreateCommand())
{
cmd.CommandText = "select guid from TypedBaseItems where type = @type";
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs
index e9d7f44ec..293da3f0f 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Persistence;
+using System.Globalization;
+using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using System;
@@ -469,36 +470,38 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
cancellationToken.ThrowIfCancellationRequested();
- _saveStreamCommand.GetParameter(0).Value = id;
- _saveStreamCommand.GetParameter(1).Value = stream.Index;
- _saveStreamCommand.GetParameter(2).Value = stream.Type.ToString();
- _saveStreamCommand.GetParameter(3).Value = stream.Codec;
- _saveStreamCommand.GetParameter(4).Value = stream.Language;
- _saveStreamCommand.GetParameter(5).Value = stream.ChannelLayout;
- _saveStreamCommand.GetParameter(6).Value = stream.Profile;
- _saveStreamCommand.GetParameter(7).Value = stream.AspectRatio;
- _saveStreamCommand.GetParameter(8).Value = stream.Path;
-
- _saveStreamCommand.GetParameter(9).Value = stream.IsInterlaced;
-
- _saveStreamCommand.GetParameter(10).Value = stream.BitRate;
- _saveStreamCommand.GetParameter(11).Value = stream.Channels;
- _saveStreamCommand.GetParameter(12).Value = stream.SampleRate;
-
- _saveStreamCommand.GetParameter(13).Value = stream.IsDefault;
- _saveStreamCommand.GetParameter(14).Value = stream.IsForced;
- _saveStreamCommand.GetParameter(15).Value = stream.IsExternal;
-
- _saveStreamCommand.GetParameter(16).Value = stream.Width;
- _saveStreamCommand.GetParameter(17).Value = stream.Height;
- _saveStreamCommand.GetParameter(18).Value = stream.AverageFrameRate;
- _saveStreamCommand.GetParameter(19).Value = stream.RealFrameRate;
- _saveStreamCommand.GetParameter(20).Value = stream.Level;
- _saveStreamCommand.GetParameter(21).Value = stream.PixelFormat;
- _saveStreamCommand.GetParameter(22).Value = stream.BitDepth;
- _saveStreamCommand.GetParameter(23).Value = stream.IsAnamorphic;
- _saveStreamCommand.GetParameter(24).Value = stream.RefFrames;
- _saveStreamCommand.GetParameter(25).Value = stream.IsCabac;
+ var index = 0;
+
+ _saveStreamCommand.GetParameter(index++).Value = id;
+ _saveStreamCommand.GetParameter(index++).Value = stream.Index;
+ _saveStreamCommand.GetParameter(index++).Value = stream.Type.ToString();
+ _saveStreamCommand.GetParameter(index++).Value = stream.Codec;
+ _saveStreamCommand.GetParameter(index++).Value = stream.Language;
+ _saveStreamCommand.GetParameter(index++).Value = stream.ChannelLayout;
+ _saveStreamCommand.GetParameter(index++).Value = stream.Profile;
+ _saveStreamCommand.GetParameter(index++).Value = stream.AspectRatio;
+ _saveStreamCommand.GetParameter(index++).Value = stream.Path;
+
+ _saveStreamCommand.GetParameter(index++).Value = stream.IsInterlaced;
+
+ _saveStreamCommand.GetParameter(index++).Value = stream.BitRate;
+ _saveStreamCommand.GetParameter(index++).Value = stream.Channels;
+ _saveStreamCommand.GetParameter(index++).Value = stream.SampleRate;
+
+ _saveStreamCommand.GetParameter(index++).Value = stream.IsDefault;
+ _saveStreamCommand.GetParameter(index++).Value = stream.IsForced;
+ _saveStreamCommand.GetParameter(index++).Value = stream.IsExternal;
+
+ _saveStreamCommand.GetParameter(index++).Value = stream.Width;
+ _saveStreamCommand.GetParameter(index++).Value = stream.Height;
+ _saveStreamCommand.GetParameter(index++).Value = stream.AverageFrameRate;
+ _saveStreamCommand.GetParameter(index++).Value = stream.RealFrameRate;
+ _saveStreamCommand.GetParameter(index++).Value = stream.Level;
+ _saveStreamCommand.GetParameter(index++).Value = stream.PixelFormat;
+ _saveStreamCommand.GetParameter(index++).Value = stream.BitDepth;
+ _saveStreamCommand.GetParameter(index++).Value = stream.IsAnamorphic;
+ _saveStreamCommand.GetParameter(index++).Value = stream.RefFrames;
+ _saveStreamCommand.GetParameter(index++).Value = stream.IsCabac;
_saveStreamCommand.Transaction = transaction;
_saveStreamCommand.ExecuteNonQuery();
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs
index f4820f432..743d8fed6 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs
@@ -208,15 +208,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
result.LastErrorMessage = reader.GetString(7);
}
- if (!reader.IsDBNull(8))
- {
- result.MetadataProvidersRefreshed = reader.GetString(8).Split('|').Where(i => !string.IsNullOrEmpty(i)).Select(i => new Guid(i)).ToList();
- }
-
- if (!reader.IsDBNull(9))
- {
- result.ImageProvidersRefreshed = reader.GetString(9).Split('|').Where(i => !string.IsNullOrEmpty(i)).Select(i => new Guid(i)).ToList();
- }
+ // Skip metadata and image providers
if (!reader.IsDBNull(10))
{
@@ -251,8 +243,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveStatusCommand.GetParameter(5).Value = status.DateLastImagesRefresh;
_saveStatusCommand.GetParameter(6).Value = status.LastStatus.ToString();
_saveStatusCommand.GetParameter(7).Value = status.LastErrorMessage;
- _saveStatusCommand.GetParameter(8).Value = string.Join("|", status.MetadataProvidersRefreshed.ToArray());
- _saveStatusCommand.GetParameter(9).Value = string.Join("|", status.ImageProvidersRefreshed.ToArray());
+ _saveStatusCommand.GetParameter(8).Value = string.Empty;
+ _saveStatusCommand.GetParameter(9).Value = string.Empty;
_saveStatusCommand.GetParameter(10).Value = status.ItemDateModified;
_saveStatusCommand.Transaction = transaction;
diff --git a/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs b/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs
index 79a1181ca..15c43213f 100644
--- a/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs
@@ -1,13 +1,12 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Playlists;
using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Server.Implementations.UserViews;
using System;
using System.Collections.Generic;
using System.IO;
@@ -23,12 +22,14 @@ namespace MediaBrowser.Server.Implementations.Photos
protected IFileSystem FileSystem { get; private set; }
protected IProviderManager ProviderManager { get; private set; }
protected IApplicationPaths ApplicationPaths { get; private set; }
+ protected IImageProcessor ImageProcessor { get; set; }
- protected BaseDynamicImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths)
+ protected BaseDynamicImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor)
{
ApplicationPaths = applicationPaths;
ProviderManager = providerManager;
FileSystem = fileSystem;
+ ImageProcessor = imageProcessor;
}
public virtual bool Supports(IHasImages item)
@@ -77,56 +78,23 @@ namespace MediaBrowser.Server.Implementations.Photos
string cacheKey,
CancellationToken cancellationToken)
{
- var stream = await CreateImageAsync(item, itemsWithImages, imageType, 0).ConfigureAwait(false);
+ var outputPath = Path.Combine(ApplicationPaths.TempDirectory, Guid.NewGuid() + ".png");
+ Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
+ var imageCreated = CreateImage(item, itemsWithImages, outputPath, imageType, 0);
- if (stream == null)
+ if (!imageCreated)
{
return ItemUpdateType.None;
}
- if (stream is MemoryStream)
- {
- using (stream)
- {
- stream.Position = 0;
-
- await ProviderManager.SaveImage(item, stream, "image/png", imageType, null, cacheKey, cancellationToken).ConfigureAwait(false);
- }
- }
- else
- {
- using (var ms = new MemoryStream())
- {
- await stream.CopyToAsync(ms).ConfigureAwait(false);
-
- ms.Position = 0;
-
- await ProviderManager.SaveImage(item, ms, "image/png", imageType, null, cacheKey, cancellationToken).ConfigureAwait(false);
- }
- }
+ await ProviderManager.SaveImage(item, outputPath, "image/png", imageType, null, cacheKey, cancellationToken).ConfigureAwait(false);
return ItemUpdateType.ImageUpdate;
}
- public async Task<DynamicImageResponse> GetImage(IHasImages item, ImageType type, CancellationToken cancellationToken)
- {
- var items = await GetItemsWithImages(item).ConfigureAwait(false);
- var cacheKey = GetConfigurationCacheKey(items, item.Name);
-
- var result = await CreateImageAsync(item, items, type, 0).ConfigureAwait(false);
-
- return new DynamicImageResponse
- {
- HasImage = result != null,
- Stream = result,
- InternalCacheKey = cacheKey,
- Format = ImageFormat.Png
- };
- }
-
protected abstract Task<List<BaseItem>> GetItemsWithImages(IHasImages item);
- private const string Version = "18";
+ private const string Version = "32";
protected string GetConfigurationCacheKey(List<BaseItem> items, string itemName)
{
var parts = Version + "_" + (itemName ?? string.Empty) + "_" +
@@ -135,32 +103,47 @@ namespace MediaBrowser.Server.Implementations.Photos
return parts.GetMD5().ToString("N");
}
- protected Task<Stream> GetThumbCollage(IHasImages primaryItem, List<BaseItem> items)
+ protected void CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, bool drawText)
{
- var stream = new StripCollageBuilder(ApplicationPaths).BuildThumbCollage(GetStripCollageImagePaths(items), 960, 540, true, primaryItem.Name);
-
- return Task.FromResult(stream);
+ CreateCollage(primaryItem, items, outputPath, 960, 540, drawText, primaryItem.Name);
}
- private IEnumerable<String> GetStripCollageImagePaths(IEnumerable<BaseItem> items)
+ protected virtual IEnumerable<string> GetStripCollageImagePaths(IHasImages primaryItem, IEnumerable<BaseItem> items)
{
return items
.Select(i => i.GetImagePath(ImageType.Primary) ?? i.GetImagePath(ImageType.Thumb))
.Where(i => !string.IsNullOrWhiteSpace(i));
}
- protected Task<Stream> GetPosterCollage(IHasImages primaryItem, List<BaseItem> items)
+ protected void CreatePosterCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
+ {
+ CreateCollage(primaryItem, items, outputPath, 600, 900, true, primaryItem.Name);
+ }
+
+ protected void CreateSquareCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, bool drawText)
{
- var stream = new StripCollageBuilder(ApplicationPaths).BuildPosterCollage(GetStripCollageImagePaths(items), 600, 900, true, primaryItem.Name);
+ CreateCollage(primaryItem, items, outputPath, 800, 800, drawText, primaryItem.Name);
+ }
- return Task.FromResult(stream);
+ protected void CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height, bool drawText, string text)
+ {
+ CreateCollage(primaryItem, items, outputPath, width, height, drawText, text);
}
- protected Task<Stream> GetSquareCollage(IHasImages primaryItem, List<BaseItem> items)
+ private void CreateCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height, bool drawText, string text)
{
- var stream = new StripCollageBuilder(ApplicationPaths).BuildSquareCollage(GetStripCollageImagePaths(items), 800, 800, true, primaryItem.Name);
+ Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
+
+ var options = new ImageCollageOptions
+ {
+ Height = height,
+ Width = width,
+ OutputPath = outputPath,
+ Text = drawText ? text : null,
+ InputPaths = GetStripCollageImagePaths(primaryItem, items).ToArray()
+ };
- return Task.FromResult(stream);
+ ImageProcessor.CreateImageCollage(options);
}
public string Name
@@ -168,26 +151,41 @@ namespace MediaBrowser.Server.Implementations.Photos
get { return "Dynamic Image Provider"; }
}
- protected virtual async Task<Stream> CreateImageAsync(IHasImages item,
+ protected virtual bool CreateImage(IHasImages item,
List<BaseItem> itemsWithImages,
+ string outputPath,
ImageType imageType,
int imageIndex)
{
if (itemsWithImages.Count == 0)
{
- return null;
+ return false;
}
+ var drawText = !(item is UserView);
+
if (imageType == ImageType.Thumb)
{
- return await GetThumbCollage(item, itemsWithImages).ConfigureAwait(false);
+ CreateThumbCollage(item, itemsWithImages, outputPath, drawText);
+ return true;
}
if (imageType == ImageType.Primary)
{
- return item is PhotoAlbum || item is Playlist ?
- await GetSquareCollage(item, itemsWithImages).ConfigureAwait(false) :
- await GetPosterCollage(item, itemsWithImages).ConfigureAwait(false);
+ if (item is UserView)
+ {
+ CreateSquareCollage(item, itemsWithImages, outputPath, drawText);
+ }
+ else if (item is PhotoAlbum || item is Playlist)
+ {
+ CreateSquareCollage(item, itemsWithImages, outputPath, drawText);
+ }
+ else
+ {
+ CreatePosterCollage(item, itemsWithImages, outputPath);
+ }
+
+ return true;
}
throw new ArgumentException("Unexpected image type");
@@ -230,14 +228,13 @@ namespace MediaBrowser.Server.Implementations.Photos
protected List<BaseItem> GetFinalItems(List<BaseItem> items)
{
- // Rotate the images no more than once per week
return GetFinalItems(items, 4);
}
protected virtual List<BaseItem> GetFinalItems(List<BaseItem> items, int limit)
{
// Rotate the images once every x days
- var random = DateTime.Now.DayOfYear % 4;
+ var random = DateTime.Now.DayOfYear % 5;
return items
.OrderBy(i => (random + "" + items.IndexOf(i)).GetMD5())
diff --git a/MediaBrowser.Server.Implementations/Photos/DynamicImageHelpers.cs b/MediaBrowser.Server.Implementations/Photos/DynamicImageHelpers.cs
deleted file mode 100644
index 7f8435097..000000000
--- a/MediaBrowser.Server.Implementations/Photos/DynamicImageHelpers.cs
+++ /dev/null
@@ -1,132 +0,0 @@
-using ImageMagickSharp;
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.IO;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Server.Implementations.Photos
-{
- public static class DynamicImageHelpers
- {
- public static async Task<Stream> GetThumbCollage(List<string> files,
- IFileSystem fileSystem,
- int width,
- int height, IApplicationPaths appPaths)
- {
- if (files.Any(string.IsNullOrWhiteSpace))
- {
- throw new ArgumentException("Empty file found in files list");
- }
-
- if (files.Count == 0)
- {
- return null;
- }
-
- if (files.Count < 3)
- {
- return await GetSingleImage(files, fileSystem).ConfigureAwait(false);
- }
-
- const int rows = 1;
- const int cols = 3;
-
- int cellWidth = 2 * (width / 3);
- int cellHeight = height;
- var index = 0;
-
- using (var wand = new MagickWand(width, height, new PixelWand(ColorName.None, 1)))
- {
- for (var row = 0; row < rows; row++)
- {
- for (var col = 0; col < cols; col++)
- {
- var x = col * (cellWidth / 2);
- var y = row * cellHeight;
-
- if (files.Count > index)
- {
- using (var innerWand = new MagickWand(files[index]))
- {
- innerWand.CurrentImage.ResizeImage(cellWidth, cellHeight);
- wand.CurrentImage.CompositeImage(innerWand, CompositeOperator.OverCompositeOp, x, y);
- }
- }
-
- index++;
- }
- }
-
- return GetStream(wand, appPaths);
- }
- }
-
- public static async Task<Stream> GetSquareCollage(List<string> files,
- IFileSystem fileSystem,
- int size, IApplicationPaths appPaths)
- {
- if (files.Any(string.IsNullOrWhiteSpace))
- {
- throw new ArgumentException("Empty file found in files list");
- }
-
- if (files.Count == 0)
- {
- return null;
- }
-
- if (files.Count < 4)
- {
- return await GetSingleImage(files, fileSystem).ConfigureAwait(false);
- }
-
- const int rows = 2;
- const int cols = 2;
-
- int singleSize = size / 2;
- var index = 0;
-
- using (var wand = new MagickWand(size, size, new PixelWand(ColorName.None, 1)))
- {
- for (var row = 0; row < rows; row++)
- {
- for (var col = 0; col < cols; col++)
- {
- var x = col * singleSize;
- var y = row * singleSize;
-
- using (var innerWand = new MagickWand(files[index]))
- {
- innerWand.CurrentImage.ResizeImage(singleSize, singleSize);
- wand.CurrentImage.CompositeImage(innerWand, CompositeOperator.OverCompositeOp, x, y);
- }
-
- index++;
- }
- }
-
- return GetStream(wand, appPaths);
- }
- }
-
- private static Task<Stream> GetSingleImage(List<string> files, IFileSystem fileSystem)
- {
- return Task.FromResult<Stream>(fileSystem.GetFileStream(files[0], FileMode.Open, FileAccess.Read, FileShare.Read));
- }
-
- internal static Stream GetStream(MagickWand image, IApplicationPaths appPaths)
- {
- var tempFile = Path.Combine(appPaths.TempDirectory, Guid.NewGuid().ToString("N") + ".png");
-
- Directory.CreateDirectory(Path.GetDirectoryName(tempFile));
-
- image.CurrentImage.CompressionQuality = 100;
- image.SaveImage(tempFile);
-
- return File.OpenRead(tempFile);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Photos/PhotoAlbumImageProvider.cs b/MediaBrowser.Server.Implementations/Photos/PhotoAlbumImageProvider.cs
index 73d9183a5..8c142b646 100644
--- a/MediaBrowser.Server.Implementations/Photos/PhotoAlbumImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/Photos/PhotoAlbumImageProvider.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
using System.Collections.Generic;
@@ -8,18 +9,18 @@ using System.Threading.Tasks;
namespace MediaBrowser.Server.Implementations.Photos
{
- public class PhotoAlbumImageProvider : BaseDynamicImageProvider<PhotoAlbum>
- {
- public PhotoAlbumImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths) : base(fileSystem, providerManager, applicationPaths)
- {
- }
+ //public class PhotoAlbumImageProvider : BaseDynamicImageProvider<PhotoAlbum>
+ //{
+ // public PhotoAlbumImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor) : base(fileSystem, providerManager, applicationPaths, imageProcessor)
+ // {
+ // }
- protected override Task<List<BaseItem>> GetItemsWithImages(IHasImages item)
- {
- var photoAlbum = (PhotoAlbum)item;
- var items = GetFinalItems(photoAlbum.GetRecursiveChildren(i => i is Photo).ToList());
+ // protected override Task<List<BaseItem>> GetItemsWithImages(IHasImages item)
+ // {
+ // var photoAlbum = (PhotoAlbum)item;
+ // var items = GetFinalItems(photoAlbum.Children.ToList());
- return Task.FromResult(items);
- }
- }
+ // return Task.FromResult(items);
+ // }
+ //}
}
diff --git a/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs b/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs
index 980c3d14a..2f3a1dd0c 100644
--- a/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs
+++ b/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs
@@ -45,11 +45,11 @@ namespace MediaBrowser.Server.Implementations.Playlists
}
}
- public class PlaylistssDynamicFolder : IVirtualFolderCreator
+ public class PlaylistsDynamicFolder : IVirtualFolderCreator
{
private readonly IApplicationPaths _appPaths;
- public PlaylistssDynamicFolder(IApplicationPaths appPaths)
+ public PlaylistsDynamicFolder(IApplicationPaths appPaths)
{
_appPaths = appPaths;
}
diff --git a/MediaBrowser.Server.Implementations/Playlists/PlaylistImageProvider.cs b/MediaBrowser.Server.Implementations/Playlists/PlaylistImageProvider.cs
index 81f9438b9..dcd9d21ea 100644
--- a/MediaBrowser.Server.Implementations/Playlists/PlaylistImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/Playlists/PlaylistImageProvider.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.TV;
@@ -16,7 +17,7 @@ namespace MediaBrowser.Server.Implementations.Playlists
{
public class PlaylistImageProvider : BaseDynamicImageProvider<Playlist>
{
- public PlaylistImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths) : base(fileSystem, providerManager, applicationPaths)
+ public PlaylistImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor) : base(fileSystem, providerManager, applicationPaths, imageProcessor)
{
}
diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
index 7f5033b98..112778ec8 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
@@ -305,12 +305,9 @@ namespace MediaBrowser.Server.Implementations.Session
}
}
- private async Task<MediaSourceInfo> GetMediaSource(IHasMediaSources item, string mediaSourceId)
+ private Task<MediaSourceInfo> GetMediaSource(IHasMediaSources item, string mediaSourceId)
{
- var sources = await _mediaSourceManager.GetPlayackMediaSources(item.Id.ToString("N"), false, CancellationToken.None)
- .ConfigureAwait(false);
-
- return sources.FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));
+ return _mediaSourceManager.GetMediaSource(item, mediaSourceId, false);
}
/// <summary>
diff --git a/MediaBrowser.Server.Implementations/Sync/AppSyncProvider.cs b/MediaBrowser.Server.Implementations/Sync/AppSyncProvider.cs
index 99d758233..7b1fa4dec 100644
--- a/MediaBrowser.Server.Implementations/Sync/AppSyncProvider.cs
+++ b/MediaBrowser.Server.Implementations/Sync/AppSyncProvider.cs
@@ -44,7 +44,7 @@ namespace MediaBrowser.Server.Implementations.Sync
public string Name
{
- get { return "App Sync"; }
+ get { return "Mobile Sync"; }
}
public IEnumerable<SyncTarget> GetAllSyncTargets()
diff --git a/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs b/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs
index 73400f834..992f1d16c 100644
--- a/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs
+++ b/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs
@@ -195,17 +195,39 @@ namespace MediaBrowser.Server.Implementations.Sync
}
};
- var maxAudioChannels = supportsAc3 || supportsDca ? "5" : "2";
codecProfiles.Add(new CodecProfile
{
Type = CodecType.VideoAudio,
+ Codec = "ac3",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
- Value = maxAudioChannels,
+ Value = "6",
+ IsRequired = false
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.Equals,
+ Property = ProfileConditionValue.IsSecondaryAudio,
+ Value = "false",
+ IsRequired = false
+ }
+ }
+ });
+ codecProfiles.Add(new CodecProfile
+ {
+ Type = CodecType.VideoAudio,
+ Codec = "aac,mp3",
+ Conditions = new[]
+ {
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.AudioChannels,
+ Value = "2",
IsRequired = true
},
new ProfileCondition
diff --git a/MediaBrowser.Server.Implementations/Sync/MediaSync.cs b/MediaBrowser.Server.Implementations/Sync/MediaSync.cs
index 5bc8b8088..96e996ff1 100644
--- a/MediaBrowser.Server.Implementations/Sync/MediaSync.cs
+++ b/MediaBrowser.Server.Implementations/Sync/MediaSync.cs
@@ -1,7 +1,8 @@
-using System.Globalization;
+using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Progress;
using MediaBrowser.Controller;
+using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Sync;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
@@ -10,12 +11,14 @@ using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Sync;
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using Interfaces.IO;
namespace MediaBrowser.Server.Implementations.Sync
{
@@ -25,13 +28,18 @@ namespace MediaBrowser.Server.Implementations.Sync
private readonly IServerApplicationHost _appHost;
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
+ private readonly IConfigurationManager _config;
- public MediaSync(ILogger logger, ISyncManager syncManager, IServerApplicationHost appHost, IFileSystem fileSystem)
+ public const string PathSeparatorString = "/";
+ public const char PathSeparatorChar = '/';
+
+ public MediaSync(ILogger logger, ISyncManager syncManager, IServerApplicationHost appHost, IFileSystem fileSystem, IConfigurationManager config)
{
_logger = logger;
_syncManager = syncManager;
_appHost = appHost;
_fileSystem = fileSystem;
+ _config = config;
}
public async Task Sync(IServerSyncProvider provider,
@@ -67,7 +75,24 @@ namespace MediaBrowser.Server.Implementations.Sync
SyncTarget target,
CancellationToken cancellationToken)
{
- var jobItemIds = await dataProvider.GetSyncJobItemIds(target, serverId).ConfigureAwait(false);
+ var localItems = await dataProvider.GetLocalItems(target, serverId).ConfigureAwait(false);
+ var remoteFiles = await provider.GetFiles(new FileQuery(), target, cancellationToken).ConfigureAwait(false);
+ var remoteIds = remoteFiles.Items.Select(i => i.Id).ToList();
+
+ var jobItemIds = new List<string>();
+
+ foreach (var localItem in localItems)
+ {
+ // TODO: Remove this after a while
+ if (string.IsNullOrWhiteSpace(localItem.FileId))
+ {
+ jobItemIds.Add(localItem.SyncJobItemId);
+ }
+ else if (remoteIds.Contains(localItem.FileId, StringComparer.OrdinalIgnoreCase))
+ {
+ jobItemIds.Add(localItem.SyncJobItemId);
+ }
+ }
var result = await _syncManager.SyncData(new SyncDataRequest
{
@@ -152,12 +177,14 @@ namespace MediaBrowser.Server.Implementations.Sync
var transferSuccess = false;
Exception transferException = null;
+ var options = _config.GetSyncOptions();
+
try
{
var fileTransferProgress = new ActionableProgress<double>();
fileTransferProgress.RegisterAction(pct => progress.Report(pct * .92));
- var sendFileResult = await SendFile(provider, internalSyncJobItem.OutputPath, localItem.LocalPath, target, fileTransferProgress, cancellationToken).ConfigureAwait(false);
+ var sendFileResult = await SendFile(provider, internalSyncJobItem.OutputPath, localItem.LocalPath.Split(PathSeparatorChar), target, options, fileTransferProgress, cancellationToken).ConfigureAwait(false);
if (localItem.Item.MediaSources != null)
{
@@ -171,6 +198,8 @@ namespace MediaBrowser.Server.Implementations.Sync
}
}
+ localItem.FileId = sendFileResult.Id;
+
// Create db record
await dataProvider.AddOrUpdate(target, localItem).ConfigureAwait(false);
@@ -179,7 +208,7 @@ namespace MediaBrowser.Server.Implementations.Sync
var mediaSource = localItem.Item.MediaSources.FirstOrDefault();
if (mediaSource != null)
{
- await SendSubtitles(localItem, mediaSource, provider, dataProvider, target, cancellationToken).ConfigureAwait(false);
+ await SendSubtitles(localItem, mediaSource, provider, dataProvider, target, options, cancellationToken).ConfigureAwait(false);
}
}
@@ -207,7 +236,7 @@ namespace MediaBrowser.Server.Implementations.Sync
}
}
- private async Task SendSubtitles(LocalItem localItem, MediaSourceInfo mediaSource, IServerSyncProvider provider, ISyncDataProvider dataProvider, SyncTarget target, CancellationToken cancellationToken)
+ private async Task SendSubtitles(LocalItem localItem, MediaSourceInfo mediaSource, IServerSyncProvider provider, ISyncDataProvider dataProvider, SyncTarget target, SyncOptions options, CancellationToken cancellationToken)
{
var failedSubtitles = new List<MediaStream>();
var requiresSave = false;
@@ -219,13 +248,13 @@ namespace MediaBrowser.Server.Implementations.Sync
try
{
var remotePath = GetRemoteSubtitlePath(localItem, mediaStream, provider, target);
- var sendFileResult = await SendFile(provider, mediaStream.Path, remotePath, target, new Progress<double>(), cancellationToken).ConfigureAwait(false);
+ var sendFileResult = await SendFile(provider, mediaStream.Path, remotePath, target, options, new Progress<double>(), cancellationToken).ConfigureAwait(false);
// This is the path that will be used when talking to the provider
- mediaStream.ExternalId = remotePath;
+ mediaStream.ExternalId = sendFileResult.Id;
// Keep track of all additional files for cleanup later.
- localItem.AdditionalFiles.Add(remotePath);
+ localItem.AdditionalFiles.Add(sendFileResult.Id);
// This is the public path clients will use
mediaStream.Path = sendFileResult.Path;
@@ -250,17 +279,15 @@ namespace MediaBrowser.Server.Implementations.Sync
}
}
- private string GetRemoteSubtitlePath(LocalItem item, MediaStream stream, IServerSyncProvider provider, SyncTarget target)
+ private string[] GetRemoteSubtitlePath(LocalItem item, MediaStream stream, IServerSyncProvider provider, SyncTarget target)
{
- var path = item.LocalPath;
-
var filename = GetSubtitleSaveFileName(item, stream.Language, stream.IsForced) + "." + stream.Codec.ToLower();
- var parentPath = provider.GetParentDirectoryPath(path, target);
-
- path = Path.Combine(parentPath, filename);
+ var pathParts = item.LocalPath.Split(PathSeparatorChar);
+ var list = pathParts.Take(pathParts.Length - 1).ToList();
+ list.Add(filename);
- return path;
+ return list.ToArray();
}
private string GetSubtitleSaveFileName(LocalItem item, string language, bool isForced)
@@ -289,17 +316,21 @@ namespace MediaBrowser.Server.Implementations.Sync
SyncTarget target,
CancellationToken cancellationToken)
{
- var localItems = await dataProvider.GetCachedItemsBySyncJobItemId(target, serverId, syncJobItemId);
+ var localItems = await dataProvider.GetItemsBySyncJobItemId(target, serverId, syncJobItemId);
foreach (var localItem in localItems)
{
var files = localItem.AdditionalFiles.ToList();
- files.Insert(0, localItem.LocalPath);
+
+ // TODO: Remove this. Have to check it for now since this is a new property
+ if (!string.IsNullOrWhiteSpace(localItem.FileId))
+ {
+ files.Insert(0, localItem.FileId);
+ }
foreach (var file in files)
{
_logger.Debug("Removing {0} from {1}.", file, target.Name);
-
await provider.DeleteFile(file, target, cancellationToken).ConfigureAwait(false);
}
@@ -307,12 +338,19 @@ namespace MediaBrowser.Server.Implementations.Sync
}
}
- private async Task<SyncedFileInfo> SendFile(IServerSyncProvider provider, string inputPath, string remotePath, SyncTarget target, IProgress<double> progress, CancellationToken cancellationToken)
+ private async Task<SyncedFileInfo> SendFile(IServerSyncProvider provider, string inputPath, string[] pathParts, SyncTarget target, SyncOptions options, IProgress<double> progress, CancellationToken cancellationToken)
{
- _logger.Debug("Sending {0} to {1}. Remote path: {2}", inputPath, provider.Name, remotePath);
- using (var stream = _fileSystem.GetFileStream(inputPath, FileMode.Open, FileAccess.Read, FileShare.Read, true))
+ _logger.Debug("Sending {0} to {1}. Remote path: {2}", inputPath, provider.Name, string.Join("/", pathParts));
+ using (var fileStream = _fileSystem.GetFileStream(inputPath, FileMode.Open, FileAccess.Read, FileShare.Read, true))
{
- return await provider.SendFile(stream, remotePath, target, progress, cancellationToken).ConfigureAwait(false);
+ Stream stream = fileStream;
+
+ if (options.UploadSpeedLimitBytes > 0 && provider is IRemoteSyncProvider)
+ {
+ stream = new ThrottledStream(stream, options.UploadSpeedLimitBytes);
+ }
+
+ return await provider.SendFile(stream, pathParts, target, progress, cancellationToken).ConfigureAwait(false);
}
}
@@ -336,7 +374,7 @@ namespace MediaBrowser.Server.Implementations.Sync
var path = GetDirectoryPath(provider, job, syncedItem, libraryItem, serverName);
path.Add(GetLocalFileName(provider, libraryItem, originalFileName));
- var localPath = provider.GetFullPath(path, target);
+ var localPath = string.Join(PathSeparatorString, path.ToArray());
foreach (var mediaSource in libraryItem.MediaSources)
{
diff --git a/MediaBrowser.Server.Implementations/Sync/MultiProviderSync.cs b/MediaBrowser.Server.Implementations/Sync/MultiProviderSync.cs
index a8bc24c2a..6f09e96f0 100644
--- a/MediaBrowser.Server.Implementations/Sync/MultiProviderSync.cs
+++ b/MediaBrowser.Server.Implementations/Sync/MultiProviderSync.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
using MediaBrowser.Common.Progress;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Sync;
@@ -18,13 +19,15 @@ namespace MediaBrowser.Server.Implementations.Sync
private readonly IServerApplicationHost _appHost;
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
+ private readonly IConfigurationManager _config;
- public MultiProviderSync(SyncManager syncManager, IServerApplicationHost appHost, ILogger logger, IFileSystem fileSystem)
+ public MultiProviderSync(SyncManager syncManager, IServerApplicationHost appHost, ILogger logger, IFileSystem fileSystem, IConfigurationManager config)
{
_syncManager = syncManager;
_appHost = appHost;
_logger = logger;
_fileSystem = fileSystem;
+ _config = config;
}
public async Task Sync(IEnumerable<IServerSyncProvider> providers, IProgress<double> progress, CancellationToken cancellationToken)
@@ -56,7 +59,7 @@ namespace MediaBrowser.Server.Implementations.Sync
var dataProvider = _syncManager.GetDataProvider(target.Item1, target.Item2);
- await new MediaSync(_logger, _syncManager, _appHost, _fileSystem)
+ await new MediaSync(_logger, _syncManager, _appHost, _fileSystem, _config)
.Sync(target.Item1, dataProvider, target.Item2, innerProgress, cancellationToken)
.ConfigureAwait(false);
diff --git a/MediaBrowser.Server.Implementations/Sync/ServerSyncScheduledTask.cs b/MediaBrowser.Server.Implementations/Sync/ServerSyncScheduledTask.cs
index 148602bd4..9477a23f1 100644
--- a/MediaBrowser.Server.Implementations/Sync/ServerSyncScheduledTask.cs
+++ b/MediaBrowser.Server.Implementations/Sync/ServerSyncScheduledTask.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Sync;
@@ -17,13 +18,15 @@ namespace MediaBrowser.Server.Implementations.Sync
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
private readonly IServerApplicationHost _appHost;
+ private readonly IConfigurationManager _config;
- public ServerSyncScheduledTask(ISyncManager syncManager, ILogger logger, IFileSystem fileSystem, IServerApplicationHost appHost)
+ public ServerSyncScheduledTask(ISyncManager syncManager, ILogger logger, IFileSystem fileSystem, IServerApplicationHost appHost, IConfigurationManager config)
{
_syncManager = syncManager;
_logger = logger;
_fileSystem = fileSystem;
_appHost = appHost;
+ _config = config;
}
public string Name
@@ -46,7 +49,7 @@ namespace MediaBrowser.Server.Implementations.Sync
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
{
- return new MultiProviderSync((SyncManager)_syncManager, _appHost, _logger, _fileSystem)
+ return new MultiProviderSync((SyncManager)_syncManager, _appHost, _logger, _fileSystem, _config)
.Sync(ServerSyncProviders, progress, cancellationToken);
}
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
index 271b2bb39..fd4092974 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
@@ -67,9 +67,10 @@ namespace MediaBrowser.Server.Implementations.Sync
var items = (await GetItemsForSync(job.Category, job.ParentId, job.RequestedItemIds, user, job.UnwatchedOnly).ConfigureAwait(false))
.ToList();
- var jobItems = _syncRepo.GetJobItems(new SyncJobItemQuery
+ var jobItems = _syncManager.GetJobItems(new SyncJobItemQuery
{
- JobId = job.Id
+ JobId = job.Id,
+ AddMetadata = false
}).Items.ToList();
@@ -140,9 +141,10 @@ namespace MediaBrowser.Server.Implementations.Sync
throw new ArgumentNullException("job");
}
- var result = _syncRepo.GetJobItems(new SyncJobItemQuery
+ var result = _syncManager.GetJobItems(new SyncJobItemQuery
{
- JobId = job.Id
+ JobId = job.Id,
+ AddMetadata = false
});
return UpdateJobStatus(job, result.Items.ToList());
@@ -362,9 +364,10 @@ namespace MediaBrowser.Server.Implementations.Sync
await EnsureSyncJobItems(null, cancellationToken).ConfigureAwait(false);
// If it already has a converting status then is must have been aborted during conversion
- var result = _syncRepo.GetJobItems(new SyncJobItemQuery
+ var result = _syncManager.GetJobItems(new SyncJobItemQuery
{
- Statuses = new SyncJobItemStatus[] { SyncJobItemStatus.Queued, SyncJobItemStatus.Converting }
+ Statuses = new[] { SyncJobItemStatus.Queued, SyncJobItemStatus.Converting },
+ AddMetadata = false
});
await SyncJobItems(result.Items, true, progress, cancellationToken).ConfigureAwait(false);
@@ -384,13 +387,14 @@ namespace MediaBrowser.Server.Implementations.Sync
await EnsureSyncJobItems(targetId, cancellationToken).ConfigureAwait(false);
// If it already has a converting status then is must have been aborted during conversion
- var result = _syncRepo.GetJobItems(new SyncJobItemQuery
+ var result = _syncManager.GetJobItems(new SyncJobItemQuery
{
- Statuses = new SyncJobItemStatus[] { SyncJobItemStatus.Queued, SyncJobItemStatus.Converting },
- TargetId = targetId
+ Statuses = new[] { SyncJobItemStatus.Queued, SyncJobItemStatus.Converting },
+ TargetId = targetId,
+ AddMetadata = false
});
- await SyncJobItems(result.Items, true, progress, cancellationToken).ConfigureAwait(false);
+ await SyncJobItems(result.Items, enableConversion, progress, cancellationToken).ConfigureAwait(false);
}
public async Task SyncJobItems(SyncJobItem[] items, bool enableConversion, IProgress<double> progress, CancellationToken cancellationToken)
@@ -452,17 +456,18 @@ namespace MediaBrowser.Server.Implementations.Sync
jobItem.Progress = 0;
+ var syncOptions = _config.GetSyncOptions();
var user = _userManager.GetUserById(job.UserId);
var video = item as Video;
if (video != null)
{
- await Sync(jobItem, job, video, user, enableConversion, progress, cancellationToken).ConfigureAwait(false);
+ await Sync(jobItem, job, video, user, enableConversion, syncOptions, progress, cancellationToken).ConfigureAwait(false);
}
else if (item is Audio)
{
- await Sync(jobItem, job, (Audio)item, user, enableConversion, progress, cancellationToken).ConfigureAwait(false);
+ await Sync(jobItem, job, (Audio)item, user, enableConversion, syncOptions, progress, cancellationToken).ConfigureAwait(false);
}
else if (item is Photo)
@@ -476,7 +481,7 @@ namespace MediaBrowser.Server.Implementations.Sync
}
}
- private async Task Sync(SyncJobItem jobItem, SyncJob job, Video item, User user, bool enableConversion, IProgress<double> progress, CancellationToken cancellationToken)
+ private async Task Sync(SyncJobItem jobItem, SyncJob job, Video item, User user, bool enableConversion, SyncOptions syncOptions, IProgress<double> progress, CancellationToken cancellationToken)
{
var jobOptions = _syncManager.GetVideoOptions(jobItem, job);
var conversionOptions = new VideoOptions
@@ -489,7 +494,7 @@ namespace MediaBrowser.Server.Implementations.Sync
conversionOptions.ItemId = item.Id.ToString("N");
conversionOptions.MediaSources = _mediaSourceManager.GetStaticMediaSources(item, false, user).ToList();
- var streamInfo = new StreamBuilder().BuildVideoItem(conversionOptions);
+ var streamInfo = new StreamBuilder(_logger).BuildVideoItem(conversionOptions);
var mediaSource = streamInfo.MediaSource;
// No sense creating external subs if we're already burning one into the video
@@ -538,7 +543,9 @@ namespace MediaBrowser.Server.Implementations.Sync
jobItem.OutputPath = await _mediaEncoder.EncodeVideo(new EncodingJobOptions(streamInfo, conversionOptions.Profile)
{
- OutputDirectory = jobItem.TemporaryPath
+ OutputDirectory = jobItem.TemporaryPath,
+ CpuCoreLimit = syncOptions.TranscodingCpuCoreLimit,
+ ReadInputAtNativeFramerate = !syncOptions.EnableFullSpeedTranscoding
}, innerProgress, cancellationToken);
}
@@ -673,7 +680,7 @@ namespace MediaBrowser.Server.Implementations.Sync
private const int DatabaseProgressUpdateIntervalSeconds = 2;
- private async Task Sync(SyncJobItem jobItem, SyncJob job, Audio item, User user, bool enableConversion, IProgress<double> progress, CancellationToken cancellationToken)
+ private async Task Sync(SyncJobItem jobItem, SyncJob job, Audio item, User user, bool enableConversion, SyncOptions syncOptions, IProgress<double> progress, CancellationToken cancellationToken)
{
var jobOptions = _syncManager.GetAudioOptions(jobItem, job);
var conversionOptions = new AudioOptions
@@ -686,7 +693,7 @@ namespace MediaBrowser.Server.Implementations.Sync
conversionOptions.ItemId = item.Id.ToString("N");
conversionOptions.MediaSources = _mediaSourceManager.GetStaticMediaSources(item, false, user).ToList();
- var streamInfo = new StreamBuilder().BuildAudioItem(conversionOptions);
+ var streamInfo = new StreamBuilder(_logger).BuildAudioItem(conversionOptions);
var mediaSource = streamInfo.MediaSource;
jobItem.MediaSourceId = streamInfo.MediaSourceId;
@@ -721,7 +728,8 @@ namespace MediaBrowser.Server.Implementations.Sync
jobItem.OutputPath = await _mediaEncoder.EncodeAudio(new EncodingJobOptions(streamInfo, conversionOptions.Profile)
{
- OutputDirectory = jobItem.TemporaryPath
+ OutputDirectory = jobItem.TemporaryPath,
+ CpuCoreLimit = syncOptions.TranscodingCpuCoreLimit
}, innerProgress, cancellationToken);
}
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs
index 102218979..0e4a3bcf1 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs
@@ -182,19 +182,21 @@ namespace MediaBrowser.Server.Implementations.Sync
await processor.EnsureJobItems(job).ConfigureAwait(false);
// If it already has a converting status then is must have been aborted during conversion
- var jobItemsResult = _repo.GetJobItems(new SyncJobItemQuery
+ var jobItemsResult = GetJobItems(new SyncJobItemQuery
{
- Statuses = new SyncJobItemStatus[] { SyncJobItemStatus.Queued, SyncJobItemStatus.Converting },
- JobId = jobId
+ Statuses = new[] { SyncJobItemStatus.Queued, SyncJobItemStatus.Converting },
+ JobId = jobId,
+ AddMetadata = false
});
await processor.SyncJobItems(jobItemsResult.Items, false, new Progress<double>(), CancellationToken.None)
.ConfigureAwait(false);
- jobItemsResult = _repo.GetJobItems(new SyncJobItemQuery
+ jobItemsResult = GetJobItems(new SyncJobItemQuery
{
- Statuses = new SyncJobItemStatus[] { SyncJobItemStatus.Queued, SyncJobItemStatus.Converting },
- JobId = jobId
+ Statuses = new[] { SyncJobItemStatus.Queued, SyncJobItemStatus.Converting },
+ JobId = jobId,
+ AddMetadata = false
});
var returnResult = new SyncJobCreationResult
@@ -510,12 +512,7 @@ namespace MediaBrowser.Server.Implementations.Sync
var video = item as Video;
if (video != null)
{
- if (video.VideoType == VideoType.Iso)
- {
- return false;
- }
-
- if (video.VideoType == VideoType.BluRay || video.VideoType == VideoType.Dvd || video.VideoType == VideoType.HdDvd)
+ if (video.VideoType == VideoType.Iso || video.VideoType == VideoType.HdDvd)
{
return false;
}
@@ -550,7 +547,7 @@ namespace MediaBrowser.Server.Implementations.Sync
}
}
- if (item is LiveTvChannel || item is IChannelItem || item is ILiveTvRecording)
+ if (item is LiveTvChannel || item is IChannelItem)
{
return false;
}
@@ -564,7 +561,7 @@ namespace MediaBrowser.Server.Implementations.Sync
return true;
}
- return item.LocationType == LocationType.FileSystem || item is Season || item is ILiveTvRecording;
+ return item.LocationType == LocationType.FileSystem || item is Season;
}
private string GetDefaultName(BaseItem item)
@@ -726,14 +723,19 @@ namespace MediaBrowser.Server.Implementations.Sync
TargetId = targetId,
Statuses = new[]
{
- SyncJobItemStatus.ReadyToTransfer
+ SyncJobItemStatus.ReadyToTransfer,
+ SyncJobItemStatus.Transferring
}
});
- return jobItemResult.Items
+ var readyItems = jobItemResult.Items
.Select(GetJobItemInfo)
.Where(i => i != null)
.ToList();
+
+ _logger.Debug("Returning {0} ready sync items for targetId {1}", readyItems.Count, targetId);
+
+ return readyItems;
}
public async Task<SyncDataResponse> SyncData(SyncDataRequest request)
@@ -753,6 +755,11 @@ namespace MediaBrowser.Server.Implementations.Sync
foreach (var jobItem in jobItemResult.Items)
{
+ var requiresSaving = false;
+ var removeFromDevice = false;
+
+ var libraryItem = _libraryManager.GetItemById(jobItem.ItemId);
+
if (request.LocalItemIds.Contains(jobItem.ItemId, StringComparer.OrdinalIgnoreCase))
{
var job = _repo.GetJob(jobItem.JobId);
@@ -761,36 +768,55 @@ namespace MediaBrowser.Server.Implementations.Sync
if (jobItem.IsMarkedForRemoval)
{
// Tell the device to remove it since it has been marked for removal
- response.ItemIdsToRemove.Add(jobItem.ItemId);
+ _logger.Debug("Adding ItemIdsToRemove {0} because IsMarkedForRemoval is set.", jobItem.ItemId);
+ removeFromDevice = true;
}
else if (user == null)
{
// Tell the device to remove it since the user is gone now
- response.ItemIdsToRemove.Add(jobItem.ItemId);
+ _logger.Debug("Adding ItemIdsToRemove {0} because the user is no longer valid.", jobItem.ItemId);
+ removeFromDevice = true;
+ }
+ else if (!IsLibraryItemAvailable(libraryItem))
+ {
+ // Tell the device to remove it since it's no longer available
+ _logger.Debug("Adding ItemIdsToRemove {0} because it is no longer available.", jobItem.ItemId);
+ removeFromDevice = true;
}
else if (job.UnwatchedOnly)
{
- var libraryItem = _libraryManager.GetItemById(jobItem.ItemId);
-
- if (IsLibraryItemAvailable(libraryItem))
- {
- if (libraryItem.IsPlayed(user) && libraryItem is Video)
- {
- // Tell the device to remove it since it has been played
- response.ItemIdsToRemove.Add(jobItem.ItemId);
- }
- }
- else
+ if (libraryItem.IsPlayed(user) && libraryItem is Video)
{
- // Tell the device to remove it since it's no longer available
- response.ItemIdsToRemove.Add(jobItem.ItemId);
+ // Tell the device to remove it since it has been played
+ _logger.Debug("Adding ItemIdsToRemove {0} because it has been marked played.", jobItem.ItemId);
+ removeFromDevice = true;
}
}
}
else
{
// Content is no longer on the device
- jobItem.Status = SyncJobItemStatus.RemovedFromDevice;
+ if (jobItem.IsMarkedForRemoval)
+ {
+ jobItem.Status = SyncJobItemStatus.RemovedFromDevice;
+ }
+ else
+ {
+ _logger.Debug("Setting status to Queued for {0} because it is no longer on the device.", jobItem.ItemId);
+ jobItem.Status = SyncJobItemStatus.Queued;
+ }
+ requiresSaving = true;
+ }
+
+ if (removeFromDevice)
+ {
+ response.ItemIdsToRemove.Add(jobItem.ItemId);
+ jobItem.IsMarkedForRemoval = true;
+ requiresSaving = true;
+ }
+
+ if (requiresSaving)
+ {
await UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false);
}
}
@@ -834,6 +860,11 @@ namespace MediaBrowser.Server.Implementations.Sync
foreach (var jobItem in jobItemResult.Items)
{
+ var requiresSaving = false;
+ var removeFromDevice = false;
+
+ var libraryItem = _libraryManager.GetItemById(jobItem.ItemId);
+
if (request.SyncJobItemIds.Contains(jobItem.Id, StringComparer.OrdinalIgnoreCase))
{
var job = _repo.GetJob(jobItem.JobId);
@@ -842,36 +873,55 @@ namespace MediaBrowser.Server.Implementations.Sync
if (jobItem.IsMarkedForRemoval)
{
// Tell the device to remove it since it has been marked for removal
- response.ItemIdsToRemove.Add(jobItem.Id);
+ _logger.Debug("Adding ItemIdsToRemove {0} because IsMarkedForRemoval is set.", jobItem.Id);
+ removeFromDevice = true;
}
else if (user == null)
{
// Tell the device to remove it since the user is gone now
- response.ItemIdsToRemove.Add(jobItem.Id);
+ _logger.Debug("Adding ItemIdsToRemove {0} because the user is no longer valid.", jobItem.Id);
+ removeFromDevice = true;
+ }
+ else if (!IsLibraryItemAvailable(libraryItem))
+ {
+ // Tell the device to remove it since it's no longer available
+ _logger.Debug("Adding ItemIdsToRemove {0} because it is no longer available.", jobItem.Id);
+ removeFromDevice = true;
}
else if (job.UnwatchedOnly)
{
- var libraryItem = _libraryManager.GetItemById(jobItem.ItemId);
-
- if (IsLibraryItemAvailable(libraryItem))
- {
- if (libraryItem.IsPlayed(user) && libraryItem is Video)
- {
- // Tell the device to remove it since it has been played
- response.ItemIdsToRemove.Add(jobItem.Id);
- }
- }
- else
+ if (libraryItem.IsPlayed(user) && libraryItem is Video)
{
- // Tell the device to remove it since it's no longer available
- response.ItemIdsToRemove.Add(jobItem.Id);
+ // Tell the device to remove it since it has been played
+ _logger.Debug("Adding ItemIdsToRemove {0} because it has been marked played.", jobItem.Id);
+ removeFromDevice = true;
}
}
}
else
{
// Content is no longer on the device
- jobItem.Status = SyncJobItemStatus.RemovedFromDevice;
+ if (jobItem.IsMarkedForRemoval)
+ {
+ jobItem.Status = SyncJobItemStatus.RemovedFromDevice;
+ }
+ else
+ {
+ _logger.Debug("Setting status to Queued for {0} because it is no longer on the device.", jobItem.Id);
+ jobItem.Status = SyncJobItemStatus.Queued;
+ }
+ requiresSaving = true;
+ }
+
+ if (removeFromDevice)
+ {
+ response.ItemIdsToRemove.Add(jobItem.Id);
+ jobItem.IsMarkedForRemoval = true;
+ requiresSaving = true;
+ }
+
+ if (requiresSaving)
+ {
await UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false);
}
}
@@ -894,12 +944,6 @@ namespace MediaBrowser.Server.Implementations.Sync
response.ItemIdsToRemove = response.ItemIdsToRemove.Distinct(StringComparer.OrdinalIgnoreCase).ToList();
- var itemsOnDevice = request.LocalItemIds
- .Except(response.ItemIdsToRemove)
- .ToList();
-
- SetUserAccess(request, response, itemsOnDevice);
-
return response;
}
@@ -962,16 +1006,39 @@ namespace MediaBrowser.Server.Implementations.Sync
await processor.UpdateJobStatus(jobItem.JobId).ConfigureAwait(false);
}
+ public async Task CancelItems(string targetId, IEnumerable<string> itemIds)
+ {
+ foreach (var item in itemIds)
+ {
+ var syncJobItemResult = GetJobItems(new SyncJobItemQuery
+ {
+ AddMetadata = false,
+ ItemId = item,
+ TargetId = targetId,
+ Statuses = new[] { SyncJobItemStatus.Queued, SyncJobItemStatus.ReadyToTransfer, SyncJobItemStatus.Converting, SyncJobItemStatus.Synced, SyncJobItemStatus.Failed }
+ });
+
+ foreach (var jobItem in syncJobItemResult.Items)
+ {
+ await CancelJobItem(jobItem.Id).ConfigureAwait(false);
+ }
+ }
+ }
+
public async Task CancelJobItem(string id)
{
var jobItem = _repo.GetJobItem(id);
- if (jobItem.Status != SyncJobItemStatus.Queued && jobItem.Status != SyncJobItemStatus.ReadyToTransfer && jobItem.Status != SyncJobItemStatus.Converting)
+ if (jobItem.Status != SyncJobItemStatus.Queued && jobItem.Status != SyncJobItemStatus.ReadyToTransfer && jobItem.Status != SyncJobItemStatus.Converting && jobItem.Status != SyncJobItemStatus.Failed && jobItem.Status != SyncJobItemStatus.Synced)
{
throw new ArgumentException("Operation is not valid for this job item");
}
- jobItem.Status = SyncJobItemStatus.Cancelled;
+ if (jobItem.Status != SyncJobItemStatus.Synced)
+ {
+ jobItem.Status = SyncJobItemStatus.Cancelled;
+ }
+
jobItem.Progress = 0;
jobItem.IsMarkedForRemoval = true;
@@ -995,24 +1062,24 @@ namespace MediaBrowser.Server.Implementations.Sync
{
_logger.ErrorException("Error deleting directory {0}", ex, path);
}
+
+ //var jobItemsResult = GetJobItems(new SyncJobItemQuery
+ //{
+ // AddMetadata = false,
+ // JobId = jobItem.JobId,
+ // Limit = 0,
+ // Statuses = new[] { SyncJobItemStatus.Converting, SyncJobItemStatus.Failed, SyncJobItemStatus.Queued, SyncJobItemStatus.ReadyToTransfer, SyncJobItemStatus.Synced, SyncJobItemStatus.Transferring }
+ //});
+
+ //if (jobItemsResult.TotalRecordCount == 0)
+ //{
+ // await CancelJob(jobItem.JobId).ConfigureAwait(false);
+ //}
}
- public async Task MarkJobItemForRemoval(string id)
+ public Task MarkJobItemForRemoval(string id)
{
- var jobItem = _repo.GetJobItem(id);
-
- if (jobItem.Status != SyncJobItemStatus.Synced)
- {
- throw new ArgumentException("Operation is not valid for this job item");
- }
-
- jobItem.IsMarkedForRemoval = true;
-
- await UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false);
-
- var processor = GetSyncJobProcessor();
-
- await processor.UpdateJobStatus(jobItem.JobId).ConfigureAwait(false);
+ return CancelJobItem(id);
}
public async Task UnmarkJobItemForRemoval(string id)
@@ -1137,13 +1204,18 @@ namespace MediaBrowser.Server.Implementations.Sync
public IEnumerable<SyncQualityOption> GetQualityOptions(string targetId)
{
+ return GetQualityOptions(targetId, null);
+ }
+
+ public IEnumerable<SyncQualityOption> GetQualityOptions(string targetId, User user)
+ {
foreach (var provider in _providers)
{
foreach (var target in GetSyncTargets(provider))
{
if (string.Equals(target.Id, targetId, StringComparison.OrdinalIgnoreCase))
{
- return GetQualityOptions(provider, target);
+ return GetQualityOptions(provider, target, user);
}
}
}
@@ -1151,12 +1223,19 @@ namespace MediaBrowser.Server.Implementations.Sync
return new List<SyncQualityOption>();
}
- private IEnumerable<SyncQualityOption> GetQualityOptions(ISyncProvider provider, SyncTarget target)
+ private IEnumerable<SyncQualityOption> GetQualityOptions(ISyncProvider provider, SyncTarget target, User user)
{
var hasQuality = provider as IHasSyncQuality;
if (hasQuality != null)
{
- return hasQuality.GetQualityOptions(target);
+ var options = hasQuality.GetQualityOptions(target);
+
+ if (user != null && !user.Policy.EnableSyncTranscoding)
+ {
+ options = options.Where(i => i.IsOriginalQuality);
+ }
+
+ return options;
}
// Default options for providers that don't override
@@ -1186,7 +1265,7 @@ namespace MediaBrowser.Server.Implementations.Sync
};
}
- public IEnumerable<SyncProfileOption> GetProfileOptions(string targetId)
+ public IEnumerable<SyncProfileOption> GetProfileOptions(string targetId, User user)
{
foreach (var provider in _providers)
{
@@ -1194,7 +1273,7 @@ namespace MediaBrowser.Server.Implementations.Sync
{
if (string.Equals(target.Id, targetId, StringComparison.OrdinalIgnoreCase))
{
- return GetProfileOptions(provider, target);
+ return GetProfileOptions(provider, target, user);
}
}
}
@@ -1202,7 +1281,12 @@ namespace MediaBrowser.Server.Implementations.Sync
return new List<SyncProfileOption>();
}
- private IEnumerable<SyncProfileOption> GetProfileOptions(ISyncProvider provider, SyncTarget target)
+ public IEnumerable<SyncProfileOption> GetProfileOptions(string targetId)
+ {
+ return GetProfileOptions(targetId, null);
+ }
+
+ private IEnumerable<SyncProfileOption> GetProfileOptions(ISyncProvider provider, SyncTarget target, User user)
{
var hasQuality = provider as IHasSyncQuality;
if (hasQuality != null)
@@ -1220,20 +1304,23 @@ namespace MediaBrowser.Server.Implementations.Sync
EnableQualityOptions = false
});
- list.Add(new SyncProfileOption
+ if (user == null || user.Policy.EnableSyncTranscoding)
{
- Name = "Baseline",
- Id = "baseline",
- Description = "Designed for compatibility with all devices, including web browsers. Targets H264/AAC video and MP3 audio."
- });
+ list.Add(new SyncProfileOption
+ {
+ Name = "Baseline",
+ Id = "baseline",
+ Description = "Designed for compatibility with all devices, including web browsers. Targets H264/AAC video and MP3 audio."
+ });
- list.Add(new SyncProfileOption
- {
- Name = "General",
- Id = "general",
- Description = "Designed for compatibility with Chromecast, Roku, Smart TV's, and other similar devices. Targets H264/AAC/AC3 video and MP3 audio.",
- IsDefault = true
- });
+ list.Add(new SyncProfileOption
+ {
+ Name = "General",
+ Id = "general",
+ Description = "Designed for compatibility with Chromecast, Roku, Smart TV's, and other similar devices. Targets H264/AAC/AC3 video and MP3 audio.",
+ IsDefault = true
+ });
+ }
return list;
}
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs
index d1ef523e1..f7f320741 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs
@@ -56,7 +56,7 @@ namespace MediaBrowser.Server.Implementations.Sync
var syncProvider = targetTuple.Item1;
var dataProvider = _syncManager.GetDataProvider(targetTuple.Item1, syncTarget);
- var localItems = await dataProvider.GetCachedItems(syncTarget, serverId, item.Id.ToString("N")).ConfigureAwait(false);
+ var localItems = await dataProvider.GetItems(syncTarget, serverId, item.Id.ToString("N")).ConfigureAwait(false);
foreach (var localItem in localItems)
{
@@ -109,8 +109,13 @@ namespace MediaBrowser.Server.Implementations.Sync
var dataProvider = _syncManager.GetDataProvider(provider, target);
var localItem = await dataProvider.Get(target, openKeys[2]).ConfigureAwait(false);
+ var fileId = localItem.FileId;
+ if (string.IsNullOrWhiteSpace(fileId))
+ {
+ }
+
var requiresDynamicAccess = (IHasDynamicAccess)provider;
- var dynamicInfo = await requiresDynamicAccess.GetSyncedFileInfo(localItem.LocalPath, target, cancellationToken).ConfigureAwait(false);
+ var dynamicInfo = await requiresDynamicAccess.GetSyncedFileInfo(fileId, target, cancellationToken).ConfigureAwait(false);
var mediaSource = localItem.Item.MediaSources.First();
mediaSource.LiveStreamId = Guid.NewGuid().ToString();
diff --git a/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs b/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs
index dea868848..676adad34 100644
--- a/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs
+++ b/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs
@@ -1,5 +1,4 @@
using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Sync;
@@ -12,6 +11,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Interfaces.IO;
namespace MediaBrowser.Server.Implementations.Sync
{
@@ -29,8 +29,6 @@ namespace MediaBrowser.Server.Implementations.Sync
private readonly IApplicationPaths _appPaths;
private readonly IServerApplicationHost _appHost;
- private readonly SemaphoreSlim _cacheFileLock = new SemaphoreSlim(1, 1);
-
public TargetDataProvider(IServerSyncProvider provider, SyncTarget target, IServerApplicationHost appHost, ILogger logger, IJsonSerializer json, IFileSystem fileSystem, IApplicationPaths appPaths)
{
_logger = logger;
@@ -42,12 +40,7 @@ namespace MediaBrowser.Server.Implementations.Sync
_appHost = appHost;
}
- private string GetCachePath()
- {
- return Path.Combine(_appPaths.DataPath, "sync", _target.Id.GetMD5().ToString("N") + ".json");
- }
-
- private string GetRemotePath()
+ private string[] GetRemotePath()
{
var parts = new List<string>
{
@@ -57,7 +50,7 @@ namespace MediaBrowser.Server.Implementations.Sync
parts = parts.Select(i => GetValidFilename(_provider, i)).ToList();
- return _provider.GetFullPath(parts, _target);
+ return parts.ToArray();
}
private string GetValidFilename(IServerSyncProvider provider, string filename)
@@ -66,58 +59,29 @@ namespace MediaBrowser.Server.Implementations.Sync
return _fileSystem.GetValidFilename(filename);
}
- private async Task CacheData(Stream stream)
- {
- var cachePath = GetCachePath();
-
- await _cacheFileLock.WaitAsync().ConfigureAwait(false);
-
- try
- {
- Directory.CreateDirectory(Path.GetDirectoryName(cachePath));
- using (var fileStream = _fileSystem.GetFileStream(cachePath, FileMode.Create, FileAccess.Write, FileShare.Read, true))
- {
- await stream.CopyToAsync(fileStream).ConfigureAwait(false);
- }
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error saving sync data to {0}", ex, cachePath);
- }
- finally
- {
- _cacheFileLock.Release();
- }
- }
-
private async Task EnsureData(CancellationToken cancellationToken)
{
if (_items == null)
{
- try
+ _logger.Debug("Getting {0} from {1}", string.Join(MediaSync.PathSeparatorString, GetRemotePath().ToArray()), _provider.Name);
+
+ var fileResult = await _provider.GetFiles(new FileQuery
+ {
+ FullPath = GetRemotePath().ToArray()
+
+ }, _target, cancellationToken).ConfigureAwait(false);
+
+ if (fileResult.Items.Length > 0)
{
- using (var stream = await _provider.GetFile(GetRemotePath(), _target, new Progress<double>(), cancellationToken))
+ using (var stream = await _provider.GetFile(fileResult.Items[0].Id, _target, new Progress<double>(), cancellationToken))
{
_items = _json.DeserializeFromStream<List<LocalItem>>(stream);
}
}
- catch (FileNotFoundException)
- {
- _items = new List<LocalItem>();
- }
- catch (DirectoryNotFoundException)
+ else
{
_items = new List<LocalItem>();
}
-
- using (var memoryStream = new MemoryStream())
- {
- _json.SerializeToStream(_items, memoryStream);
-
- // Now cache it
- memoryStream.Position = 0;
- await CacheData(memoryStream).ConfigureAwait(false);
- }
}
}
@@ -130,10 +94,6 @@ namespace MediaBrowser.Server.Implementations.Sync
// Save to sync provider
stream.Position = 0;
await _provider.SendFile(stream, GetRemotePath(), _target, new Progress<double>(), cancellationToken).ConfigureAwait(false);
-
- // Now cache it
- stream.Position = 0;
- await CacheData(stream).ConfigureAwait(false);
}
}
@@ -171,14 +131,9 @@ namespace MediaBrowser.Server.Implementations.Sync
}
}
- public Task<List<string>> GetServerItemIds(SyncTarget target, string serverId)
+ public Task<List<LocalItem>> GetLocalItems(SyncTarget target, string serverId)
{
- return GetData(items => items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase)).Select(i => i.ItemId).ToList());
- }
-
- public Task<List<string>> GetSyncJobItemIds(SyncTarget target, string serverId)
- {
- return GetData(items => items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase)).Select(i => i.SyncJobItemId).Where(i => !string.IsNullOrWhiteSpace(i)).ToList());
+ return GetData(items => items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase)).ToList());
}
public Task AddOrUpdate(SyncTarget target, LocalItem item)
@@ -204,62 +159,14 @@ namespace MediaBrowser.Server.Implementations.Sync
return GetData(items => items.FirstOrDefault(i => string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase)));
}
- private async Task<List<LocalItem>> GetCachedData()
- {
- if (_items == null)
- {
- await _cacheFileLock.WaitAsync().ConfigureAwait(false);
-
- try
- {
- if (_items == null)
- {
- try
- {
- _items = _json.DeserializeFromFile<List<LocalItem>>(GetCachePath());
- }
- catch (FileNotFoundException)
- {
- _items = new List<LocalItem>();
- }
- catch (DirectoryNotFoundException)
- {
- _items = new List<LocalItem>();
- }
- }
- }
- finally
- {
- _cacheFileLock.Release();
- }
- }
-
- return _items.ToList();
- }
-
- public async Task<List<string>> GetCachedServerItemIds(SyncTarget target, string serverId)
- {
- var items = await GetCachedData().ConfigureAwait(false);
-
- return items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase))
- .Select(i => i.ItemId)
- .ToList();
- }
-
- public async Task<List<LocalItem>> GetCachedItems(SyncTarget target, string serverId, string itemId)
+ public Task<List<LocalItem>> GetItems(SyncTarget target, string serverId, string itemId)
{
- var items = await GetCachedData().ConfigureAwait(false);
-
- return items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase) && string.Equals(i.ItemId, itemId, StringComparison.OrdinalIgnoreCase))
- .ToList();
+ return GetData(items => items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase) && string.Equals(i.ItemId, itemId, StringComparison.OrdinalIgnoreCase)).ToList());
}
- public async Task<List<LocalItem>> GetCachedItemsBySyncJobItemId(SyncTarget target, string serverId, string syncJobItemId)
+ public Task<List<LocalItem>> GetItemsBySyncJobItemId(SyncTarget target, string serverId, string syncJobItemId)
{
- var items = await GetCachedData().ConfigureAwait(false);
-
- return items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase) && string.Equals(i.SyncJobItemId, syncJobItemId, StringComparison.OrdinalIgnoreCase))
- .ToList();
+ return GetData(items => items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase) && string.Equals(i.SyncJobItemId, syncJobItemId, StringComparison.OrdinalIgnoreCase)).ToList());
}
}
}
diff --git a/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs b/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs
index 7bcbbd6a8..4a4d90d14 100644
--- a/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.TV;
@@ -22,8 +23,8 @@ namespace MediaBrowser.Server.Implementations.UserViews
private readonly IUserManager _userManager;
private readonly ILibraryManager _libraryManager;
- public DynamicImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IUserManager userManager, ILibraryManager libraryManager)
- : base(fileSystem, providerManager, applicationPaths)
+ public DynamicImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, IUserManager userManager, ILibraryManager libraryManager)
+ : base(fileSystem, providerManager, applicationPaths, imageProcessor)
{
_userManager = userManager;
_libraryManager = libraryManager;
@@ -61,42 +62,18 @@ namespace MediaBrowser.Server.Implementations.UserViews
return new List<BaseItem>();
}
- if (string.Equals(view.ViewType, SpecialFolder.GameGenre, StringComparison.OrdinalIgnoreCase))
- {
- var list = new List<BaseItem>();
-
- var genre = _libraryManager.GetGameGenre(view.Name);
-
- if (genre.HasImage(ImageType.Primary) || genre.HasImage(ImageType.Thumb))
- {
- list.Add(genre);
- }
- return list;
- }
- if (string.Equals(view.ViewType, SpecialFolder.MusicGenre, StringComparison.OrdinalIgnoreCase))
- {
- var list = new List<BaseItem>();
-
- var genre = _libraryManager.GetMusicGenre(view.Name);
-
- if (genre.HasImage(ImageType.Primary) || genre.HasImage(ImageType.Thumb))
- {
- list.Add(genre);
- }
- return list;
- }
- if (string.Equals(view.ViewType, SpecialFolder.MovieGenre, StringComparison.OrdinalIgnoreCase) ||
+ if (string.Equals(view.ViewType, SpecialFolder.GameGenre, StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(view.ViewType, SpecialFolder.MusicGenre, StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(view.ViewType, SpecialFolder.MovieGenre, StringComparison.OrdinalIgnoreCase) ||
string.Equals(view.ViewType, SpecialFolder.TvGenre, StringComparison.OrdinalIgnoreCase))
{
- var list = new List<BaseItem>();
-
- var genre = _libraryManager.GetGenre(view.Name);
-
- if (genre.HasImage(ImageType.Primary) || genre.HasImage(ImageType.Thumb))
+ var userItemsResult = await view.GetItems(new InternalItemsQuery
{
- list.Add(genre);
- }
- return list;
+ User = _userManager.GetUserById(view.UserId.Value),
+ CollapseBoxSetItems = false
+ });
+
+ return userItemsResult.Items.ToList();
}
var isUsingCollectionStrip = IsUsingCollectionStrip(view);
@@ -202,6 +179,7 @@ namespace MediaBrowser.Server.Implementations.UserViews
SpecialFolder.MusicGenres,
SpecialFolder.MusicGenre,
SpecialFolder.MusicLatest,
+ SpecialFolder.MusicPlaylists,
SpecialFolder.MusicSongs,
SpecialFolder.MusicFavorites,
SpecialFolder.MusicFavoriteArtists,
@@ -238,25 +216,28 @@ namespace MediaBrowser.Server.Implementations.UserViews
return collectionStripViewTypes.Contains(view.ViewType ?? string.Empty);
}
- protected override async Task<Stream> CreateImageAsync(IHasImages item, List<BaseItem> itemsWithImages, ImageType imageType, int imageIndex)
+ protected override bool CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPath, ImageType imageType, int imageIndex)
{
var view = (UserView)item;
if (imageType == ImageType.Primary && IsUsingCollectionStrip(view))
{
if (itemsWithImages.Count == 0 && !string.Equals(view.ViewType, CollectionType.LiveTv, StringComparison.OrdinalIgnoreCase))
{
- return null;
+ return false;
}
- return new StripCollageBuilder(ApplicationPaths).BuildThumbCollage(GetStripCollageImagePaths(itemsWithImages, view.ViewType), 960, 540, false, item.Name);
+ CreateThumbCollage(item, itemsWithImages, outputPath, 960, 540, false, item.Name);
+ return true;
}
- return await base.CreateImageAsync(item, itemsWithImages, imageType, imageIndex);
+ return base.CreateImage(item, itemsWithImages, outputPath, imageType, imageIndex);
}
- private IEnumerable<String> GetStripCollageImagePaths(IEnumerable<BaseItem> items, string viewType)
+ protected override IEnumerable<String> GetStripCollageImagePaths(IHasImages primaryItem, IEnumerable<BaseItem> items)
{
- if (string.Equals(viewType, CollectionType.LiveTv, StringComparison.OrdinalIgnoreCase))
+ var userView = primaryItem as UserView;
+
+ if (userView != null && string.Equals(userView.ViewType, CollectionType.LiveTv, StringComparison.OrdinalIgnoreCase))
{
var list = new List<string>();
for (int i = 1; i <= 8; i++)
@@ -266,9 +247,7 @@ namespace MediaBrowser.Server.Implementations.UserViews
return list;
}
- return items
- .Select(i => i.GetImagePath(ImageType.Primary) ?? i.GetImagePath(ImageType.Thumb))
- .Where(i => !string.IsNullOrWhiteSpace(i));
+ return base.GetStripCollageImagePaths(primaryItem, items);
}
private string ExtractLiveTvResource(string name, IApplicationPaths paths)
diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config
index 438ccff92..036dffe95 100644
--- a/MediaBrowser.Server.Implementations/packages.config
+++ b/MediaBrowser.Server.Implementations/packages.config
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="ImageMagickSharp" version="1.0.0.11" targetFramework="net45" />
+ <package id="Interfaces.IO" version="1.0.0.5" targetFramework="net45" />
<package id="MediaBrowser.Naming" version="1.0.0.32" targetFramework="net45" />
- <package id="Mono.Nat" version="1.2.21.0" targetFramework="net45" />
+ <package id="Mono.Nat" version="1.2.23.0" targetFramework="net45" />
<package id="morelinq" version="1.1.0" targetFramework="net45" />
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
- <package id="SocketHttpListener" version="1.0.0.3" targetFramework="net45" />
+ <package id="SocketHttpListener" version="1.0.0.5" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.Server.Mac.sln b/MediaBrowser.Server.Mac.sln
index 1813c2029..3167aa65f 100644
--- a/MediaBrowser.Server.Mac.sln
+++ b/MediaBrowser.Server.Mac.sln
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Server.Mac", "MediaBrowser.Server.Mac\MediaBrowser.Server.Mac.csproj", "{C97B98FA-00D4-4880-88B8-C76017A418AB}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Server.Mac", "MediaBrowser.Server.Mac\Emby.Server.Mac.csproj", "{C97B98FA-00D4-4880-88B8-C76017A418AB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Api", "MediaBrowser.Api\MediaBrowser.Api.csproj", "{4FD51AC5-2C16-4308-A993-C3A84F3B4582}"
EndProject
@@ -33,6 +33,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.XbmcMetadata",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenSubtitlesHandler", "OpenSubtitlesHandler\OpenSubtitlesHandler.csproj", "{4A4402D4-E910-443B-B8FC-2C18286A2CA0}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Drawing", "Emby.Drawing\Emby.Drawing.csproj", "{08FFF49B-F175-4807-A2B5-73B0EBD9F716}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -44,6 +46,20 @@ Global
Release Mono|x86 = Release Mono|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.AppStore|Any CPU.Build.0 = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Debug|x86.Build.0 = Debug|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release Mono|Any CPU.ActiveCfg = Debug|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release Mono|Any CPU.Build.0 = Debug|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release Mono|x86.ActiveCfg = Debug|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release Mono|x86.Build.0 = Debug|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release|Any CPU.Build.0 = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release|x86.ActiveCfg = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release|x86.Build.0 = Release|Any CPU
{0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.AppStore|Any CPU.Build.0 = Release|Any CPU
{0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@@ -270,14 +286,12 @@ Global
{C97B98FA-00D4-4880-88B8-C76017A418AB}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
- StartupItems = $0
- $0.Item = MediaBrowser.Server.Mac\MediaBrowser.Server.Mac.csproj
- Policies = $1
- $1.DotNetNamingPolicy = $2
- $2.DirectoryNamespaceAssociation = None
- $2.ResourceNamePolicy = FileFormatDefault
- $1.VersionControlPolicy = $3
- $3.inheritsSet = Mono
+ Policies = $0
+ $0.DotNetNamingPolicy = $1
+ $1.DirectoryNamespaceAssociation = None
+ $1.ResourceNamePolicy = FileFormatDefault
+ $0.VersionControlPolicy = $2
+ $2.inheritsSet = Mono
version =
EndGlobalSection
EndGlobal
diff --git a/MediaBrowser.Server.Mac.userprefs b/MediaBrowser.Server.Mac.userprefs
index fd846d5e5..b5f227685 100644
--- a/MediaBrowser.Server.Mac.userprefs
+++ b/MediaBrowser.Server.Mac.userprefs
@@ -1,26 +1,20 @@
<Properties>
- <MonoDevelop.Ide.Workspace ActiveConfiguration="Debug" />
- <MonoDevelop.Ide.Workbench ActiveDocument="MediaBrowser.Server.Mac/Main.cs">
+ <MonoDevelop.Ide.Workspace ActiveConfiguration="Release" />
+ <MonoDevelop.Ide.Workbench ActiveDocument="MediaBrowser.Common/Properties/AssemblyInfo.cs">
<Files>
- <File FileName="MediaBrowser.Server.Mac/AppController.cs" Line="4" Column="4" />
- <File FileName="MediaBrowser.Server.Mac/Main.cs" Line="18" Column="18" />
- <File FileName="MediaBrowser.Server.Startup.Common/ApplicationHost.cs" Line="22" Column="22" />
- <File FileName="MediaBrowser.Common.Implementations/BaseApplicationHost.cs" Line="14" Column="14" />
- <File FileName="MediaBrowser.Common.Implementations/Logging/NlogManager.cs" Line="24" Column="24" />
+ <File FileName="MediaBrowser.Server.Mac/ImageMagickSharp.dll.config" Line="1" Column="1" />
+ <File FileName="MediaBrowser.Server.Startup.Common/ApplicationHost.cs" Line="1" Column="18" />
+ <File FileName="MediaBrowser.Api/ConnectService.cs" Line="7" Column="22" />
+ <File FileName="MediaBrowser.Server.Mac/AppController.cs" Line="22" Column="1" />
+ <File FileName="MediaBrowser.Server.Mac/AppDelegate.cs" Line="24" Column="1" />
+ <File FileName="MediaBrowser.Server.Mac/Main.cs" Line="60" Column="4" />
+ <File FileName="SharedVersion.cs" Line="1" Column="1" />
+ <File FileName="MediaBrowser.Common/Properties/AssemblyInfo.cs" Line="9" Column="12" />
</Files>
<Pads>
<Pad Id="ProjectPad">
<State expanded="True">
- <Node name="MediaBrowser.Common.Implementations" expanded="True">
- <Node name="Logging" expanded="True" />
- </Node>
- <Node name="MediaBrowser.Model" expanded="True">
- <Node name="Logging" expanded="True" />
- </Node>
- <Node name="MediaBrowser.Server.Mac" expanded="True" selected="True" />
- <Node name="MediaBrowser.Server.Startup.Common" expanded="True" />
- <Node name="MediaBrowser.WebDashboard" expanded="True" />
- <Node name="MediaBrowser.XbmcMetadata" expanded="True" />
+ <Node name="Emby.Server.Mac" selected="True" />
<Node name="OpenSubtitlesHandler" expanded="True" />
</State>
</Pad>
@@ -32,4 +26,7 @@
</BreakpointStore>
</MonoDevelop.Ide.DebuggingService.Breakpoints>
<MonoDevelop.Ide.DebuggingService.PinnedWatches />
+ <StartupItems>
+ <String>MediaBrowser.Server.Mac/Emby.Server.Mac.csproj</String>
+ </StartupItems>
</Properties> \ No newline at end of file
diff --git a/MediaBrowser.Server.Mac/MediaBrowser.Server.Mac.csproj b/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj
index 66a0897a5..8592fc460 100644
--- a/MediaBrowser.Server.Mac/MediaBrowser.Server.Mac.csproj
+++ b/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj
@@ -13,6 +13,7 @@
<ReleaseVersion>
</ReleaseVersion>
<StartupObject>MediaBrowser.Server.Mac.MainClass</StartupObject>
+ <Description>A personal media server</Description>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -30,6 +31,7 @@
<EnableCodeSigning>false</EnableCodeSigning>
<CreatePackage>true</CreatePackage>
<PackageSigningKey>Developer ID Installer</PackageSigningKey>
+ <UseRefCounting>false</UseRefCounting>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Optimize>true</Optimize>
@@ -44,6 +46,7 @@
<EnableCodeSigning>false</EnableCodeSigning>
<CreatePackage>true</CreatePackage>
<PackageSigningKey>Developer ID Installer</PackageSigningKey>
+ <UseRefCounting>false</UseRefCounting>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'AppStore|AnyCPU' ">
<DebugType>full</DebugType>
@@ -59,6 +62,7 @@
<CodeSigningKey>3rd Party Mac Developer Application</CodeSigningKey>
<EnableCodeSigning>false</EnableCodeSigning>
<EnablePackageSigning>false</EnablePackageSigning>
+ <UseRefCounting>false</UseRefCounting>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@@ -110,10 +114,10 @@
<None Include="MediaBrowser.MediaInfo.dll.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
- <None Include="Imazen.WebP.dll.config">
+ <None Include="packages.config" />
+ <None Include="ImageMagickSharp.dll.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
- <None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
@@ -186,10 +190,6 @@
<IsCxx>False</IsCxx>
<Kind>Dynamic</Kind>
</NativeReference>
- <NativeReference Include="..\ThirdParty\libwebp\osx\libwebp.5.dylib">
- <IsCxx>False</IsCxx>
- <Kind>Dynamic</Kind>
- </NativeReference>
<NativeReference Include="..\ThirdParty\SQLite3\osx\libsqlite3.0.dylib">
<IsCxx>False</IsCxx>
<Kind>Dynamic</Kind>
@@ -271,6 +271,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\advanced.html">
<Link>Resources\dashboard-ui\advanced.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\appservices.html">
+ <Link>Resources\dashboard-ui\appservices.html</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\autoorganizelog.html">
<Link>Resources\dashboard-ui\autoorganizelog.html</Link>
</BundleResource>
@@ -388,6 +391,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\itemlist.html">
<Link>Resources\dashboard-ui\itemlist.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\kids.html">
+ <Link>Resources\dashboard-ui\kids.html</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\library.html">
<Link>Resources\dashboard-ui\library.html</Link>
</BundleResource>
@@ -406,6 +412,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\livetvguide.html">
<Link>Resources\dashboard-ui\livetvguide.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\livetvitems.html">
+ <Link>Resources\dashboard-ui\livetvitems.html</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\livetvnewrecording.html">
<Link>Resources\dashboard-ui\livetvnewrecording.html</Link>
</BundleResource>
@@ -472,9 +481,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\movies.html">
<Link>Resources\dashboard-ui\movies.html</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\movieslatest.html">
- <Link>Resources\dashboard-ui\movieslatest.html</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\moviesrecommended.html">
<Link>Resources\dashboard-ui\moviesrecommended.html</Link>
</BundleResource>
@@ -535,9 +541,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\playbackconfiguration.html">
<Link>Resources\dashboard-ui\playbackconfiguration.html</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\playlist.html">
- <Link>Resources\dashboard-ui\playlist.html</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\playlistedit.html">
<Link>Resources\dashboard-ui\playlistedit.html</Link>
</BundleResource>
@@ -568,6 +571,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\songs.html">
<Link>Resources\dashboard-ui\songs.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\streamingsettings.html">
+ <Link>Resources\dashboard-ui\streamingsettings.html</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\support.html">
<Link>Resources\dashboard-ui\support.html</Link>
</BundleResource>
@@ -706,6 +712,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\userimage.css">
<Link>Resources\dashboard-ui\css\userimage.css</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\fonts\Montserrat.woff">
+ <Link>Resources\dashboard-ui\css\fonts\Montserrat.woff</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\fonts\RobotoBold.woff">
<Link>Resources\dashboard-ui\css\fonts\RobotoBold.woff</Link>
</BundleResource>
@@ -721,9 +730,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\fonts\RobotoThin.woff">
<Link>Resources\dashboard-ui\css\fonts\RobotoThin.woff</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\fonts\mblogo.woff">
- <Link>Resources\dashboard-ui\css\fonts\mblogo.woff</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\images\checkmarkblack.png">
<Link>Resources\dashboard-ui\css\images\checkmarkblack.png</Link>
</BundleResource>
@@ -820,6 +826,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\images\clients\android.png">
<Link>Resources\dashboard-ui\css\images\clients\android.png</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\images\clients\androidtv-tile.png">
+ <Link>Resources\dashboard-ui\css\images\clients\androidtv-tile.png</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\images\clients\chrome.png">
<Link>Resources\dashboard-ui\css\images\clients\chrome.png</Link>
</BundleResource>
@@ -997,6 +1006,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\images\items\searchhintsv2\tv.png">
<Link>Resources\dashboard-ui\css\images\items\searchhintsv2\tv.png</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\images\kids\bg.jpg">
+ <Link>Resources\dashboard-ui\css\images\kids\bg.jpg</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\images\media\chapterflyout.png">
<Link>Resources\dashboard-ui\css\images\media\chapterflyout.png</Link>
</BundleResource>
@@ -1132,6 +1144,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\alphapicker.js">
<Link>Resources\dashboard-ui\scripts\alphapicker.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\appservices.js">
+ <Link>Resources\dashboard-ui\scripts\appservices.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\autoorganizelog.js">
<Link>Resources\dashboard-ui\scripts\autoorganizelog.js</Link>
</BundleResource>
@@ -1261,6 +1276,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\itemlistpage.js">
<Link>Resources\dashboard-ui\scripts\itemlistpage.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\kids.js">
+ <Link>Resources\dashboard-ui\scripts\kids.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\librarybrowser.js">
<Link>Resources\dashboard-ui\scripts\librarybrowser.js</Link>
</BundleResource>
@@ -1285,6 +1303,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\livetvguide.js">
<Link>Resources\dashboard-ui\scripts\livetvguide.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\livetvitems.js">
+ <Link>Resources\dashboard-ui\scripts\livetvitems.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\livetvnewrecording.js">
<Link>Resources\dashboard-ui\scripts\livetvnewrecording.js</Link>
</BundleResource>
@@ -1366,9 +1387,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\movies.js">
<Link>Resources\dashboard-ui\scripts\movies.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\movieslatest.js">
- <Link>Resources\dashboard-ui\scripts\movieslatest.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\moviesrecommended.js">
<Link>Resources\dashboard-ui\scripts\moviesrecommended.js</Link>
</BundleResource>
@@ -1429,9 +1447,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\playbackconfiguration.js">
<Link>Resources\dashboard-ui\scripts\playbackconfiguration.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\playlist.js">
- <Link>Resources\dashboard-ui\scripts\playlist.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\playlistedit.js">
<Link>Resources\dashboard-ui\scripts\playlistedit.js</Link>
</BundleResource>
@@ -1477,6 +1492,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\songs.js">
<Link>Resources\dashboard-ui\scripts\songs.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\streamingsettings.js">
+ <Link>Resources\dashboard-ui\scripts\streamingsettings.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\supporterkeypage.js">
<Link>Resources\dashboard-ui\scripts\supporterkeypage.js</Link>
</BundleResource>
@@ -1573,6 +1591,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\apiclient\ajax.js">
<Link>Resources\dashboard-ui\thirdparty\apiclient\ajax.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\apiclient\apiclient.js">
+ <Link>Resources\dashboard-ui\thirdparty\apiclient\apiclient.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\apiclient\connectionmanager.js">
<Link>Resources\dashboard-ui\thirdparty\apiclient\connectionmanager.js</Link>
</BundleResource>
@@ -1585,9 +1606,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\apiclient\deferred.js">
<Link>Resources\dashboard-ui\thirdparty\apiclient\deferred.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\apiclient\deferredAlt.js">
- <Link>Resources\dashboard-ui\thirdparty\apiclient\deferredAlt.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\apiclient\device.js">
<Link>Resources\dashboard-ui\thirdparty\apiclient\device.js</Link>
</BundleResource>
@@ -1600,9 +1618,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\apiclient\md5.js">
<Link>Resources\dashboard-ui\thirdparty\apiclient\md5.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\apiclient\mediabrowser.apiclient.js">
- <Link>Resources\dashboard-ui\thirdparty\apiclient\mediabrowser.apiclient.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\apiclient\network.js">
<Link>Resources\dashboard-ui\thirdparty\apiclient\network.js</Link>
</BundleResource>
@@ -1615,6 +1630,18 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\apiclient\store.js">
<Link>Resources\dashboard-ui\thirdparty\apiclient\store.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\apiclient\alt\ajax.js">
+ <Link>Resources\dashboard-ui\thirdparty\apiclient\alt\ajax.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\apiclient\alt\bean.js">
+ <Link>Resources\dashboard-ui\thirdparty\apiclient\alt\bean.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\apiclient\alt\deferred.js">
+ <Link>Resources\dashboard-ui\thirdparty\apiclient\alt\deferred.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\apiclient\alt\events.js">
+ <Link>Resources\dashboard-ui\thirdparty\apiclient\alt\events.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\fontawesome\css\font-awesome.css">
<Link>Resources\dashboard-ui\thirdparty\fontawesome\css\font-awesome.css</Link>
</BundleResource>
diff --git a/MediaBrowser.Server.Mac/ImageMagickSharp.dll.config b/MediaBrowser.Server.Mac/ImageMagickSharp.dll.config
new file mode 100644
index 000000000..0ad6d1e60
--- /dev/null
+++ b/MediaBrowser.Server.Mac/ImageMagickSharp.dll.config
@@ -0,0 +1,3 @@
+<configuration>
+ <dllmap dll="CORE_RL_Wand_.dll" target="libMagickWand-6.Q8.dylib" os="osx"/>
+</configuration> \ No newline at end of file
diff --git a/MediaBrowser.Server.Mac/Imazen.WebP.dll.config b/MediaBrowser.Server.Mac/Imazen.WebP.dll.config
deleted file mode 100644
index 1b6270fd5..000000000
--- a/MediaBrowser.Server.Mac/Imazen.WebP.dll.config
+++ /dev/null
@@ -1,3 +0,0 @@
-<configuration>
- <dllmap dll="libwebp" target="libwebp.5.dylib" os="osx"/>
-</configuration> \ No newline at end of file
diff --git a/MediaBrowser.Server.Mac/Info.plist b/MediaBrowser.Server.Mac/Info.plist
index 3e058c72f..73c2036b1 100644
--- a/MediaBrowser.Server.Mac/Info.plist
+++ b/MediaBrowser.Server.Mac/Info.plist
@@ -2,12 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
- <key>CFBundleDisplayName</key>
- <string>Media Browser</string>
<key>CFBundleIconFile</key>
<string>appicon</string>
<key>CFBundleIdentifier</key>
- <string>com.MediaBrowser.MediaBrowser.Server.Mac</string>
+ <string>com.emby.server</string>
<key>CFBundleName</key>
<string>Media Browser</string>
<key>CFBundleShortVersionString</key>
@@ -26,5 +24,7 @@
<string>NSApplication</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
+ <key>CFBundleDisplayName</key>
+ <string>Emby</string>
</dict>
</plist>
diff --git a/MediaBrowser.Server.Mac/Main.cs b/MediaBrowser.Server.Mac/Main.cs
index 0a1fd1b3d..b4184f3b1 100644
--- a/MediaBrowser.Server.Mac/Main.cs
+++ b/MediaBrowser.Server.Mac/Main.cs
@@ -62,6 +62,10 @@ namespace MediaBrowser.Server.Mac
{
// TODO: Use CommonApplicationData? Will we always have write access?
programDataPath = Path.Combine(Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData), "mediabrowser-server");
+
+ if (!Directory.Exists (programDataPath)) {
+ programDataPath = Path.Combine(Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData), "emby-server");
+ }
}
// Within the mac bundle, go uo two levels then down into Resources folder
diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
index df7b3f061..057996739 100644
--- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
+++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
@@ -1,4 +1,7 @@
-using MediaBrowser.Api;
+using Emby.Drawing;
+using Emby.Drawing.GDI;
+using Emby.Drawing.ImageMagick;
+using MediaBrowser.Api;
using MediaBrowser.Common;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Events;
@@ -63,7 +66,6 @@ using MediaBrowser.Server.Implementations.Collections;
using MediaBrowser.Server.Implementations.Configuration;
using MediaBrowser.Server.Implementations.Connect;
using MediaBrowser.Server.Implementations.Devices;
-using MediaBrowser.Server.Implementations.Drawing;
using MediaBrowser.Server.Implementations.Dto;
using MediaBrowser.Server.Implementations.EntryPoints;
using MediaBrowser.Server.Implementations.FileOrganization;
@@ -440,7 +442,7 @@ namespace MediaBrowser.Server.Startup.Common
var innerProgress = new ActionableProgress<double>();
innerProgress.RegisterAction(p => progress.Report((.75 * p) + 15));
- ImageProcessor = new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer);
+ ImageProcessor = new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, GetImageEncoder());
RegisterSingleInstance(ImageProcessor);
TVSeriesManager = new TVSeriesManager(UserManager, UserDataManager, LibraryManager);
@@ -525,7 +527,7 @@ namespace MediaBrowser.Server.Startup.Common
RegisterSingleInstance(activityLogRepo);
RegisterSingleInstance<IActivityManager>(new ActivityManager(LogManager.GetLogger("ActivityManager"), activityLogRepo, UserManager));
- var authContext = new AuthorizationContext(AuthenticationRepository);
+ var authContext = new AuthorizationContext(AuthenticationRepository, ConnectManager);
RegisterSingleInstance<IAuthorizationContext>(authContext);
RegisterSingleInstance<ISessionContext>(new SessionContext(UserManager, authContext, SessionManager));
RegisterSingleInstance<IAuthService>(new AuthService(UserManager, authContext, ServerConfigurationManager, ConnectManager, SessionManager, DeviceManager));
@@ -544,6 +546,23 @@ namespace MediaBrowser.Server.Startup.Common
await ((UserManager)UserManager).Initialize().ConfigureAwait(false);
}
+ private IImageEncoder GetImageEncoder()
+ {
+ if (!_startupOptions.ContainsOption("-enablegdi"))
+ {
+ try
+ {
+ return new ImageMagickEncoder(LogManager.GetLogger("ImageMagick"), ApplicationPaths);
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error loading ImageMagick. Will revert to GDI.", ex);
+ }
+ }
+
+ return new GDIImageEncoder(FileSystemManager, LogManager.GetLogger("GDI"));
+ }
+
protected override INetworkManager CreateNetworkManager(ILogger logger)
{
return NativeApp.CreateNetworkManager(logger);
@@ -756,7 +775,7 @@ namespace MediaBrowser.Server.Startup.Common
ChannelManager.AddParts(GetExports<IChannel>(), GetExports<IChannelFactory>());
MediaSourceManager.AddParts(GetExports<IMediaSourceProvider>());
-
+
NotificationManager.AddParts(GetExports<INotificationService>(), GetExports<INotificationTypeFactory>());
SyncManager.AddParts(GetExports<ISyncProvider>());
}
diff --git a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj
index 38e07fde4..fb49692b5 100644
--- a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj
+++ b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj
@@ -76,6 +76,10 @@
<Compile Include="UnhandledExceptionWriter.cs" />
</ItemGroup>
<ItemGroup>
+ <ProjectReference Include="..\Emby.Drawing\Emby.Drawing.csproj">
+ <Project>{08fff49b-f175-4807-a2b5-73b0ebd9f716}</Project>
+ <Name>Emby.Drawing</Name>
+ </ProjectReference>
<ProjectReference Include="..\MediaBrowser.Api\MediaBrowser.Api.csproj">
<Project>{4fd51ac5-2c16-4308-a993-c3a84f3b4582}</Project>
<Name>MediaBrowser.Api</Name>
diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs
index e77af1c6b..6e8774eea 100644
--- a/MediaBrowser.ServerApplication/MainStartup.cs
+++ b/MediaBrowser.ServerApplication/MainStartup.cs
@@ -40,7 +40,6 @@ namespace MediaBrowser.ServerApplication
var applicationPath = currentProcess.MainModule.FileName;
- //Wand.SetMagickCoderModulePath(Path.Combine(Path.GetDirectoryName(applicationPath), "ImageMagickCoders", "x86"));
var appPaths = CreateApplicationPaths(applicationPath, _isRunningAsService);
var logManager = new NlogManager(appPaths.LogDirectoryPath, "server");
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index 2adb9fbbc..5c4a15d70 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -62,7 +62,7 @@
<ItemGroup>
<Reference Include="ImageMagickSharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\ImageMagickSharp.1.0.0.11\lib\net45\ImageMagickSharp.dll</HintPath>
+ <HintPath>..\packages\ImageMagickSharp.1.0.0.15\lib\net45\ImageMagickSharp.dll</HintPath>
</Reference>
<Reference Include="MediaBrowser.IsoMounter">
<HintPath>..\packages\MediaBrowser.IsoMounting.3.0.69\lib\net45\MediaBrowser.IsoMounter.dll</HintPath>
diff --git a/MediaBrowser.ServerApplication/ServerNotifyIcon.cs b/MediaBrowser.ServerApplication/ServerNotifyIcon.cs
index 9db3bdb90..3c5ed6e54 100644
--- a/MediaBrowser.ServerApplication/ServerNotifyIcon.cs
+++ b/MediaBrowser.ServerApplication/ServerNotifyIcon.cs
@@ -166,6 +166,13 @@ namespace MediaBrowser.ServerApplication
contextMenuStrip1.Invoke(action);
}
+
+ notifyIcon1.DoubleClick += notifyIcon1_DoubleClick;
+ }
+
+ void notifyIcon1_DoubleClick(object sender, EventArgs e)
+ {
+ BrowserLauncher.OpenDashboard(_appHost, _logger);
}
private void LocalizeText()
diff --git a/MediaBrowser.ServerApplication/packages.config b/MediaBrowser.ServerApplication/packages.config
index f429269b3..6c69a853d 100644
--- a/MediaBrowser.ServerApplication/packages.config
+++ b/MediaBrowser.ServerApplication/packages.config
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="ImageMagickSharp" version="1.0.0.11" targetFramework="net45" />
+ <package id="ImageMagickSharp" version="1.0.0.15" targetFramework="net45" />
<package id="MediaBrowser.IsoMounting" version="3.0.69" targetFramework="net45" />
<package id="System.Data.SQLite.Core" version="1.0.94.0" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
index 5138b157f..030d68791 100644
--- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs
+++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
@@ -470,6 +470,7 @@ namespace MediaBrowser.WebDashboard.Api
"notificationlist.js",
"notificationsetting.js",
"notificationsettings.js",
+ "photos.js",
"playlists.js",
"playlistedit.js",
@@ -482,6 +483,7 @@ namespace MediaBrowser.WebDashboard.Api
"selectserver.js",
"serversecurity.js",
"songs.js",
+ "streamingsettings.js",
"supporterkeypage.js",
"supporterpage.js",
"syncactivity.js",
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index 88a2a8ae1..5c4aab1e4 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -57,9 +57,9 @@
<Reference Include="ServiceStack.Interfaces">
<HintPath>..\ThirdParty\ServiceStack\ServiceStack.Interfaces.dll</HintPath>
</Reference>
- <Reference Include="WebMarkupMin.Core, Version=0.9.11.0, Culture=neutral, PublicKeyToken=99472178d266584b, processorArchitecture=MSIL">
+ <Reference Include="WebMarkupMin.Core, Version=0.9.12.0, Culture=neutral, PublicKeyToken=99472178d266584b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\WebMarkupMin.Core.0.9.11\lib\net40\WebMarkupMin.Core.dll</HintPath>
+ <HintPath>..\packages\WebMarkupMin.Core.0.9.12\lib\net40\WebMarkupMin.Core.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
@@ -87,7 +87,9 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
- <Content Include="dashboard-ui\css\images\clients\androidtv-tile.png" />
+ <Content Include="dashboard-ui\css\images\clients\androidtv-tile.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\css\images\kids\bg.jpg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -130,6 +132,9 @@
<Content Include="dashboard-ui\mysyncjob.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\photos.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\scripts\dashboardhosting.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -145,9 +150,15 @@
<Content Include="dashboard-ui\scripts\livetvitems.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\scripts\photos.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\scripts\selectserver.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\scripts\streamingsettings.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\scripts\syncjob.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -172,6 +183,9 @@
<Content Include="dashboard-ui\selectserver.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\streamingsettings.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\syncjob.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config
index aed67fb69..48f68789b 100644
--- a/MediaBrowser.WebDashboard/packages.config
+++ b/MediaBrowser.WebDashboard/packages.config
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="MediaBrowser.ApiClient.Javascript" version="3.0.249" targetFramework="net45" />
- <package id="WebMarkupMin.Core" version="0.9.11" targetFramework="net45" />
+ <package id="WebMarkupMin.Core" version="0.9.12" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
index c854f9f4a..11cb25ab8 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
@@ -222,6 +222,10 @@ namespace MediaBrowser.XbmcMetadata.Parsers
break;
}
+ case "type":
+ item.DisplayMediaType = reader.ReadElementContentAsString();
+ break;
+
case "title":
case "localtitle":
item.Name = reader.ReadElementContentAsString();
diff --git a/MediaBrowser.sln b/MediaBrowser.sln
index 143a3da41..3fc5e3f33 100644
--- a/MediaBrowser.sln
+++ b/MediaBrowser.sln
@@ -61,6 +61,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Server.Mono",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Server.Startup.Common", "MediaBrowser.Server.Startup.Common\MediaBrowser.Server.Startup.Common.csproj", "{B90AB8F2-1BFF-4568-A3FD-2A338A435A75}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Drawing", "Emby.Drawing\Emby.Drawing.csproj", "{08FFF49B-F175-4807-A2B5-73B0EBD9F716}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -516,6 +518,27 @@ Global
{B90AB8F2-1BFF-4568-A3FD-2A338A435A75}.Release|Win32.ActiveCfg = Release|Any CPU
{B90AB8F2-1BFF-4568-A3FD-2A338A435A75}.Release|x64.ActiveCfg = Release|Any CPU
{B90AB8F2-1BFF-4568-A3FD-2A338A435A75}.Release|x86.ActiveCfg = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release Mono|Any CPU.ActiveCfg = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release Mono|Any CPU.Build.0 = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release Mono|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release Mono|Mixed Platforms.Build.0 = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release Mono|Win32.ActiveCfg = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release Mono|x64.ActiveCfg = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release Mono|x86.ActiveCfg = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release|Any CPU.Build.0 = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release|Win32.ActiveCfg = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release|x64.ActiveCfg = Release|Any CPU
+ {08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec
index d31071666..269fc720a 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.612</version>
+ <version>3.0.621</version>
<title>MediaBrowser.Common.Internal</title>
<authors>Luke</authors>
<owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
<description>Contains common components shared by Emby Theater and Emby Server. Not intended for plugin developer consumption.</description>
<copyright>Copyright © Emby 2013</copyright>
<dependencies>
- <dependency id="MediaBrowser.Common" version="3.0.612" />
+ <dependency id="MediaBrowser.Common" version="3.0.621" />
<dependency id="NLog" version="3.2.0.0" />
<dependency id="SimpleInjector" version="2.7.0" />
</dependencies>
diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec
index d4d7de019..e2577369a 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.612</version>
+ <version>3.0.621</version>
<title>MediaBrowser.Common</title>
<authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners>
diff --git a/Nuget/MediaBrowser.Model.Signed.nuspec b/Nuget/MediaBrowser.Model.Signed.nuspec
index de9c503b9..cb467b5e5 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.612</version>
+ <version>3.0.621</version>
<title>MediaBrowser.Model - Signed Edition</title>
<authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners>
diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec
index b0008f9d0..a576cab49 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.612</version>
+ <version>3.0.621</version>
<title>Media Browser.Server.Core</title>
<authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,8 @@
<description>Contains core components required to build plugins for Emby Server.</description>
<copyright>Copyright © Emby 2013</copyright>
<dependencies>
- <dependency id="MediaBrowser.Common" version="3.0.612" />
+ <dependency id="MediaBrowser.Common" version="3.0.621" />
+ <dependency id="Interfaces.IO" version="1.0.0.5" />
</dependencies>
</metadata>
<files>
diff --git a/OpenSubtitlesHandler/XML-RPC/XmlRpcGenerator.cs b/OpenSubtitlesHandler/XML-RPC/XmlRpcGenerator.cs
index 76096a541..5a190ab72 100644
--- a/OpenSubtitlesHandler/XML-RPC/XmlRpcGenerator.cs
+++ b/OpenSubtitlesHandler/XML-RPC/XmlRpcGenerator.cs
@@ -51,8 +51,10 @@ namespace XmlRpcHandler
XmlWriterSettings sett = new XmlWriterSettings();
sett.Indent = true;
+ var requestXmlPath = Path.Combine(Path.GetTempPath(), "request.xml");
+
sett.Encoding = Encoding.UTF8;
- FileStream str = new FileStream(Path.GetTempPath() + "\\request.xml", FileMode.Create, FileAccess.Write);
+ FileStream str = new FileStream(requestXmlPath, FileMode.Create, FileAccess.Write);
XmlWriter XMLwrt = XmlWriter.Create(str, sett);
// Let's write the methods
@@ -88,7 +90,7 @@ namespace XmlRpcHandler
XMLwrt.Flush();
XMLwrt.Close();
str.Close();
- string requestContent = File.ReadAllText(Path.GetTempPath() + "\\request.xml");
+ string requestContent = File.ReadAllText(requestXmlPath);
return Encoding.UTF8.GetBytes(requestContent);
}
/// <summary>
diff --git a/README.md b/README.md
index f024d1e2a..8d8ac63af 100644
--- a/README.md
+++ b/README.md
@@ -5,19 +5,21 @@ Emby Server is a home media server built on top of other popular open source tec
It features a REST-based api with built-in documention to facilitate client development. We also have client libraries for our api to enable rapid development.
-We have several client apps released and in production:
+## Emby Apps
-- [Android](https://play.google.com/store/apps/details?id=com.mb.android "Android")
-- Html5
+- [Android (Play Store)](https://play.google.com/store/apps/details?id=com.mb.android "Android (Play Store)")
+- [Android (Amazon)](http://www.amazon.com/Emby-for-Android/dp/B00GVH9O0I "Android (Amazon)")
+- [Android TV](https://play.google.com/store/apps/details?id=tv.emby.embyatv "Android TV")
+- [HTML5](http://app.emby.media "HTML5")
- [iPad](https://itunes.apple.com/us/app/media-browser-client/id879475585 "iPad")
- [iPhone](https://itunes.apple.com/us/app/media-browser-for-ios/id705058087?mt=8 "iPhone")
+- [Kodi](http://emby.media/download/ "Kodi")
- [Media Portal](http://www.team-mediaportal.com/ "Media Portal")
-- [Roku](http://www.roku.com/channels/#!details/44191/media-browser-for-roku "Roku")
-- Windows 7/8 Desktop
-- Windows Media Center
+- [Roku](https://www.roku.com/channels#!details/44191/emby "Roku")
+- [Windows Desktop](http://emby.media/download/ "Windows Desktop")
+- [Windows Media Center](http://emby.media/download/ "Windows Media Center")
- [Windows Phone](http://www.windowsphone.com/s?appid=f4971ed9-f651-4bf6-84bb-94fd98613b86 "Windows Phone")
- [Windows 8](http://apps.microsoft.com/windows/en-us/app/media-browser/ad55a2f0-9897-47bd-8944-bed3aefd5d06 "Windows 8.1")
-- [Xbmc](http://emby.media/download/ "Xbmc")
## New Users ##
diff --git a/SharedVersion.cs b/SharedVersion.cs
index 11c0c6b5e..1469ab639 100644
--- a/SharedVersion.cs
+++ b/SharedVersion.cs
@@ -1,4 +1,4 @@
using System.Reflection;
[assembly: AssemblyVersion("3.0.*")]
-//[assembly: AssemblyVersion("3.0.5569.0")]
+//[assembly: AssemblyVersion("3.0.5588.1")]